~ubuntu-branches/ubuntu/natty/monodevelop/natty

« back to all changes in this revision

Viewing changes to src/addins/CSharpBinding/MonoDevelop.CSharp.Resolver/NRefactoryResolver.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2010-01-07 19:06:58 UTC
  • mto: (1.6.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 46.
  • Revision ID: james.westby@ubuntu.com-20100107190658-z9z95lgk4kwfes7p
ImportĀ upstreamĀ versionĀ 2.2+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// NRefactoryResolver.cs
 
3
//
 
4
// Author:
 
5
//   Mike KrĆ¼ger <mkrueger@novell.com>
 
6
//
 
7
// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
 
8
//
 
9
// Permission is hereby granted, free of charge, to any person obtaining
 
10
// a copy of this software and associated documentation files (the
 
11
// "Software"), to deal in the Software without restriction, including
 
12
// without limitation the rights to use, copy, modify, merge, publish,
 
13
// distribute, sublicense, and/or sell copies of the Software, and to
 
14
// permit persons to whom the Software is furnished to do so, subject to
 
15
// the following conditions:
 
16
// 
 
17
// The above copyright notice and this permission notice shall be
 
18
// included in all copies or substantial portions of the Software.
 
19
// 
 
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
21
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
22
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
23
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 
24
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 
25
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
26
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
27
//
 
28
 
 
29
using System;
 
30
using System.IO;
 
31
using System.Collections;
 
32
using System.Collections.ObjectModel;
 
33
using System.Collections.Generic;
 
34
using System.Collections.Specialized;
 
35
using System.Drawing;
 
36
using System.Text;
 
37
 
 
38
using MonoDevelop.Core;
 
39
using MonoDevelop.Projects.Dom;
 
40
using MonoDevelop.Projects.Dom.Parser;
 
41
using MonoDevelop.Projects;
 
42
using MonoDevelop.Ide.Gui;
 
43
using MonoDevelop.Ide.Gui.Content;
 
44
using MonoDevelop.Ide.CodeTemplates;
 
45
using MonoDevelop.Projects.Gui.Completion;
 
46
using MonoDevelop.Refactoring;
 
47
using ICSharpCode.NRefactory.Visitors;
 
48
using ICSharpCode.NRefactory.Parser;
 
49
using ICSharpCode.NRefactory.Ast;
 
50
using ICSharpCode.NRefactory;
 
51
using MonoDevelop.CSharp.Parser;
 
52
using MonoDevelop.CSharp.Completion;
 
53
 
 
54
namespace MonoDevelop.CSharp.Resolver
 
55
{
 
56
        public class NRefactoryResolver : IResolver
 
57
        {
 
58
                ProjectDom dom;
 
59
                SupportedLanguage lang;
 
60
                MonoDevelop.Ide.Gui.TextEditor editor;
 
61
                IType   callingType;
 
62
                IMember callingMember;
 
63
                ICompilationUnit unit;
 
64
                LookupTableVisitor lookupTableVisitor;
 
65
                DomLocation resolvePosition;
 
66
                string fileName;
 
67
                
 
68
                public IType CallingType {
 
69
                        get {
 
70
                                return callingType;
 
71
                        }
 
72
                }
 
73
                
 
74
                public IMember CallingMember {
 
75
                        get {
 
76
                                return callingMember;
 
77
                        }
 
78
                        set {
 
79
                                callingMember = value;
 
80
                        }
 
81
                }
 
82
 
 
83
                public ProjectDom Dom {
 
84
                        get {
 
85
                                return dom;
 
86
                        }
 
87
                }
 
88
                
 
89
                public ICompilationUnit Unit {
 
90
                        get {
 
91
                                return unit;
 
92
                        }
 
93
                }
 
94
 
 
95
                public static IType GetTypeAtCursor (IType outerType, string fileName, DomLocation position)
 
96
                {
 
97
                        foreach (IType type in outerType.InnerTypes) {
 
98
                                if (type.BodyRegion.Contains (position))
 
99
                                        return GetTypeAtCursor (type, fileName, position);
 
100
                        }
 
101
                        return outerType;
 
102
                }
 
103
                
 
104
                public static IType GetTypeAtCursor (ICompilationUnit unit, string fileName, DomLocation position)
 
105
                {
 
106
                        if (unit == null)
 
107
                                return null;
 
108
                        foreach (IType type in unit.Types) {
 
109
                                if (type.BodyRegion.Contains (position))
 
110
                                        return GetTypeAtCursor (type, fileName, position);
 
111
                        }
 
112
                        return null;
 
113
                }
 
114
                
 
115
                public NRefactoryResolver (ProjectDom dom, ICompilationUnit unit, MonoDevelop.Ide.Gui.TextEditor editor, string fileName) : this (dom, unit, SupportedLanguage.CSharp, editor, fileName)
 
116
                {
 
117
                }
 
118
                        
 
119
                public NRefactoryResolver (ProjectDom dom, ICompilationUnit unit, SupportedLanguage lang, MonoDevelop.Ide.Gui.TextEditor editor, string fileName)
 
120
                {
 
121
                        if (dom == null)
 
122
                                throw new ArgumentNullException ("dom");
 
123
                        this.unit = unit;
 
124
                        
 
125
                        this.dom = dom;
 
126
                        this.lang   = lang;
 
127
                        this.editor = editor;
 
128
                        this.fileName = fileName;
 
129
                        this.lookupTableVisitor = new LookupTableVisitor (lang);
 
130
                        
 
131
                }
 
132
                
 
133
                ICSharpCode.NRefactory.Ast.CompilationUnit memberCompilationUnit;
 
134
                public ICSharpCode.NRefactory.Ast.CompilationUnit MemberCompilationUnit {
 
135
                        get {
 
136
                                return this.memberCompilationUnit;
 
137
                        }
 
138
                }
 
139
                
 
140
                internal static IMember GetMemberAt (IType type, DomLocation location)
 
141
                {
 
142
                        foreach (IMember member in type.Members) {
 
143
                                if (!(member is IMethod || member is IProperty || member is IEvent || member is IField))
 
144
                                        continue;
 
145
//                              Console.WriteLine (member.Location.Line  + " --- " + location.Line);
 
146
                                if (member.Location.Line == location.Line || member.BodyRegion.Contains (location)) {
 
147
                                        return member;
 
148
                                }
 
149
                        }
 
150
                        return null;
 
151
                }
 
152
                
 
153
                internal void SetupResolver (DomLocation resolvePosition)
 
154
                {
 
155
                        this.resolvePosition = resolvePosition;
 
156
                        this.resultTable.Clear ();
 
157
                        callingType = GetTypeAtCursor (unit, fileName, resolvePosition);
 
158
                        if (callingType != null) {
 
159
                                callingMember = GetMemberAt (callingType, resolvePosition);
 
160
                                if (callingMember == null) {
 
161
                                        DomLocation posAbove = resolvePosition;
 
162
                                        posAbove.Line--;
 
163
                                        callingMember = GetMemberAt (callingType, posAbove);
 
164
                                }
 
165
                                callingType = dom.ResolveType (callingType);
 
166
                        }
 
167
                        //System.Console.WriteLine("CallingMember: " + callingMember);
 
168
                        if (callingMember != null && !setupLookupTableVisitor ) {
 
169
                                string wrapper = CreateWrapperClassForMember (callingMember, fileName, editor);
 
170
                                using (ICSharpCode.NRefactory.IParser parser = ICSharpCode.NRefactory.ParserFactory.CreateParser (lang, new StringReader (wrapper))) {
 
171
                                        parser.Parse ();
 
172
                                        memberCompilationUnit = parser.CompilationUnit;
 
173
                                        lookupTableVisitor.VisitCompilationUnit (parser.CompilationUnit, null);
 
174
                                        lookupVariableLine = CallingMember.Location.Line - 2;
 
175
                                        setupLookupTableVisitor = true;
 
176
                                }
 
177
                        } else if (editor != null) {
 
178
                                string wrapper = editor.Text;
 
179
                                using (ICSharpCode.NRefactory.IParser parser = ICSharpCode.NRefactory.ParserFactory.CreateParser (lang, new StringReader (wrapper))) {
 
180
                                        parser.Parse ();
 
181
                                        memberCompilationUnit = parser.CompilationUnit;
 
182
                                        lookupTableVisitor.VisitCompilationUnit (parser.CompilationUnit, null);
 
183
                                        lookupVariableLine = 0;
 
184
                                        setupLookupTableVisitor = true;
 
185
                                }
 
186
                        }
 
187
                }
 
188
                bool setupLookupTableVisitor = false;
 
189
                int lookupVariableLine = 0;
 
190
                internal void SetupParsedCompilationUnit (ICSharpCode.NRefactory.Ast.CompilationUnit unit)
 
191
                {
 
192
                        lookupVariableLine = 0; // all compilation unit lines are 1 based
 
193
                        memberCompilationUnit = unit;
 
194
                        lookupTableVisitor.VisitCompilationUnit (unit, null);
 
195
                        setupLookupTableVisitor = true;
 
196
                }
 
197
                
 
198
                static void AddParameterList (CSharpTextEditorCompletion.CompletionDataCollector col, IEnumerable<IParameter> parameters)
 
199
                {
 
200
                        foreach (IParameter p in parameters) {
 
201
                                col.Add (p);
 
202
//                              completionList.Add (p.Name, "md-literal");
 
203
                        }
 
204
                }
 
205
                
 
206
                void AddContentsFromClassAndMembers (ExpressionContext context, CSharpTextEditorCompletion.CompletionDataCollector col)
 
207
                {
 
208
                        IMethod method = callingMember as IMethod;
 
209
                        if (method != null && method.Parameters != null) {
 
210
                                AddParameterList (col, method.Parameters);
 
211
                        }
 
212
                        IProperty property = callingMember as IProperty;
 
213
                        if (property != null && property.Parameters != null)
 
214
                                AddParameterList (col, property.Parameters);
 
215
                        if (CallingType == null)
 
216
                                return;
 
217
                        AddContentsFromOuterClass (CallingType.DeclaringType, context, col);
 
218
                        IType callingType = CallingType is InstantiatedType ? ((InstantiatedType)CallingType).UninstantiatedType : CallingType;
 
219
                        //bool isInStatic = CallingMember != null ? CallingMember.IsStatic : false;
 
220
 
 
221
                        if (CallingMember == null || !CallingMember.IsStatic) {
 
222
                                foreach (TypeParameter parameter in callingType.TypeParameters) {
 
223
                                        col.Add (parameter.Name, "md-literal");
 
224
                                }
 
225
                        }
 
226
                        
 
227
                        if (context != ExpressionContext.TypeDeclaration && CallingMember != null) {
 
228
                                bool includeProtected = DomType.IncludeProtected (dom, CallingType, CallingMember.DeclaringType);
 
229
                                foreach (IType type in dom.GetInheritanceTree (CallingType)) {
 
230
                                        foreach (IMember member in type.Members) {
 
231
                                                if (!(member is IType) && CallingMember.IsStatic && !(member.IsStatic || member.IsConst))
 
232
                                                        continue;
 
233
                                                if (member.IsAccessibleFrom (dom, CallingType, CallingMember, includeProtected)) {
 
234
                                                        if (context.FilterEntry (member))
 
235
                                                                continue;
 
236
                                                        col.Add (member);
 
237
                                                }
 
238
                                        }
 
239
                                }
 
240
                        }
 
241
                }
 
242
                
 
243
                void AddContentsFromOuterClass (IType outer, ExpressionContext context, CSharpTextEditorCompletion.CompletionDataCollector col)
 
244
                {
 
245
                        if (outer == null)
 
246
                                return;
 
247
                        foreach (IMember member in outer.Members) {
 
248
                                if (member is IType || member.IsStatic || member.IsConst) {
 
249
                                        col.Add (member);
 
250
                                }
 
251
                        }
 
252
                        AddContentsFromOuterClass (outer.DeclaringType, context, col);
 
253
                }
 
254
                
 
255
                static readonly IReturnType attributeType = new DomReturnType ("System.Attribute");
 
256
                public CSharpTextEditorCompletion.CompletionDataCollector AddAccessibleCodeCompletionData (ExpressionContext context, CSharpTextEditorCompletion.CompletionDataCollector col)
 
257
                {
 
258
                        if (context != ExpressionContext.Global && context != ExpressionContext.TypeName) {
 
259
                                AddContentsFromClassAndMembers (context, col);
 
260
                                
 
261
                                if (lookupTableVisitor != null && lookupTableVisitor.Variables != null) {
 
262
                                        int callingMemberline = CallingMember != null ? CallingMember.Location.Line : 0;
 
263
                                        // local variables could be outside members (LINQ initializers) 
 
264
                                        foreach (KeyValuePair<string, List<LocalLookupVariable>> pair in lookupTableVisitor.Variables) {
 
265
                                                if (pair.Value != null && pair.Value.Count > 0) {
 
266
                                                        foreach (LocalLookupVariable v in pair.Value) {
 
267
                                                                if (new DomLocation (callingMemberline + v.StartPos.Line - 2, v.StartPos.Column) <= this.resolvePosition && (v.EndPos.IsEmpty || new DomLocation (callingMemberline + v.EndPos.Line - 2, v.EndPos.Column) >= this.resolvePosition)) {
 
268
                                                                        col.Add (new LocalVariable (CallingMember, pair.Key, ConvertTypeReference (v.TypeRef), DomRegion.Empty));
 
269
                                                                }
 
270
                                                        }
 
271
                                                }
 
272
                                        }
 
273
                                }
 
274
                                
 
275
                                if (CallingMember is IProperty) {
 
276
                                        IProperty property = (IProperty)callingMember;
 
277
                                        if (property.HasSet && editor != null && property.SetRegion.Contains (resolvePosition.Line, editor.CursorColumn))
 
278
                                                col.Add ("value");
 
279
                                }
 
280
                                
 
281
                                if (CallingMember is IEvent)
 
282
                                        col.Add ("value");
 
283
                        }
 
284
                        
 
285
                        List<string> namespaceList = new List<string> ();
 
286
                        namespaceList.Add ("");
 
287
                        
 
288
                        List<string> namespaceDeclList = new List<string> ();
 
289
                        namespaceDeclList.Add ("");
 
290
                        if (unit != null) {
 
291
                                foreach (IUsing u in unit.Usings) {
 
292
                                        foreach (string alias in u.Aliases.Keys) {
 
293
                                                col.Add (alias);
 
294
                                        }
 
295
                                        if (u.Namespaces == null)
 
296
                                                continue;
 
297
                                        bool isNamespaceDecl = u.IsFromNamespace && u.Region.Contains (this.resolvePosition);
 
298
                                        if (u.IsFromNamespace && !isNamespaceDecl)
 
299
                                                continue;
 
300
                                        foreach (string ns in u.Namespaces) {
 
301
                                                namespaceList.Add (ns);
 
302
                                                if (isNamespaceDecl)
 
303
                                                        namespaceDeclList.Add (ns);
 
304
                                        }
 
305
                                }
 
306
                                
 
307
                                foreach (object o in dom.GetNamespaceContents (namespaceList, true, true)) {
 
308
                                        if (context.FilterEntry (o))
 
309
                                                continue;
 
310
                                        if (o is Namespace) {
 
311
                                                Namespace ns = o as Namespace;
 
312
                                                bool skip = true;
 
313
                                                foreach (string str in namespaceDeclList) {
 
314
                                                        if (dom.NamespaceExists (str.Length > 0 ? str + "." + ns.Name : ns.Name)) {
 
315
                                                                skip = false;
 
316
                                                                break;
 
317
                                                        }
 
318
                                                }
 
319
                                                if (skip)
 
320
                                                        continue;
 
321
                                        }
 
322
                                        
 
323
                                        //IMember member = o as IMember;
 
324
                                        //if (member != null && completionList.Find (member.Name) != null)
 
325
                                        //      continue;
 
326
                                        if (context == ExpressionContext.Attribute) {
 
327
                                                IType t = o as IType;
 
328
                                                if (t != null && !t.IsBaseType (attributeType))
 
329
                                                        continue;
 
330
                                        }
 
331
                                        ICompletionData data = col.Add (o);
 
332
                                        if (data != null && context == ExpressionContext.Attribute && data.CompletionText != null && data.CompletionText.EndsWith ("Attribute")) {
 
333
                                                string newText = data.CompletionText.Substring (0, data.CompletionText.Length - "Attribute".Length);
 
334
                                                data.SetText (newText);
 
335
                                        }
 
336
                                }
 
337
                                CodeTemplateService.AddCompletionDataForMime ("text/x-csharp", col.CompletionList);
 
338
                        }
 
339
                        return col;
 
340
                }
 
341
                
 
342
                Expression ParseExpression (ExpressionResult expressionResult)
 
343
                {
 
344
                        if (expressionResult == null || String.IsNullOrEmpty (expressionResult.Expression))
 
345
                                return null;
 
346
                        string expr = expressionResult.Expression.Trim ();
 
347
                        if (!expr.EndsWith (";"))
 
348
                                expr += ";";
 
349
                        using (ICSharpCode.NRefactory.IParser parser = ICSharpCode.NRefactory.ParserFactory.CreateParser (this.lang, new StringReader (expr))) {
 
350
                                Expression result = parser.ParseExpression();
 
351
                                if (result is BinaryOperatorExpression) {
 
352
                                        TypeReference typeRef = ParseTypeReference (expressionResult);
 
353
                                        if (typeRef != null) {
 
354
                                                return new TypeReferenceExpression (typeRef);
 
355
                                        }
 
356
                                }
 
357
                                return result;
 
358
                        }
 
359
                }
 
360
                
 
361
                static TypeReference ParseTypeReference (ExpressionResult expressionResult)
 
362
                {
 
363
                        if (expressionResult == null || String.IsNullOrEmpty (expressionResult.Expression))
 
364
                                return null;
 
365
                        string expr = expressionResult.Expression.Trim ();
 
366
                        using (ICSharpCode.NRefactory.IParser parser = ICSharpCode.NRefactory.ParserFactory.CreateParser (SupportedLanguage.CSharp, new StringReader ("typeof(" + expr + ");"))) {
 
367
                                TypeOfExpression typeOfExpression = parser.ParseExpression () as TypeOfExpression;
 
368
                                if (typeOfExpression != null)
 
369
                                        return typeOfExpression.TypeReference;
 
370
                        }
 
371
                        return null;
 
372
                }
 
373
                
 
374
                public static IReturnType ParseReturnType (ExpressionResult expressionResult)
 
375
                {
 
376
                        TypeReference typeReference = ParseTypeReference (expressionResult);
 
377
                        if (typeReference == null)
 
378
                                return null;
 
379
                        return ConvertTypeReference (typeReference);
 
380
                }
 
381
                
 
382
                public ResolveResult ResolveIdentifier (string identifier, DomLocation resolvePosition)
 
383
                {
 
384
                        this.SetupResolver (resolvePosition);
 
385
                        ResolveVisitor visitor = new ResolveVisitor (this);
 
386
                        ResolveResult result = this.ResolveIdentifier (visitor, identifier);
 
387
                        return result;
 
388
                }
 
389
                
 
390
                public ResolveResult ResolveExpression (Expression expr, DomLocation resolvePosition)
 
391
                {
 
392
                        this.expr = expr;
 
393
                        this.SetupResolver (resolvePosition);
 
394
                        ResolveVisitor visitor = new ResolveVisitor (this);
 
395
                        ResolveResult result = visitor.Resolve (expr);
 
396
                        return result;
 
397
                }
 
398
                
 
399
                Expression expr;
 
400
                public Expression ResolvedExpression {
 
401
                        get {
 
402
                                return expr;
 
403
                        }
 
404
                }
 
405
        
 
406
                public DomLocation ResolvePosition {
 
407
                        get {
 
408
                                return resolvePosition;
 
409
                        }
 
410
                }
 
411
                
 
412
                public ResolveResult Resolve (ExpressionResult expressionResult, DomLocation resolvePosition)
 
413
                {
 
414
                        this.SetupResolver (resolvePosition);
 
415
                        ResolveVisitor visitor = new ResolveVisitor (this);
 
416
                        ResolveResult result;
 
417
//                      System.Console.WriteLine("expressionResult:" + expressionResult);
 
418
 
 
419
                        if (unit != null && expressionResult.ExpressionContext == ExpressionContext.AttributeArguments) {
 
420
                                string attributeName = NewCSharpExpressionFinder.FindAttributeName (editor, unit, unit.FileName);
 
421
                                if (attributeName != null) {
 
422
                                        IType type = dom.SearchType (new SearchTypeRequest (unit, new DomReturnType (attributeName + "Attribute"), CallingType));
 
423
                                        if (type == null) 
 
424
                                                type = dom.SearchType (new SearchTypeRequest (unit, new DomReturnType (attributeName), CallingType));
 
425
                                        if (type != null) {
 
426
                                                foreach (IProperty property in type.Properties) {
 
427
                                                        if (property.Name == expressionResult.Expression) {
 
428
                                                                return new MemberResolveResult (property);
 
429
                                                        }
 
430
                                                }
 
431
                                        }
 
432
                                }
 
433
                        }
 
434
                        
 
435
                        TypeReference typeRef;
 
436
                        if (expressionResult != null && expressionResult.ExpressionContext != null && expressionResult.ExpressionContext.IsObjectCreation) {
 
437
                                typeRef = ParseTypeReference (expressionResult);
 
438
                                if (typeRef != null) {
 
439
                                        if (dom.NamespaceExists (typeRef.Type)) {
 
440
//                                              System.Console.WriteLine("namespace resolve result");
 
441
                                                result = new NamespaceResolveResult (typeRef.Type);
 
442
                                        } else {
 
443
                                                result = visitor.CreateResult (ConvertTypeReference (typeRef));
 
444
                                        }
 
445
//                                      System.Console.WriteLine("type reference resolve result");
 
446
                                        result.ResolvedExpression = expressionResult;
 
447
                                        if (dom.GetType (result.ResolvedType) != null)
 
448
                                                return result;
 
449
                                }
 
450
                        }
 
451
                        expr = ParseExpression (expressionResult);
 
452
                        
 
453
//                      System.Console.WriteLine("parsed expression:" + expr);
 
454
                        if (expr == null) {
 
455
//                              System.Console.WriteLine("Can't parse expression");
 
456
                                return null;
 
457
                        }
 
458
                        
 
459
                        result = visitor.Resolve (expr);
 
460
//                      if (CallingMember == null && result != null)
 
461
//                              result.StaticResolve = true;
 
462
//                      System.Console.WriteLine("result:" + result + "STATIC" + result.StaticResolve);
 
463
                        result.ResolvedExpression = expressionResult;
 
464
                        return result;
 
465
                }
 
466
                
 
467
                public static IReturnType ConvertTypeReference (TypeReference typeRef)
 
468
                {
 
469
                        return typeRef.ConvertToReturnType ();
 
470
                }
 
471
                
 
472
                IReturnType ResolveType (IReturnType type)
 
473
                {
 
474
                        return ResolveType (unit, type);
 
475
                }
 
476
                
 
477
                IReturnType ResolveType (ICompilationUnit unit, IReturnType type)
 
478
                {
 
479
                        if (type == null)
 
480
                                return DomReturnType.Void;
 
481
                        if (type.Type != null) // type known (possible anonymous type), no resolving needed
 
482
                                return type;
 
483
                        
 
484
                        return (IReturnType)new TypeResolverVisitor (dom, unit).Visit (type, this.CallingType);
 
485
                }
 
486
                
 
487
                ResolveResult GetFunctionParameterType (ResolveResult resolveResult)
 
488
                {
 
489
                        if (resolveResult == null || resolveResult.ResolvedType == null)
 
490
                                return null;
 
491
                        IReturnType type = resolveResult.ResolvedType;
 
492
                        while (type.GenericArguments.Count > 0) {
 
493
                                IType realType = dom.SearchType (new SearchTypeRequest (Unit, type, CallingType));
 
494
                                if (realType != null && realType.ClassType == MonoDevelop.Projects.Dom.ClassType.Delegate) {
 
495
                                        IMethod invokeMethod = realType.SearchMember ("Invoke", true) [0] as IMethod;
 
496
                                        if (invokeMethod != null && invokeMethod.Parameters.Count > 0) {
 
497
                                                type = invokeMethod.Parameters[0].ReturnType;
 
498
                                                break;
 
499
                                        }
 
500
                                }
 
501
                                if (type.GenericArguments.Count > 0) {
 
502
                                        type = type.GenericArguments[0];
 
503
                                } else {
 
504
                                        break;
 
505
                                }
 
506
                        }
 
507
                        resolveResult.ResolvedType = type;
 
508
                        return resolveResult;
 
509
                }
 
510
                
 
511
                class LambdaResolver
 
512
                {
 
513
                        HashSet<Expression> expressions = new HashSet<Expression> ();
 
514
                        Dictionary<string, ResolveResult> returnTypeDictionary = new Dictionary<string, ResolveResult> ();
 
515
                        NRefactoryResolver resolver;
 
516
                        
 
517
                        public LambdaResolver (NRefactoryResolver resolver)
 
518
                        {
 
519
                                this.resolver = resolver;
 
520
                        }
 
521
                        
 
522
                        internal ResolveResult ResolveLambda (ResolveVisitor visitor, Expression lambdaExpression)
 
523
                        {
 
524
                                if (expressions.Contains (lambdaExpression)) {
 
525
                                        Console.WriteLine ("LOOP!!!");
 
526
                                        return null;
 
527
                                }
 
528
                                expressions.Add (lambdaExpression);
 
529
                                
 
530
                                if (lambdaExpression.Parent is LambdaExpression)
 
531
                                        return ResolveLambda (visitor, lambdaExpression.Parent as Expression);
 
532
                                if (lambdaExpression.Parent is ParenthesizedExpression)
 
533
                                        return ResolveLambda (visitor, lambdaExpression.Parent as Expression);
 
534
                                if (lambdaExpression.Parent is AssignmentExpression)
 
535
                                        return visitor.Resolve (((AssignmentExpression)lambdaExpression.Parent).Left);
 
536
                                if (lambdaExpression.Parent is CastExpression)
 
537
                                        return visitor.Resolve (((CastExpression)lambdaExpression.Parent));
 
538
                                if (lambdaExpression.Parent is VariableDeclaration) {
 
539
                                        VariableDeclaration varDec = (VariableDeclaration)lambdaExpression.Parent;
 
540
                                        return resolver.GetFunctionParameterType (resolver.ResolveIdentifier (visitor, varDec.Name));
 
541
                                }
 
542
                                if (lambdaExpression.Parent is InvocationExpression) {
 
543
                                        InvocationExpression invocation = (InvocationExpression)lambdaExpression.Parent;
 
544
                                        MethodResolveResult result = visitor.Resolve (invocation.TargetObject) as MethodResolveResult;
 
545
                                        if (result == null) {
 
546
                                                MonoDevelop.Core.LoggingService.LogWarning ("No compatible method found :" + invocation.TargetObject);
 
547
                                                return null;
 
548
                                        }
 
549
                                        result.ResolveExtensionMethods ();
 
550
                                        
 
551
                                        // todo! - not 100% correct, but it's a best-fit until the dom contains token information
 
552
                                        // This code assumes that the lambda expression is the first parameter of the method.
 
553
                                        for (int i = 0; i < invocation.Arguments.Count; i++) {
 
554
                                                if (invocation.Arguments[i] == lambdaExpression && i < result.MostLikelyMethod.Parameters.Count) {
 
555
                                                        IParameter parameter = result.MostLikelyMethod.Parameters[i];
 
556
                                                        IReturnType returnType = parameter.ReturnType;
 
557
                                                        
 
558
                                                        while (returnType.GenericArguments.Count > 0) {
 
559
                                                                returnType = returnType.GenericArguments[0];
 
560
                                                        }
 
561
                                                        string invariantString = returnType.ToInvariantString ();
 
562
                                                        if (returnTypeDictionary.ContainsKey (invariantString))
 
563
                                                                return returnTypeDictionary[invariantString];
 
564
                                                        ResolveResult createdResult = visitor.CreateResult (returnType);
 
565
                                                        returnTypeDictionary[invariantString] = createdResult;
 
566
                                                        return createdResult;
 
567
                                                }
 
568
                                        }
 
569
                                        
 
570
                                        LambdaExpression lambda = (LambdaExpression)lambdaExpression;
 
571
        //                              Console.WriteLine ("lambda:" + lambda);
 
572
                                        if (!lambda.ExpressionBody.IsNull) {
 
573
                                                DomLocation old = resolver.resolvePosition;
 
574
                                                try {
 
575
                                                        resolver.resolvePosition = new DomLocation (resolver.CallingMember.Location.Line + resolver.lookupVariableLine + 
 
576
                                                                                           lambda.ExpressionBody.StartLocation.Line - 2,
 
577
                                                                                           lambda.ExpressionBody.StartLocation.Column - 1);
 
578
        //                                              Console.WriteLine ("pos:" + resolvePosition);
 
579
        //                                              result.AddArgument (visitor.GetTypeSafe (lambda.ExpressionBody));
 
580
        //                                              result.ResolveExtensionMethods ();
 
581
                                                        ResolveResult res =  visitor.Resolve (lambda.ExpressionBody);
 
582
        //                                              Console.WriteLine (lambda.ExpressionBody);
 
583
        //                                              Console.WriteLine ("RES:" + res.ResolvedType.FullName);
 
584
                                                        if (!string.IsNullOrEmpty (res.ResolvedType.FullName))
 
585
                                                                return res;
 
586
                                                } finally {
 
587
                                                        resolver.resolvePosition = old;
 
588
                                                }
 
589
                                        } 
 
590
                                        
 
591
                                        foreach (Expression arg in invocation.Arguments) {
 
592
                                                var argType = arg is LambdaExpression ?  DomReturnType.Void : visitor.GetTypeSafe (arg);
 
593
                                                result.AddArgument (argType);
 
594
                                        }
 
595
                                        
 
596
                                        result.ResolveExtensionMethods ();
 
597
                                        //Console.WriteLine ("maybe method:" + result.MostLikelyMethod);
 
598
                                        for (int i = 0; i < invocation.Arguments.Count; i++) {
 
599
                                                if (invocation.Arguments [i] == lambdaExpression && i < result.MostLikelyMethod.Parameters.Count) {
 
600
                                                        IParameter parameterType = result.MostLikelyMethod.Parameters [i];
 
601
                                                        //Console.WriteLine (i + " par: " + parameterType);
 
602
                                                        if (parameterType.ReturnType.Name == "Func" && parameterType.ReturnType.GenericArguments.Count > 0) {
 
603
                                                                return visitor.CreateResult (parameterType.ReturnType.GenericArguments[0]);
 
604
                                                        }
 
605
                                                }
 
606
                                        }
 
607
                                        return result;
 
608
                                }
 
609
                                
 
610
                                if (lambdaExpression.Parent is ObjectCreateExpression) {
 
611
                                        ObjectCreateExpression objectCreateExpression = (ObjectCreateExpression)lambdaExpression.Parent;
 
612
                                        int index = objectCreateExpression.Parameters.IndexOf (lambdaExpression);
 
613
                                        if (index < 0)
 
614
                                                return null;
 
615
                                        MemberResolveResult resolvedCreateExpression = visitor.Resolve (objectCreateExpression) as MemberResolveResult;
 
616
                                        
 
617
                                        if (resolvedCreateExpression != null) {
 
618
                                                IMethod method = resolvedCreateExpression.ResolvedMember as IMethod;
 
619
                                                if (method!= null && index < method.Parameters.Count) {
 
620
                                                        return new ParameterResolveResult (method.Parameters[index]);
 
621
                                                } else {
 
622
                                                        return null;
 
623
                                                }
 
624
                                        }
 
625
                                }
 
626
                                
 
627
                                return null;
 
628
                        }
 
629
                }
 
630
 
 
631
                public ResolveResult ResolveLambda (ResolveVisitor visitor, Expression lambdaExpression)
 
632
                {
 
633
                        return new LambdaResolver (this).ResolveLambda (visitor, lambdaExpression);
 
634
                }
 
635
                
 
636
                Dictionary<string, ResolveResult> resultTable = new Dictionary<string, ResolveResult> ();
 
637
                public ResolveResult ResolveIdentifier (ResolveVisitor visitor, string identifier)
 
638
                {
 
639
                        ResolveResult result = null;
 
640
                        if (resultTable.TryGetValue (identifier, out result))
 
641
                                return result;
 
642
                        resultTable[identifier] = result;
 
643
                
 
644
                        foreach (KeyValuePair<string, List<LocalLookupVariable>> pair in this.lookupTableVisitor.Variables) {
 
645
                                if (identifier == pair.Key) {
 
646
                                        LocalLookupVariable var = null;
 
647
//                                      Console.WriteLine ("--- RP:" + this.resolvePosition + "/" + pair.Value.Count);
 
648
                                        foreach (LocalLookupVariable v2 in pair.Value) {
 
649
                                                DomLocation varStartPos = new DomLocation (lookupVariableLine + v2.StartPos.Line, v2.StartPos.Column - 1);
 
650
                                                DomLocation varEndPos   = new DomLocation (lookupVariableLine + v2.EndPos.Line, v2.EndPos.Column - 1);
 
651
//                                              Console.WriteLine (v2.Name + ":" + varStartPos + " <> " + varEndPos);
 
652
                                                if (varStartPos > this.resolvePosition || (!v2.EndPos.IsEmpty && varEndPos < this.resolvePosition))
 
653
                                                        continue;
 
654
                                                var = v2;
 
655
                                        }
 
656
//                                      Console.WriteLine ("var:" + var);
 
657
                                        if (var == null)
 
658
                                                continue;
 
659
                                        IReturnType varType = null;
 
660
                                        IReturnType varTypeUnresolved = null;
 
661
                                        if (var.IsQueryContinuation) {
 
662
                                                QueryExpression query = var.Initializer as QueryExpression;
 
663
                                                
 
664
                                                QueryExpressionGroupClause grouBy = query.SelectOrGroupClause as QueryExpressionGroupClause;
 
665
                                                DomLocation old = resolvePosition;
 
666
                                                try {
 
667
                                                        resolvePosition = new DomLocation (lookupVariableLine + grouBy.Projection.StartLocation.Line,
 
668
                                                                                           grouBy.Projection.StartLocation.Column);
 
669
                                                        ResolveResult initializerResolve = visitor.Resolve (grouBy.Projection);
 
670
                                                        ResolveResult groupByResolve = visitor.Resolve (grouBy.GroupBy);
 
671
                                                        DomReturnType resolved = new DomReturnType (dom.GetType ("System.Linq.IGrouping", new IReturnType [] { 
 
672
                                                                DomType.GetComponentType (dom, initializerResolve.ResolvedType), groupByResolve.ResolvedType}));
 
673
                                                varTypeUnresolved = varType = resolved;
 
674
                                                } finally {
 
675
                                                        resolvePosition = old;
 
676
                                                }
 
677
                                                
 
678
                                        } else if ((var.TypeRef == null || var.TypeRef.Type == "var" || var.TypeRef.IsNull)) {
 
679
                                                if (var.ParentLambdaExpression != null) {
 
680
                                                        ResolveResult lambdaResolve = ResolveLambda (visitor, var.ParentLambdaExpression);
 
681
                                                        if (lambdaResolve != null) {
 
682
                                                                varType           = lambdaResolve.ResolvedType;
 
683
                                                                varTypeUnresolved = lambdaResolve.UnresolvedType;
 
684
                                                        } else {
 
685
                                                                varType = varTypeUnresolved = DomReturnType.Void;
 
686
                                                        }
 
687
                                                }
 
688
                                                if (var.Initializer != null) {
 
689
                                                        ResolveResult initializerResolve = visitor.Resolve (var.Initializer);
 
690
//                                                      Console.WriteLine ("initializer : "+ var.Initializer + " result:" + initializerResolve);
 
691
                                                        varType           = var.IsLoopVariable ? DomType.GetComponentType (dom, initializerResolve.ResolvedType) : initializerResolve.ResolvedType;
 
692
                                                        varTypeUnresolved = var.IsLoopVariable ? DomType.GetComponentType (dom, initializerResolve.UnresolvedType) : initializerResolve.UnresolvedType;
 
693
//                                                      Console.WriteLine ("resolved type:" + initializerResolve.ResolvedType + " is loop : " + var.IsLoopVariable);
 
694
//                                                      Console.WriteLine (varType);
 
695
//                                                      Console.WriteLine ("----------");
 
696
                                                }
 
697
                                        } else { 
 
698
                                                varTypeUnresolved = varType = ConvertTypeReference (var.TypeRef);
 
699
                                        }
 
700
//                                      Console.WriteLine ("-----");
 
701
//                                      Console.WriteLine (varType);
 
702
                                        varType = ResolveType (varType);
 
703
                                        result = new LocalVariableResolveResult (
 
704
                                                new LocalVariable (CallingMember, identifier, varType,
 
705
                                                        new DomRegion (lookupVariableLine + var.StartPos.Line - 1, var.StartPos.Column - 1, 
 
706
                                                                       lookupVariableLine + var.StartPos.Line - 1, var.EndPos.Column - 1)),
 
707
                                                        var.IsLoopVariable);
 
708
                                        
 
709
                                        result.ResolvedType = varType;
 
710
                                        result.UnresolvedType = varTypeUnresolved;
 
711
                                        goto end;
 
712
                                }
 
713
                        }
 
714
                        if (this.callingMember != null) {
 
715
                                // special handling of property or field return types, they can have the same name as the return type
 
716
                                // ex.: MyType MyType { get; set; }  Type1 Type1;
 
717
                                if ((callingMember is IProperty || callingMember is IField) && identifier == callingMember.Name) {
 
718
                                        int pos = editor.GetPositionFromLineColumn (resolvePosition.Line, resolvePosition.Column);
 
719
                                        while (pos < editor.TextLength && !Char.IsWhiteSpace (editor.GetCharAt (pos)))
 
720
                                                pos++;
 
721
                                        while (pos < editor.TextLength && Char.IsWhiteSpace (editor.GetCharAt (pos)))
 
722
                                                pos++;
 
723
                                        StringBuilder memberName = new StringBuilder ();
 
724
                                        while (pos < editor.TextLength && (Char.IsLetterOrDigit (editor.GetCharAt (pos)) || editor.GetCharAt (pos) == '_') ) {
 
725
                                                memberName.Append (editor.GetCharAt (pos));
 
726
                                                pos++;
 
727
                                        }
 
728
                                        //Console.WriteLine ("id: '" + identifier + "' : '" + memberName.ToString () +"'" + (memberName.ToString () == identifier));
 
729
                                        if (memberName.ToString () == identifier) {
 
730
                                                result = visitor.CreateResult (callingMember.ReturnType);
 
731
                                                goto end;
 
732
                                        }
 
733
                                }
 
734
                                
 
735
                                if (identifier == "value" && this.callingMember is IProperty) {
 
736
                                        result = new MemberResolveResult (this.callingMember);
 
737
                                        result.UnresolvedType = ((IProperty)this.callingMember).ReturnType;
 
738
                                        result.ResolvedType = ResolveType (((IProperty)this.callingMember).ReturnType);
 
739
                                        goto end;
 
740
                                }
 
741
                                if (this.callingMember is IMethod || this.callingMember is IProperty) {
 
742
                                        ReadOnlyCollection<IParameter> prms = this.callingMember is IMethod
 
743
                                                ? ((IMethod)this.callingMember).Parameters
 
744
                                                : ((IProperty)this.callingMember).Parameters;
 
745
                                        if (prms != null) {
 
746
                                                foreach (IParameter para in prms) {
 
747
                                                        if (para.Name == identifier) {
 
748
                                                                result = new ParameterResolveResult (para);
 
749
                                                                result.UnresolvedType = para.ReturnType;
 
750
                                                                result.ResolvedType = ResolveType (para.ReturnType);
 
751
                                                                goto end;
 
752
                                                        }
 
753
                                                }
 
754
                                        }
 
755
                                }
 
756
                        }
 
757
                        IType searchedType = dom.SearchType (new SearchTypeRequest (unit, this.CallingType, identifier));
 
758
                        if (this.callingType != null && dom != null) {
 
759
                                List<IMember> members = new List <IMember> ();
 
760
                                foreach (IType type in dom.GetInheritanceTree (callingType)) {
 
761
                                        members.AddRange (type.SearchMember (identifier, true));
 
762
                                }
 
763
                                bool includeProtected = true;
 
764
                                // filter members
 
765
                                if (this.CallingMember != null) {
 
766
                                        for (int i = 0; i < members.Count; i++) {
 
767
                                                if (this.CallingMember.IsStatic && !members[i].IsStatic
 
768
                                                    || !members[i].IsAccessibleFrom (dom, callingType, this.CallingMember, includeProtected))
 
769
                                                {
 
770
                                                        members.RemoveAt (i);
 
771
                                                        i--;
 
772
                                                        continue;
 
773
                                                }
 
774
                                        }
 
775
                                }
 
776
                                
 
777
                                if (members.Count > 0) {
 
778
                                        if (members[0] is IMethod) {
 
779
                                                result = new MethodResolveResult (members);
 
780
                                                if (CallingMember != null)
 
781
                                                        result.StaticResolve = CallingMember.IsStatic;
 
782
                                        } else if (members[0] is IType) {
 
783
                                                result = new MemberResolveResult (null, true);
 
784
                                                result.UnresolvedType = result.ResolvedType = new DomReturnType ((IType)members[0]);
 
785
                                                goto end;
 
786
                                        } else {
 
787
                                                result = new MemberResolveResult (members[0]);
 
788
                                        }
 
789
                                        result.UnresolvedType = members[0].ReturnType;
 
790
                                        result.ResolvedType = ResolveType (members[0].ReturnType);
 
791
                                        if (members[0] is IProperty && searchedType != null && result.ResolvedType.FullName == searchedType.FullName) {
 
792
                                                result = new AggregatedResolveResult (result, new MemberResolveResult (null, true) {
 
793
                                                        UnresolvedType = new DomReturnType (searchedType),
 
794
                                                        ResolvedType = new DomReturnType (searchedType)
 
795
                                                });
 
796
                                        }
 
797
                                        goto end;
 
798
                                }
 
799
                        }
 
800
                        
 
801
                
 
802
                        
 
803
                        
 
804
                        if (searchedType != null) {
 
805
                                result = new MemberResolveResult (null, true);
 
806
                                result.UnresolvedType = result.ResolvedType = new DomReturnType (searchedType);
 
807
                                goto end;
 
808
                        }
 
809
                        
 
810
                        if (dom.NamespaceExists (identifier, true)) {
 
811
                                result = new NamespaceResolveResult (identifier);
 
812
                                goto end;
 
813
                        }
 
814
 
 
815
                        if (unit != null && unit.Usings != null) {
 
816
                                foreach (IUsing u in unit.Usings) {
 
817
                                        if (u.IsFromNamespace && u.Region.Contains (resolvePosition)) {
 
818
                                                foreach (string ns in u.Namespaces) {
 
819
                                                        if (dom.NamespaceExists (ns + "."  + identifier, true)) {
 
820
                                                                result = new NamespaceResolveResult (ns + "."  + identifier);
 
821
                                                                goto end;
 
822
                                                        }
 
823
                                                }
 
824
                                        }
 
825
                                        foreach (KeyValuePair<string, IReturnType> alias in u.Aliases) {
 
826
                                                if (alias.Key == identifier || alias.Key + ".?" == identifier) {
 
827
                                                        result = new NamespaceResolveResult (alias.Value.FullName);
 
828
                                                        goto end;
 
829
                                                }
 
830
                                        }
 
831
                                }
 
832
                        }
 
833
                                
 
834
                end:
 
835
                        if (result != null) {
 
836
                                result.CallingType   = CallingType;
 
837
                                result.CallingMember = CallingMember;
 
838
                        }
 
839
                        resultTable[identifier] = result;
 
840
                        return result;
 
841
                }
 
842
                
 
843
                internal static string CreateWrapperClassForMember (IMember member, string fileName, TextEditor editor)
 
844
                {
 
845
                        if (member == null)
 
846
                                return "";
 
847
                        StringBuilder result = new StringBuilder ();
 
848
                        int startLine = member.Location.Line;
 
849
                        int endLine   = member.Location.Line;
 
850
                        if (!member.BodyRegion.IsEmpty) 
 
851
                                endLine = member.BodyRegion.End.Line + 1;
 
852
                        string text;
 
853
                        result.Append ("class " + member.DeclaringType.Name + " {");
 
854
                        if (editor != null) {
 
855
                                int col, maxLine;
 
856
                                editor.GetLineColumnFromPosition (editor.TextLength - 1, out col, out maxLine);
 
857
                                endLine = System.Math.Max (endLine, maxLine);
 
858
                                
 
859
                                int endPos = editor.GetPositionFromLineColumn (endLine, editor.GetLineLength (endLine));
 
860
                                if (endPos < 0)
 
861
                                        endPos = editor.TextLength;
 
862
                                text = editor.GetText (editor.GetPositionFromLineColumn (startLine, 0), endPos);
 
863
                        } else {
 
864
                                Mono.TextEditor.Document doc = new Mono.TextEditor.Document ();
 
865
                                doc.Text = File.ReadAllText (fileName) ?? "";
 
866
                                startLine = Math.Min (doc.LineCount, Math.Max (1, startLine));
 
867
                                endLine   = Math.Min (doc.LineCount, Math.Max (1, endLine));
 
868
                                int startOffset = doc.LocationToOffset (startLine - 1, 0);
 
869
                                text = doc.GetTextAt (startOffset, doc.LocationToOffset (endLine  - 1, doc.GetLine (endLine - 1).EditableLength) - startOffset);
 
870
                        }
 
871
                        if (!string.IsNullOrEmpty (text))
 
872
                                result.Append (text);
 
873
                        result.Append ("}");
 
874
                        
 
875
                        return result.ToString ();
 
876
                }
 
877
        }
 
878
        static class HelperMethods
 
879
        {
 
880
                public static void SetText (this ICompletionData data, string text)
 
881
                {
 
882
                        if (data is CompletionData) {
 
883
                                ((CompletionData)data).CompletionText = text;
 
884
                        } else if (data is MemberCompletionData) {
 
885
                                ((MemberCompletionData)data).CompletionText = text;
 
886
                        } else {
 
887
                                System.Console.WriteLine("Unknown completion data:" + data);
 
888
                        }
 
889
                }
 
890
        }
 
891
        
 
892
}