Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HiveProjectManagement/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Completion/CSharpCompletionEngineBase.cs @ 15377

Last change on this file since 15377 was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 25.5 KB
Line 
1//
2// CSharpCompletionEngineBase.cs
3// 
4// Author:
5//       Mike Krüger <mkrueger@xamarin.com>
6//
7// Copyright (c) 2011 Xamarin Inc. (http://xamarin.com)
8//
9// Permission is hereby granted, free of charge, to any person obtaining a copy
10// of this software and associated documentation files (the "Software"), to deal
11// in the Software without restriction, including without limitation the rights
12// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13// copies of the Software, and to permit persons to whom the Software is
14// furnished to do so, subject to the following conditions:
15//
16// The above copyright notice and this permission notice shall be included in
17// all copies or substantial portions of the Software.
18//
19// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25// THE SOFTWARE.
26using System;
27using System.Collections.Generic;
28using System.Linq;
29using System.Text;
30
31using ICSharpCode.NRefactory.CSharp.Resolver;
32using ICSharpCode.NRefactory.Editor;
33using ICSharpCode.NRefactory.TypeSystem;
34using ICSharpCode.NRefactory.Semantics;
35using ICSharpCode.NRefactory.TypeSystem.Implementation;
36using ICSharpCode.NRefactory.CSharp.TypeSystem;
37
38namespace ICSharpCode.NRefactory.CSharp.Completion
39{
40  /// <summary>
41  /// Acts as a common base between code completion and parameter completion.
42  /// </summary>
43  public class CSharpCompletionEngineBase
44  {
45    protected IDocument document;
46    protected int offset;
47    protected TextLocation location;
48    protected IUnresolvedTypeDefinition currentType;
49    protected IUnresolvedMember currentMember;
50   
51    #region Input properties
52    public CSharpTypeResolveContext ctx { get; private set; }
53
54    public IProjectContent ProjectContent { get; private set; }
55   
56    ICompilation compilation;
57
58    protected ICompilation Compilation {
59      get {
60        if (compilation == null)
61          compilation = ProjectContent.Resolve (ctx).Compilation;
62        return compilation;
63      }
64    }
65
66    Version languageVersion = new Version (5, 0);
67    public Version LanguageVersion {
68      get {
69        return languageVersion;
70      }
71      set {
72        languageVersion = value;
73      }
74    }
75    #endregion
76   
77    protected CSharpCompletionEngineBase(IProjectContent content, ICompletionContextProvider completionContextProvider, CSharpTypeResolveContext ctx)
78    {
79      if (content == null)
80        throw new ArgumentNullException("content");
81      if (ctx == null)
82        throw new ArgumentNullException("ctx");
83      if (completionContextProvider == null)
84        throw new ArgumentNullException("completionContextProvider");
85     
86      this.ProjectContent = content;
87      this.CompletionContextProvider = completionContextProvider;
88      this.ctx = ctx;
89    }
90   
91   
92    public ICompletionContextProvider CompletionContextProvider {
93      get;
94      private set;
95    }
96   
97    public void SetOffset (int offset)
98    {
99      Reset ();
100     
101      this.offset = offset;
102      this.location = document.GetLocation (offset);
103      CompletionContextProvider.GetCurrentMembers (offset, out currentType, out currentMember);
104    }
105
106    public bool GetParameterCompletionCommandOffset (out int cpos)
107    {
108      // Start calculating the parameter offset from the beginning of the
109      // current member, instead of the beginning of the file.
110      cpos = offset - 1;
111      var mem = currentMember;
112      if (mem == null || (mem is IType) || IsInsideCommentStringOrDirective ()) {
113        return false;
114      }
115      int startPos = document.GetOffset (mem.Region.BeginLine, mem.Region.BeginColumn);
116      int parenDepth = 0;
117      int chevronDepth = 0;
118      Stack<int> indexStack = new Stack<int> ();
119      while (cpos > startPos) {
120        char c = document.GetCharAt (cpos);
121        if (c == ')') {
122          parenDepth++;
123        }
124        if (c == '>') {
125          chevronDepth++;
126        }
127        if (c == '}') {
128          if (indexStack.Count > 0) {
129            parenDepth = indexStack.Pop ();
130          } else {
131            parenDepth = 0;
132          }
133          chevronDepth = 0;
134        }
135        if (indexStack.Count == 0 && (parenDepth == 0 && c == '(' || chevronDepth == 0 && c == '<')) {
136          int p = GetCurrentParameterIndex (startPos, cpos + 1);
137          if (p != -1) {
138            cpos++;
139            return true;
140          } else {
141            return false;
142          }
143        }
144        if (c == '(') {
145          parenDepth--;
146        }
147        if (c == '<') {
148          chevronDepth--;
149        }
150        if (c == '{') {
151          indexStack.Push (parenDepth);
152          chevronDepth = 0;
153        }
154        cpos--;
155      }
156      return false;
157    }
158   
159    public int GetCurrentParameterIndex(int triggerOffset, int endOffset)
160    {
161      List<string> list;
162      return  GetCurrentParameterIndex (triggerOffset, endOffset, out list);
163    }
164
165    public int GetCurrentParameterIndex (int triggerOffset, int endOffset, out List<string> usedNamedParameters)
166    {
167      usedNamedParameters =new List<string> ();
168      var parameter = new Stack<int> ();
169      var bracketStack = new Stack<Stack<int>> ();
170      bool inSingleComment = false, inString = false, inVerbatimString = false, inChar = false, inMultiLineComment = false;
171      var word = new StringBuilder ();
172      bool foundCharAfterOpenBracket = false;
173      for (int i = triggerOffset; i < endOffset; i++) {
174        char ch = document.GetCharAt (i);
175        char nextCh = i + 1 < document.TextLength ? document.GetCharAt (i + 1) : '\0';
176        if (ch == ':') {
177          usedNamedParameters.Add (word.ToString ());
178          word.Length = 0;
179        } else if (char.IsLetterOrDigit (ch) || ch =='_') {
180          word.Append (ch);
181        } else if (char.IsWhiteSpace (ch)) {
182
183        } else {
184          word.Length = 0;
185        }
186        if (!char.IsWhiteSpace(ch) && parameter.Count > 0)
187          foundCharAfterOpenBracket = true;
188
189        switch (ch) {
190          case '{':
191            if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
192              break;
193            }
194            bracketStack.Push (parameter);
195            parameter = new Stack<int> ();
196            break;
197          case '[':
198          case '(':
199            if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
200              break;
201            }
202            parameter.Push (0);
203            break;
204          case '}':
205            if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
206              break;
207            }
208            if (bracketStack.Count > 0) {
209              parameter = bracketStack.Pop ();
210            } else {
211              return -1;
212            }
213            break;
214          case ']':
215          case ')':
216            if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
217              break;
218            }
219            if (parameter.Count > 0) {
220              parameter.Pop ();
221            } else {
222              return -1;
223            }
224            break;
225          case '<':
226            if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
227              break;
228            }
229            parameter.Push (0);
230            break;
231          case '=':
232            if (nextCh == '>') {
233              i++;
234              continue;
235            }
236            break;
237          case '>':
238            if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
239              break;
240            }
241            if (parameter.Count > 0) {
242              parameter.Pop ();
243            }
244            break;
245          case ',':
246            if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
247              break;
248            }
249            if (parameter.Count > 0) {
250              parameter.Push (parameter.Pop () + 1);
251            }
252            break;
253          case '/':
254            if (inString || inChar || inVerbatimString) {
255              break;
256            }
257            if (nextCh == '/') {
258              i++;
259              inSingleComment = true;
260            }
261            if (nextCh == '*') {
262              inMultiLineComment = true;
263            }
264            break;
265          case '*':
266            if (inString || inChar || inVerbatimString || inSingleComment) {
267              break;
268            }
269            if (nextCh == '/') {
270              i++;
271              inMultiLineComment = false;
272            }
273            break;
274          case '@':
275            if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
276              break;
277            }
278            if (nextCh == '"') {
279              i++;
280              inVerbatimString = true;
281            }
282            break;
283          case '\\':
284            if (inString || inChar) {
285              i++;
286            }
287            break;
288          case '"':
289            if (inSingleComment || inMultiLineComment || inChar) {
290              break;
291            }
292            if (inVerbatimString) {
293              if (nextCh == '"') {
294                i++;
295                break;
296              }
297              inVerbatimString = false;
298              break;
299            }
300            inString = !inString;
301            break;
302          case '\'':
303            if (inSingleComment || inMultiLineComment || inString || inVerbatimString) {
304              break;
305            }
306            inChar = !inChar;
307            break;
308          default:
309            if (NewLine.IsNewLine(ch)) {
310              inSingleComment = false;
311              inString = false;
312              inChar = false;
313            }
314            break;
315        }
316      }
317      if (parameter.Count != 1 || bracketStack.Count > 0) {
318        return -1;
319      }
320      if (!foundCharAfterOpenBracket)
321        return 0;
322      return parameter.Pop() + 1;
323    }
324
325    #region Context helper methods
326    public class MiniLexer
327    {
328      readonly string text;
329
330      public bool IsFistNonWs               = true;
331      public bool IsInSingleComment         = false;
332      public bool IsInString                = false;
333      public bool IsInVerbatimString        = false;
334      public bool IsInChar                  = false;
335      public bool IsInMultiLineComment      = false;
336      public bool IsInPreprocessorDirective = false;
337
338      public MiniLexer(string text)
339      {
340        this.text = text;
341      }
342
343      /// <summary>
344      /// Parsing all text and calling act delegate on almost every character.
345      /// Skipping begining of comments, begining of verbatim strings and escaped characters.
346      /// </summary>
347      /// <param name="act">Return true to abort parsing. Integer argument represent offset in text.</param>
348      /// <returns>True if aborted.</returns>
349      public bool Parse(Func<char, int, bool> act = null)
350      {
351        return Parse(0, text.Length, act);
352      }
353
354
355      /// <summary>
356      /// Parsing text from start to start+length and calling act delegate on almost every character.
357      /// Skipping begining of comments, begining of verbatim strings and escaped characters.
358      /// </summary>
359      /// <param name="start">Start offset.</param>
360      /// <param name="length">Lenght to parse.</param>
361      /// <param name="act">Return true to abort parsing. Integer argument represent offset in text.</param>
362      /// <returns>True if aborted.</returns>
363      public bool Parse(int start, int length, Func<char, int, bool> act = null)
364      {
365        for (int i = start; i < length; i++) {
366          char ch = text [i];
367          char nextCh = i + 1 < text.Length ? text [i + 1] : '\0';
368          switch (ch) {
369            case '#':
370              if (IsFistNonWs)
371                IsInPreprocessorDirective = true;
372              break;
373            case '/':
374              if (IsInString || IsInChar || IsInVerbatimString || IsInSingleComment || IsInMultiLineComment)
375                break;
376              if (nextCh == '/') {
377                i++;
378                IsInSingleComment = true;
379                IsInPreprocessorDirective = false;
380              }
381              if (nextCh == '*' && !IsInPreprocessorDirective) {
382                IsInMultiLineComment = true;
383                i++;
384              }
385              break;
386            case '*':
387              if (IsInString || IsInChar || IsInVerbatimString || IsInSingleComment)
388                break;
389              if (nextCh == '/') {
390                i++;
391                IsInMultiLineComment = false;
392              }
393              break;
394            case '@':
395              if (IsInString || IsInChar || IsInVerbatimString || IsInSingleComment || IsInMultiLineComment)
396                break;
397              if (nextCh == '"') {
398                i++;
399                IsInVerbatimString = true;
400              }
401              break;
402            case '\n':
403            case '\r':
404              IsInSingleComment = false;
405              IsInString = false;
406              IsInChar = false;
407              IsFistNonWs = true;
408              IsInPreprocessorDirective = false;
409              break;
410            case '\\':
411              if (IsInString || IsInChar)
412                i++;
413              break;
414            case '"':
415              if (IsInSingleComment || IsInMultiLineComment || IsInChar)
416                break;
417              if (IsInVerbatimString) {
418                if (nextCh == '"') {
419                  i++;
420                  break;
421                }
422                IsInVerbatimString = false;
423                break;
424              }
425              IsInString = !IsInString;
426              break;
427            case '\'':
428              if (IsInSingleComment || IsInMultiLineComment || IsInString || IsInVerbatimString)
429                break;
430              IsInChar = !IsInChar;
431              break;
432          }
433          if (act != null)
434          if (act (ch, i))
435            return true;
436          IsFistNonWs &= ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
437        }
438        return false;
439      }
440    }
441
442   
443    protected bool IsInsideCommentStringOrDirective(int offset)
444    {
445      var lexer = new MiniLexer(document.Text);
446      lexer.Parse(0, offset);
447      return
448        lexer.IsInSingleComment ||
449        lexer.IsInString ||
450        lexer.IsInVerbatimString ||
451        lexer.IsInChar ||
452        lexer.IsInMultiLineComment ||
453        lexer.IsInPreprocessorDirective;
454    }
455
456
457    protected bool IsInsideCommentStringOrDirective()
458    {
459      var text = GetMemberTextToCaret();
460      var lexer = new MiniLexer(text.Item1);
461      lexer.Parse();
462      return
463        lexer.IsInSingleComment ||
464          lexer.IsInString ||
465          lexer.IsInVerbatimString ||
466          lexer.IsInChar ||
467          lexer.IsInMultiLineComment ||
468          lexer.IsInPreprocessorDirective;
469    }
470
471    protected bool IsInsideDocComment ()
472    {
473      var text = GetMemberTextToCaret ();
474      bool inSingleComment = false, inString = false, inVerbatimString = false, inChar = false, inMultiLineComment = false;
475      bool singleLineIsDoc = false;
476     
477      for (int i = 0; i < text.Item1.Length - 1; i++) {
478        char ch = text.Item1 [i];
479        char nextCh = text.Item1 [i + 1];
480       
481        switch (ch) {
482        case '/':
483          if (inString || inChar || inVerbatimString)
484            break;
485          if (nextCh == '/') {
486            i++;
487            inSingleComment = true;
488            singleLineIsDoc = i + 1 < text.Item1.Length && text.Item1 [i + 1] == '/';
489            if (singleLineIsDoc) {
490              i++;
491            }
492          }
493          if (nextCh == '*')
494            inMultiLineComment = true;
495          break;
496        case '*':
497          if (inString || inChar || inVerbatimString || inSingleComment)
498            break;
499          if (nextCh == '/') {
500            i++;
501            inMultiLineComment = false;
502          }
503          break;
504        case '@':
505          if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment)
506            break;
507          if (nextCh == '"') {
508            i++;
509            inVerbatimString = true;
510          }
511          break;
512        case '\n':
513        case '\r':
514          inSingleComment = false;
515          inString = false;
516          inChar = false;
517          break;
518        case '\\':
519          if (inString || inChar)
520            i++;
521          break;
522        case '"':
523          if (inSingleComment || inMultiLineComment || inChar)
524            break;
525          if (inVerbatimString) {
526            if (nextCh == '"') {
527              i++;
528              break;
529            }
530            inVerbatimString = false;
531            break;
532          }
533          inString = !inString;
534          break;
535        case '\'':
536          if (inSingleComment || inMultiLineComment || inString || inVerbatimString)
537            break;
538          inChar = !inChar;
539          break;
540        }
541      }
542     
543      return inSingleComment && singleLineIsDoc;
544    }
545
546    protected CSharpResolver GetState ()
547    {
548      return new CSharpResolver (ctx);
549      /*var state = new CSharpResolver (ctx);
550     
551      state.CurrentMember = currentMember;
552      state.CurrentTypeDefinition = currentType;
553      state.CurrentUsingScope = CSharpUnresolvedFile.GetUsingScope (location);
554      if (state.CurrentMember != null) {
555        var node = Unit.GetNodeAt (location);
556        if (node == null)
557          return state;
558        var navigator = new NodeListResolveVisitorNavigator (new[] { node });
559        var visitor = new ResolveVisitor (state, CSharpUnresolvedFile, navigator);
560        Unit.AcceptVisitor (visitor, null);
561        try {
562          var newState = visitor.GetResolverStateBefore (node);
563          if (newState != null)
564            state = newState;
565        } catch (Exception) {
566        }
567      }
568     
569      return state;*/
570    }
571        #endregion
572   
573    #region Basic parsing/resolving functions
574    static Stack<Tuple<char, int>> GetBracketStack (string memberText)
575    {
576      var bracketStack = new Stack<Tuple<char, int>> ();
577     
578      bool inSingleComment = false, inString = false, inVerbatimString = false, inChar = false, inMultiLineComment = false;
579     
580      for (int i = 0; i < memberText.Length; i++) {
581        char ch = memberText [i];
582        char nextCh = i + 1 < memberText.Length ? memberText [i + 1] : '\0';
583        switch (ch) {
584        case '(':
585        case '[':
586        case '{':
587          if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment)
588            break;
589          bracketStack.Push (Tuple.Create (ch, i));
590          break;
591        case ')':
592        case ']':
593        case '}':
594          if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment)
595            break;
596          if (bracketStack.Count > 0)
597            bracketStack.Pop ();
598          break;
599        case '/':
600          if (inString || inChar || inVerbatimString)
601            break;
602          if (nextCh == '/') {
603            i++;
604            inSingleComment = true;
605          }
606          if (nextCh == '*')
607            inMultiLineComment = true;
608          break;
609        case '*':
610          if (inString || inChar || inVerbatimString || inSingleComment)
611            break;
612          if (nextCh == '/') {
613            i++;
614            inMultiLineComment = false;
615          }
616          break;
617        case '@':
618          if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment)
619            break;
620          if (nextCh == '"') {
621            i++;
622            inVerbatimString = true;
623          }
624          break;
625        case '\\':
626          if (inString || inChar)
627            i++;
628          break;
629        case '"':
630          if (inSingleComment || inMultiLineComment || inChar)
631            break;
632          if (inVerbatimString) {
633            if (nextCh == '"') {
634              i++;
635              break;
636            }
637            inVerbatimString = false;
638            break;
639          }
640          inString = !inString;
641          break;
642        case '\'':
643          if (inSingleComment || inMultiLineComment || inString || inVerbatimString)
644            break;
645          inChar = !inChar;
646          break;
647        default :
648          if (NewLine.IsNewLine(ch)) {
649            inSingleComment = false;
650            inString = false;
651            inChar = false;
652          }
653          break;
654        }
655      }
656      return bracketStack;
657    }
658   
659    public static void AppendMissingClosingBrackets (StringBuilder wrapper, bool appendSemicolon)
660    {
661      var memberText = wrapper.ToString();
662      var bracketStack = GetBracketStack(memberText);
663      bool didAppendSemicolon = !appendSemicolon;
664      //char lastBracket = '\0';
665      while (bracketStack.Count > 0) {
666        var t = bracketStack.Pop ();
667        switch (t.Item1) {
668        case '(':
669          wrapper.Append (')');
670          if (appendSemicolon)
671            didAppendSemicolon = false;
672          //lastBracket = ')';
673          break;
674        case '[':
675          wrapper.Append (']');
676          if (appendSemicolon)
677            didAppendSemicolon = false;
678          //lastBracket = ']';
679          break;
680        case '<':
681          wrapper.Append ('>');
682          if (appendSemicolon)
683            didAppendSemicolon = false;
684          //lastBracket = '>';
685          break;
686        case '{':
687          int o = t.Item2 - 1;
688          if (!didAppendSemicolon) {
689            didAppendSemicolon = true;
690            wrapper.Append (';');
691          }
692           
693          bool didAppendCatch = false;
694          while (o >= "try".Length) {
695            char ch = memberText [o];
696            if (!char.IsWhiteSpace (ch)) {
697                if (ch == 'y' && memberText [o - 1] == 'r' && memberText [o - 2] == 't' && (o - 3 < 0 || !char.IsLetterOrDigit(memberText [o - 3]))) {
698                wrapper.Append ("} catch {}");
699                didAppendCatch = true;
700              }
701              break;
702            }
703            o--;
704          }
705          if (!didAppendCatch)
706            wrapper.Append ('}');
707          break;
708        }
709      }
710      if (!didAppendSemicolon)
711        wrapper.Append (';');
712    }
713
714    protected StringBuilder CreateWrapper(string continuation, bool appendSemicolon, string afterContinuation, string memberText, TextLocation memberLocation, ref int closingBrackets, ref int generatedLines)
715    {
716      var wrapper = new StringBuilder();
717      bool wrapInClass = memberLocation != new TextLocation(1, 1);
718      if (wrapInClass) {
719        wrapper.Append("class Stub {");
720        wrapper.AppendLine();
721        closingBrackets++;
722        generatedLines++;
723      }
724      wrapper.Append(memberText);
725      wrapper.Append(continuation);
726      AppendMissingClosingBrackets(wrapper, appendSemicolon);
727      wrapper.Append(afterContinuation);
728      if (closingBrackets > 0) {
729        wrapper.Append(new string('}', closingBrackets));
730      }
731      return wrapper;
732    }
733
734    protected SyntaxTree ParseStub(string continuation, bool appendSemicolon = true, string afterContinuation = null)
735    {
736      var mt = GetMemberTextToCaret();
737      if (mt == null) {
738        return null;
739      }
740
741      string memberText = mt.Item1;
742      var memberLocation = mt.Item2;
743      int closingBrackets = 1;
744      int generatedLines = 0;
745      var wrapper = CreateWrapper(continuation, appendSemicolon, afterContinuation, memberText, memberLocation, ref closingBrackets, ref generatedLines);
746      var parser = new CSharpParser ();
747      foreach (var sym in CompletionContextProvider.ConditionalSymbols)
748        parser.CompilerSettings.ConditionalSymbols.Add (sym);
749      parser.InitialLocation = new TextLocation(memberLocation.Line - generatedLines, 1);
750      var result = parser.Parse(wrapper.ToString ());
751      return result;
752    }
753   
754    protected virtual void Reset ()
755    {
756      memberText = null;
757    }
758
759    Tuple<string, TextLocation> memberText;
760    protected Tuple<string, TextLocation> GetMemberTextToCaret()
761    {
762      if (memberText == null)
763        memberText = CompletionContextProvider.GetMemberTextToCaret(offset, currentType, currentMember);
764      return memberText;
765    }
766
767    protected ExpressionResult GetInvocationBeforeCursor(bool afterBracket)
768    {
769      SyntaxTree baseUnit;
770      baseUnit = ParseStub("a", false);
771
772      var section = baseUnit.GetNodeAt<AttributeSection>(location.Line, location.Column - 2);
773      var attr = section != null ? section.Attributes.LastOrDefault() : null;
774      if (attr != null) {
775        return new ExpressionResult((AstNode)attr, baseUnit);
776      }
777
778      //var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin;
779      var mref = baseUnit.GetNodeAt(location.Line, location.Column - 1, n => n is InvocationExpression || n is ObjectCreateExpression);
780      AstNode expr = null;
781      if (mref is InvocationExpression) {
782        expr = ((InvocationExpression)mref).Target;
783      } else if (mref is ObjectCreateExpression) {
784        expr = mref;
785      } else {
786        baseUnit = ParseStub(")};", false);
787        mref = baseUnit.GetNodeAt(location.Line, location.Column - 1, n => n is InvocationExpression || n is ObjectCreateExpression);
788        if (mref is InvocationExpression) {
789          expr = ((InvocationExpression)mref).Target;
790        } else if (mref is ObjectCreateExpression) {
791          expr = mref;
792        }
793      }
794
795      if (expr == null) {
796        // work around for missing ';' bug in mcs:
797        baseUnit = ParseStub("a", true);
798     
799        section = baseUnit.GetNodeAt<AttributeSection>(location.Line, location.Column - 2);
800        attr = section != null ? section.Attributes.LastOrDefault() : null;
801        if (attr != null) {
802          return new ExpressionResult((AstNode)attr, baseUnit);
803        }
804 
805        //var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin;
806        mref = baseUnit.GetNodeAt(location.Line, location.Column - 1, n => n is InvocationExpression || n is ObjectCreateExpression);
807        expr = null;
808        if (mref is InvocationExpression) {
809          expr = ((InvocationExpression)mref).Target;
810        } else if (mref is ObjectCreateExpression) {
811          expr = mref;
812        }
813      }
814
815      if (expr == null) {
816        return null;
817      }
818      return new ExpressionResult ((AstNode)expr, baseUnit);
819    }
820   
821    public class ExpressionResult
822    {
823      public AstNode Node { get; private set; }
824      public SyntaxTree Unit  { get; private set; }
825     
826     
827      public ExpressionResult (AstNode item2, SyntaxTree item3)
828      {
829        this.Node = item2;
830        this.Unit = item3;
831      }
832     
833      public override string ToString ()
834      {
835        return string.Format ("[ExpressionResult: Node={0}, Unit={1}]", Node, Unit);
836      }
837    }
838   
839    protected ExpressionResolveResult ResolveExpression (ExpressionResult tuple)
840    {
841      return ResolveExpression (tuple.Node);
842    }
843
844    protected class ExpressionResolveResult
845    {
846      public ResolveResult Result { get; set; }
847      public CSharpResolver Resolver { get; set; }
848      public CSharpAstResolver AstResolver { get; set; }
849
850      public ExpressionResolveResult(ResolveResult item1, CSharpResolver item2, CSharpAstResolver item3)
851      {
852        this.Result = item1;
853        this.Resolver = item2;
854        this.AstResolver = item3;
855      }
856    }
857
858    protected ExpressionResolveResult ResolveExpression(AstNode expr)
859    {
860      if (expr == null) {
861        return null;
862      }
863      AstNode resolveNode;
864      if (expr is Expression || expr is AstType) {
865        resolveNode = expr;
866      } else if (expr is VariableDeclarationStatement) {
867        resolveNode = ((VariableDeclarationStatement)expr).Type;
868      } else {
869        resolveNode = expr;
870      }
871      try {
872        var root = expr.AncestorsAndSelf.FirstOrDefault(n => n is EntityDeclaration || n is SyntaxTree);
873        if (root == null) {
874          return null;
875        }
876        var curState = GetState();
877        // current member needs to be in the setter because of the 'value' parameter
878        if (root is Accessor) {
879          var prop = curState.CurrentMember as IProperty;
880          if (prop != null && prop.CanSet && (root.Role == IndexerDeclaration.SetterRole || root.Role == PropertyDeclaration.SetterRole))
881              curState = curState.WithCurrentMember(prop.Setter);
882        }
883
884        // Rood should be the 'body' - otherwise the state -> current member isn't correct.
885        var body = root.Children.FirstOrDefault(r => r.Role == Roles.Body);
886        if (body != null && body.Contains(expr.StartLocation))
887          root = body;
888
889        var csResolver = CompletionContextProvider.GetResolver (curState, root);
890        var result = csResolver.Resolve(resolveNode);
891        var state = csResolver.GetResolverStateBefore(resolveNode);
892        if (state.CurrentMember == null)
893          state = state.WithCurrentMember(curState.CurrentMember);
894        if (state.CurrentTypeDefinition == null)
895          state = state.WithCurrentTypeDefinition(curState.CurrentTypeDefinition);
896        if (state.CurrentUsingScope == null)
897          state = state.WithCurrentUsingScope(curState.CurrentUsingScope);
898        return new ExpressionResolveResult(result, state, csResolver);
899      } catch (Exception e) {
900        Console.WriteLine(e);
901        return null;
902      }
903    }
904   
905    #endregion
906  }
907}
Note: See TracBrowser for help on using the repository browser.