Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Resolver/FindReferences.cs

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

#2077: created branch and added first version

File size: 56.1 KB
Line 
1// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4// software and associated documentation files (the "Software"), to deal in the Software
5// without restriction, including without limitation the rights to use, copy, modify, merge,
6// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7// to whom the Software is furnished to do so, subject to the following conditions:
8//
9// The above copyright notice and this permission notice shall be included in all copies or
10// substantial portions of the Software.
11//
12// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17// DEALINGS IN THE SOFTWARE.
18
19using System;
20using System.Collections.Generic;
21using System.Diagnostics;
22using System.Linq;
23using System.Threading;
24using ICSharpCode.NRefactory.CSharp;
25using ICSharpCode.NRefactory.CSharp.Refactoring;
26using ICSharpCode.NRefactory.CSharp.TypeSystem;
27using ICSharpCode.NRefactory.Semantics;
28using ICSharpCode.NRefactory.TypeSystem;
29using ICSharpCode.NRefactory.Utils;
30
31namespace ICSharpCode.NRefactory.CSharp.Resolver
32{
33  public delegate void FoundReferenceCallback(AstNode astNode, ResolveResult result);
34 
35  /// <summary>
36  /// 'Find references' implementation.
37  /// </summary>
38  /// <remarks>
39  /// This class is thread-safe.
40  /// The intended multi-threaded usage is to call GetSearchScopes() once, and then
41  /// call FindReferencesInFile() concurrently on multiple threads (parallel foreach over all interesting files).
42  /// </remarks>
43  public sealed class FindReferences
44  {
45    #region Properties
46    /// <summary>
47    /// Specifies whether to find type references even if an alias is being used.
48    /// Aliases may be <c>var</c> or <c>using Alias = ...;</c>.
49    /// </summary>
50    public bool FindTypeReferencesEvenIfAliased { get; set; }
51   
52    /// <summary>
53    /// Specifies whether find references should only look for specialized matches
54    /// with equal type parameter substitution to the member we are searching for.
55    /// </summary>
56    public bool FindOnlySpecializedReferences { get; set; }
57   
58    /// <summary>
59    /// If this option is enabled, find references on a overridden member
60    /// will find calls to the base member.
61    /// </summary>
62    public bool FindCallsThroughVirtualBaseMethod { get; set; }
63   
64    /// <summary>
65    /// If this option is enabled, find references on a member implementing
66    /// an interface will also find calls to the interface.
67    /// </summary>
68    public bool FindCallsThroughInterface { get; set; }
69   
70    /// <summary>
71    /// If this option is enabled, find references will look for all references
72    /// to the virtual method slot.
73    /// </summary>
74    public bool WholeVirtualSlot { get; set; }
75   
76    //public bool FindAllOverloads { get; set; }
77   
78    /// <summary>
79    /// Specifies whether to look for references in documentation comments.
80    /// This will find entity references in <c>cref</c> attributes and
81    /// parameter references in <c>&lt;param&gt;</c> and <c>&lt;paramref&gt;</c> tags.
82    /// TODO: implement this feature.
83    /// </summary>
84    public bool SearchInDocumentationComments { get; set; }
85    #endregion
86   
87    #region GetEffectiveAccessibility
88    /// <summary>
89    /// Gets the effective accessibility of the specified entity -
90    /// that is, the accessibility viewed from the top level.
91    /// </summary>
92    /// <remarks>
93    /// internal member in public class -> internal
94    /// public member in internal class -> internal
95    /// protected member in public class -> protected
96    /// protected member in internal class -> protected and internal
97    /// </remarks>
98    public static Accessibility GetEffectiveAccessibility(IEntity entity)
99    {
100      if (entity == null)
101        throw new ArgumentNullException("entity");
102      Accessibility a = entity.Accessibility;
103      for (ITypeDefinition declType = entity.DeclaringTypeDefinition; declType != null; declType = declType.DeclaringTypeDefinition) {
104        a = MergeAccessibility(declType.Accessibility, a);
105      }
106      return a;
107    }
108   
109    static Accessibility MergeAccessibility(Accessibility outer, Accessibility inner)
110    {
111      if (outer == inner)
112        return inner;
113      if (outer == Accessibility.None || inner == Accessibility.None)
114        return Accessibility.None;
115      if (outer == Accessibility.Private || inner == Accessibility.Private)
116        return Accessibility.Private;
117      if (outer == Accessibility.Public)
118        return inner;
119      if (inner == Accessibility.Public)
120        return outer;
121      // Inner and outer are both in { protected, internal, protected and internal, protected or internal }
122      // (but they aren't both the same)
123      if (outer == Accessibility.ProtectedOrInternal)
124        return inner;
125      if (inner == Accessibility.ProtectedOrInternal)
126        return outer;
127      // Inner and outer are both in { protected, internal, protected and internal },
128      // but aren't both the same, so the result is protected and internal.
129      return Accessibility.ProtectedAndInternal;
130    }
131    #endregion
132   
133    #region class SearchScope
134    sealed class SearchScope : IFindReferenceSearchScope
135    {
136      readonly Func<ICompilation, FindReferenceNavigator> factory;
137     
138      public SearchScope(Func<ICompilation, FindReferenceNavigator> factory)
139      {
140        this.factory = factory;
141      }
142     
143      public SearchScope(string searchTerm, Func<ICompilation, FindReferenceNavigator> factory)
144      {
145        this.searchTerm = searchTerm;
146        this.factory = factory;
147      }
148     
149      internal string searchTerm;
150      internal FindReferences findReferences;
151      internal ICompilation declarationCompilation;
152      internal Accessibility accessibility;
153      internal ITypeDefinition topLevelTypeDefinition;
154      internal string fileName;
155     
156      IResolveVisitorNavigator IFindReferenceSearchScope.GetNavigator(ICompilation compilation, FoundReferenceCallback callback)
157      {
158        FindReferenceNavigator n = factory(compilation);
159        if (n != null) {
160          n.callback = callback;
161          n.findReferences = findReferences;
162          return n;
163        } else {
164          return new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Skip, null);
165        }
166      }
167     
168      ICompilation IFindReferenceSearchScope.Compilation {
169        get { return declarationCompilation; }
170      }
171     
172      string IFindReferenceSearchScope.SearchTerm {
173        get { return searchTerm; }
174      }
175     
176      Accessibility IFindReferenceSearchScope.Accessibility {
177        get { return accessibility; }
178      }
179     
180      ITypeDefinition IFindReferenceSearchScope.TopLevelTypeDefinition {
181        get { return topLevelTypeDefinition; }
182      }
183     
184      string IFindReferenceSearchScope.FileName {
185        get { return fileName; }
186      }
187    }
188   
189    abstract class FindReferenceNavigator : IResolveVisitorNavigator
190    {
191      internal FoundReferenceCallback callback;
192      internal FindReferences findReferences;
193     
194      internal abstract bool CanMatch(AstNode node);
195      internal abstract bool IsMatch(ResolveResult rr);
196     
197      ResolveVisitorNavigationMode IResolveVisitorNavigator.Scan(AstNode node)
198      {
199        if (CanMatch(node))
200          return ResolveVisitorNavigationMode.Resolve;
201        else
202          return ResolveVisitorNavigationMode.Scan;
203      }
204     
205      void IResolveVisitorNavigator.Resolved(AstNode node, ResolveResult result)
206      {
207        if (CanMatch(node) && IsMatch(result)) {
208          ReportMatch(node, result);
209        }
210      }
211     
212      public virtual void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
213      {
214      }
215     
216      protected void ReportMatch(AstNode node, ResolveResult result)
217      {
218        if (callback != null)
219          callback(node, result);
220      }
221     
222      internal virtual void NavigatorDone(CSharpAstResolver resolver, CancellationToken cancellationToken)
223      {
224      }
225    }
226    #endregion
227   
228    #region GetSearchScopes
229    public IList<IFindReferenceSearchScope> GetSearchScopes(ISymbol symbol)
230    {
231      if (symbol == null)
232        throw new ArgumentNullException("symbol");
233      switch (symbol.SymbolKind) {
234        case SymbolKind.Namespace:
235          return new[] { GetSearchScopeForNamespace((INamespace)symbol) };
236        case SymbolKind.TypeParameter:
237          return new[] { GetSearchScopeForTypeParameter((ITypeParameter)symbol) };
238      }
239      SearchScope scope;
240      SearchScope additionalScope = null;
241      IEntity entity = null;
242
243      if (symbol.SymbolKind == SymbolKind.Variable) {
244        var variable = (IVariable) symbol;
245        scope = GetSearchScopeForLocalVariable(variable);
246      } else if (symbol.SymbolKind == SymbolKind.Parameter) {
247        var par = (IParameter)symbol;
248        scope = GetSearchScopeForParameter(par);
249        entity = par.Owner;
250      } else {
251        entity = symbol as IEntity;
252        if (entity == null)
253          throw new NotSupportedException("Unsupported symbol type");
254        if (entity is IMember)
255          entity = NormalizeMember((IMember)entity);
256        switch (entity.SymbolKind) {
257          case SymbolKind.TypeDefinition:
258            scope = FindTypeDefinitionReferences((ITypeDefinition)entity, this.FindTypeReferencesEvenIfAliased, out additionalScope);
259            break;
260          case SymbolKind.Field:
261            if (entity.DeclaringTypeDefinition != null && entity.DeclaringTypeDefinition.Kind == TypeKind.Enum)
262              scope = FindMemberReferences(entity, m => new FindEnumMemberReferences((IField)m));
263            else
264              scope = FindMemberReferences(entity, m => new FindFieldReferences((IField)m));
265            break;
266          case SymbolKind.Property:
267            scope = FindMemberReferences(entity, m => new FindPropertyReferences((IProperty)m));
268            if (entity.Name == "Current")
269              additionalScope = FindEnumeratorCurrentReferences((IProperty)entity);
270            else if (entity.Name == "IsCompleted")
271              additionalScope = FindAwaiterIsCompletedReferences((IProperty)entity);
272            break;
273          case SymbolKind.Event:
274            scope = FindMemberReferences(entity, m => new FindEventReferences((IEvent)m));
275            break;
276          case SymbolKind.Method:
277            scope = GetSearchScopeForMethod((IMethod)entity);
278            break;
279          case SymbolKind.Indexer:
280            scope = FindIndexerReferences((IProperty)entity);
281            break;
282          case SymbolKind.Operator:
283            scope = GetSearchScopeForOperator((IMethod)entity);
284            break;
285          case SymbolKind.Constructor:
286            IMethod ctor = (IMethod)entity;
287            scope = FindObjectCreateReferences(ctor);
288            additionalScope = FindChainedConstructorReferences(ctor);
289            break;
290          case SymbolKind.Destructor:
291            scope = GetSearchScopeForDestructor((IMethod)entity);
292            break;
293          default:
294            throw new ArgumentException("Unknown entity type " + entity.SymbolKind);
295        }
296      }
297      var effectiveAccessibility = entity != null ? GetEffectiveAccessibility(entity) : Accessibility.Private;
298      var topLevelTypeDefinition = GetTopLevelTypeDefinition(entity);
299
300      if (scope.accessibility == Accessibility.None)
301        scope.accessibility = effectiveAccessibility;
302      scope.declarationCompilation = entity != null ? entity.Compilation : null;
303      scope.topLevelTypeDefinition = topLevelTypeDefinition;
304      scope.findReferences = this;
305      if (additionalScope != null) {
306        if (additionalScope.accessibility == Accessibility.None)
307          additionalScope.accessibility = effectiveAccessibility;
308        additionalScope.declarationCompilation = scope.declarationCompilation;
309        additionalScope.topLevelTypeDefinition = topLevelTypeDefinition;
310        additionalScope.findReferences = this;
311        return new[] { scope, additionalScope };
312      } else {
313        return new[] { scope };
314      }
315    }
316
317    public IList<IFindReferenceSearchScope> GetSearchScopes(IEnumerable<ISymbol> symbols)
318    {
319      if (symbols == null)
320        throw new ArgumentNullException("symbols");
321      return symbols.SelectMany(GetSearchScopes).ToList();
322    }
323   
324    static ITypeDefinition GetTopLevelTypeDefinition(IEntity entity)
325    {
326      if (entity == null)
327        return null;
328      ITypeDefinition topLevelTypeDefinition = entity.DeclaringTypeDefinition;
329      while (topLevelTypeDefinition != null && topLevelTypeDefinition.DeclaringTypeDefinition != null)
330        topLevelTypeDefinition = topLevelTypeDefinition.DeclaringTypeDefinition;
331      return topLevelTypeDefinition;
332    }
333    #endregion
334   
335    #region GetInterestingFileNames
336    /// <summary>
337    /// Gets the file names that possibly contain references to the element being searched for.
338    /// </summary>
339    public IEnumerable<CSharpUnresolvedFile> GetInterestingFiles(IFindReferenceSearchScope searchScope, ICompilation compilation)
340    {
341      if (searchScope == null)
342        throw new ArgumentNullException("searchScope");
343      if (compilation == null)
344        throw new ArgumentNullException("compilation");
345      var pc = compilation.MainAssembly.UnresolvedAssembly as IProjectContent;
346      if (pc == null)
347        throw new ArgumentException("Main assembly is not a project content");
348      if (searchScope.TopLevelTypeDefinition != null) {
349        ITypeDefinition topLevelTypeDef = compilation.Import(searchScope.TopLevelTypeDefinition);
350        if (topLevelTypeDef == null) {
351          // This compilation cannot have references to the target entity.
352          return EmptyList<CSharpUnresolvedFile>.Instance;
353        }
354        switch (searchScope.Accessibility) {
355          case Accessibility.None:
356          case Accessibility.Private:
357            if (topLevelTypeDef.ParentAssembly == compilation.MainAssembly)
358              return topLevelTypeDef.Parts.Select(p => p.UnresolvedFile).OfType<CSharpUnresolvedFile>().Distinct();
359            else
360              return EmptyList<CSharpUnresolvedFile>.Instance;
361          case Accessibility.Protected:
362            return GetInterestingFilesProtected(topLevelTypeDef);
363          case Accessibility.Internal:
364            if (topLevelTypeDef.ParentAssembly.InternalsVisibleTo(compilation.MainAssembly))
365              return pc.Files.OfType<CSharpUnresolvedFile>();
366            else
367              return EmptyList<CSharpUnresolvedFile>.Instance;
368          case Accessibility.ProtectedAndInternal:
369            if (topLevelTypeDef.ParentAssembly.InternalsVisibleTo(compilation.MainAssembly))
370              return GetInterestingFilesProtected(topLevelTypeDef);
371            else
372              return EmptyList<CSharpUnresolvedFile>.Instance;
373          case Accessibility.ProtectedOrInternal:
374            if (topLevelTypeDef.ParentAssembly.InternalsVisibleTo(compilation.MainAssembly))
375              return pc.Files.OfType<CSharpUnresolvedFile>();
376            else
377              return GetInterestingFilesProtected(topLevelTypeDef);
378          default:
379            return pc.Files.OfType<CSharpUnresolvedFile>();
380        }
381      } else {
382        if (searchScope.FileName == null)
383          return pc.Files.OfType<CSharpUnresolvedFile>();
384        else
385          return pc.Files.OfType<CSharpUnresolvedFile>().Where(f => f.FileName == searchScope.FileName);
386      }
387    }
388   
389    IEnumerable<CSharpUnresolvedFile> GetInterestingFilesProtected(ITypeDefinition referencedTypeDefinition)
390    {
391      return (from typeDef in referencedTypeDefinition.Compilation.MainAssembly.GetAllTypeDefinitions()
392              where typeDef.IsDerivedFrom(referencedTypeDefinition)
393              from part in typeDef.Parts
394              select part.UnresolvedFile
395             ).OfType<CSharpUnresolvedFile>().Distinct();
396    }
397    #endregion
398   
399    #region FindReferencesInFile
400    /// <summary>
401    /// Finds all references in the given file.
402    /// </summary>
403    /// <param name="searchScope">The search scope for which to look.</param>
404    /// <param name="resolver">AST resolver for the file to search in.</param>
405    /// <param name="callback">Callback used to report the references that were found.</param>
406    /// <param name="cancellationToken">CancellationToken that may be used to cancel the operation.</param>
407    public void FindReferencesInFile(IFindReferenceSearchScope searchScope, CSharpAstResolver resolver,
408                                     FoundReferenceCallback callback, CancellationToken cancellationToken)
409    {
410      if (resolver == null)
411        throw new ArgumentNullException("resolver");
412      FindReferencesInFile(searchScope, resolver.UnresolvedFile, (SyntaxTree)resolver.RootNode, resolver.Compilation, callback, cancellationToken);
413    }
414   
415    /// <summary>
416    /// Finds all references in the given file.
417    /// </summary>
418    /// <param name="searchScopes">The search scopes for which to look.</param>
419    /// <param name="resolver">AST resolver for the file to search in.</param>
420    /// <param name="callback">Callback used to report the references that were found.</param>
421    /// <param name="cancellationToken">CancellationToken that may be used to cancel the operation.</param>
422    public void FindReferencesInFile(IList<IFindReferenceSearchScope> searchScopes, CSharpAstResolver resolver,
423                                     FoundReferenceCallback callback, CancellationToken cancellationToken)
424    {
425      if (resolver == null)
426        throw new ArgumentNullException("resolver");
427      FindReferencesInFile(searchScopes, resolver.UnresolvedFile, (SyntaxTree)resolver.RootNode, resolver.Compilation, callback, cancellationToken);
428    }
429   
430    /// <summary>
431    /// Finds all references in the given file.
432    /// </summary>
433    /// <param name="searchScope">The search scope for which to look.</param>
434    /// <param name="unresolvedFile">The type system representation of the file being searched.</param>
435    /// <param name="syntaxTree">The syntax tree of the file being searched.</param>
436    /// <param name="compilation">The compilation for the project that contains the file.</param>
437    /// <param name="callback">Callback used to report the references that were found.</param>
438    /// <param name="cancellationToken">CancellationToken that may be used to cancel the operation.</param>
439    public void FindReferencesInFile(IFindReferenceSearchScope searchScope, CSharpUnresolvedFile unresolvedFile, SyntaxTree syntaxTree,
440                                     ICompilation compilation, FoundReferenceCallback callback, CancellationToken cancellationToken)
441    {
442      if (searchScope == null)
443        throw new ArgumentNullException("searchScope");
444      FindReferencesInFile(new[] { searchScope }, unresolvedFile, syntaxTree, compilation, callback, cancellationToken);
445    }
446   
447    /// <summary>
448    /// Finds all references in the given file.
449    /// </summary>
450    /// <param name="searchScopes">The search scopes for which to look.</param>
451    /// <param name="unresolvedFile">The type system representation of the file being searched.</param>
452    /// <param name="syntaxTree">The syntax tree of the file being searched.</param>
453    /// <param name="compilation">The compilation for the project that contains the file.</param>
454    /// <param name="callback">Callback used to report the references that were found.</param>
455    /// <param name="cancellationToken">CancellationToken that may be used to cancel the operation.</param>
456    public void FindReferencesInFile(IList<IFindReferenceSearchScope> searchScopes, CSharpUnresolvedFile unresolvedFile, SyntaxTree syntaxTree,
457                                     ICompilation compilation, FoundReferenceCallback callback, CancellationToken cancellationToken)
458    {
459      if (searchScopes == null)
460        throw new ArgumentNullException("searchScopes");
461      if (syntaxTree == null)
462        throw new ArgumentNullException("syntaxTree");
463      if (compilation == null)
464        throw new ArgumentNullException("compilation");
465      if (callback == null)
466        throw new ArgumentNullException("callback");
467     
468      if (searchScopes.Count == 0)
469        return;
470      var navigators = new IResolveVisitorNavigator[searchScopes.Count];
471      for (int i = 0; i < navigators.Length; i++) {
472        navigators[i] = searchScopes[i].GetNavigator(compilation, callback);
473      }
474      IResolveVisitorNavigator combinedNavigator;
475      if (searchScopes.Count == 1) {
476        combinedNavigator = navigators[0];
477      } else {
478        combinedNavigator = new CompositeResolveVisitorNavigator(navigators);
479      }
480     
481      cancellationToken.ThrowIfCancellationRequested();
482      combinedNavigator = new DetectSkippableNodesNavigator(combinedNavigator, syntaxTree);
483      cancellationToken.ThrowIfCancellationRequested();
484      CSharpAstResolver resolver = new CSharpAstResolver(compilation, syntaxTree, unresolvedFile);
485      resolver.ApplyNavigator(combinedNavigator, cancellationToken);
486      foreach (var n in navigators) {
487        var frn = n as FindReferenceNavigator;
488        if (frn != null)
489          frn.NavigatorDone(resolver, cancellationToken);
490      }
491    }
492    #endregion
493   
494    #region RenameReferencesInFile
495
496    public static AstNode GetNodeToReplace(AstNode node)
497    {
498      if (node is ConstructorInitializer)
499        return null;
500      if (node is ObjectCreateExpression)
501        node = ((ObjectCreateExpression)node).Type;
502
503      if (node is InvocationExpression)
504        node = ((InvocationExpression)node).Target;
505
506      if (node is MemberReferenceExpression)
507        node = ((MemberReferenceExpression)node).MemberNameToken;
508
509      if (node is SimpleType)
510        node = ((SimpleType)node).IdentifierToken;
511
512      if (node is MemberType)
513        node = ((MemberType)node).MemberNameToken;
514
515      if (node is NamespaceDeclaration) {
516//        var nsd = ((NamespaceDeclaration)node);
517//        node = nsd.Identifiers.LastOrDefault (n => n.Name == memberName) ?? nsd.Identifiers.FirstOrDefault ();
518//        if (node == null)
519        return null;
520      }
521
522      if (node is TypeDeclaration)
523        node = ((TypeDeclaration)node).NameToken;
524      if (node is DelegateDeclaration)
525        node = ((DelegateDeclaration)node).NameToken;
526
527      if (node is EntityDeclaration)
528        node = ((EntityDeclaration)node).NameToken;
529
530      if (node is ParameterDeclaration)
531        node = ((ParameterDeclaration)node).NameToken;
532      if (node is ConstructorDeclaration)
533        node = ((ConstructorDeclaration)node).NameToken;
534      if (node is DestructorDeclaration)
535        node = ((DestructorDeclaration)node).NameToken;
536      if (node is NamedArgumentExpression)
537        node = ((NamedArgumentExpression)node).NameToken;
538      if (node is NamedExpression)
539        node = ((NamedExpression)node).NameToken;
540      if (node is VariableInitializer)
541        node = ((VariableInitializer)node).NameToken;
542
543      if (node is IdentifierExpression) {
544        node = ((IdentifierExpression)node).IdentifierToken;
545      }
546      return node;
547    }
548
549    public void RenameReferencesInFile(IList<IFindReferenceSearchScope> searchScopes, string newName, CSharpAstResolver resolver,
550                                       Action<RenameCallbackArguments> callback, Action<Error> errorCallback, CancellationToken cancellationToken = default (CancellationToken))
551    {
552      FindReferencesInFile(
553        searchScopes,
554        resolver,
555        delegate(AstNode astNode, ResolveResult result) {
556          var nodeToReplace = GetNodeToReplace(astNode);
557          if (nodeToReplace == null) {
558            errorCallback (new Error (ErrorType.Error, "no node to replace found."));
559            return;
560          }
561          callback (new RenameCallbackArguments(nodeToReplace, Identifier.Create(newName)));
562        },
563        cancellationToken);
564    }
565    #endregion
566   
567    #region Find TypeDefinition References
568    SearchScope FindTypeDefinitionReferences(ITypeDefinition typeDefinition, bool findTypeReferencesEvenIfAliased, out SearchScope additionalScope)
569    {
570      string searchTerm = null;
571      additionalScope = null;
572      if (!findTypeReferencesEvenIfAliased && KnownTypeReference.GetCSharpNameByTypeCode(typeDefinition.KnownTypeCode) == null) {
573        // We can optimize the search by looking only for the type references with the right identifier,
574        // but only if it's not a primitive type and we're not looking for indirect references (through an alias)
575        searchTerm = typeDefinition.Name;
576        if (searchTerm.Length > 9 && searchTerm.EndsWith("Attribute", StringComparison.Ordinal)) {
577          // The type might be an attribute, so we also need to look for the short form:
578          string shortForm = searchTerm.Substring(0, searchTerm.Length - 9);
579          additionalScope = FindTypeDefinitionReferences(typeDefinition, shortForm);
580        }
581      }
582      return FindTypeDefinitionReferences(typeDefinition, searchTerm);
583    }
584   
585    SearchScope FindTypeDefinitionReferences(ITypeDefinition typeDefinition, string searchTerm)
586    {
587      return new SearchScope(
588        searchTerm,
589        delegate (ICompilation compilation) {
590          ITypeDefinition imported = compilation.Import(typeDefinition);
591          if (imported != null)
592            return new FindTypeDefinitionReferencesNavigator(imported, searchTerm);
593          else
594            return null;
595        });
596    }
597   
598    sealed class FindTypeDefinitionReferencesNavigator : FindReferenceNavigator
599    {
600      readonly ITypeDefinition typeDefinition;
601      readonly string searchTerm;
602     
603      public FindTypeDefinitionReferencesNavigator(ITypeDefinition typeDefinition, string searchTerm)
604      {
605        this.typeDefinition = typeDefinition;
606        this.searchTerm = searchTerm;
607      }
608     
609      internal override bool CanMatch(AstNode node)
610      {
611        IdentifierExpression ident = node as IdentifierExpression;
612        if (ident != null)
613          return searchTerm == null || ident.Identifier == searchTerm;
614       
615        MemberReferenceExpression mre = node as MemberReferenceExpression;
616        if (mre != null)
617          return searchTerm == null || mre.MemberName == searchTerm;
618       
619        SimpleType st = node as SimpleType;
620        if (st != null)
621          return searchTerm == null || st.Identifier == searchTerm;
622       
623        MemberType mt = node as MemberType;
624        if (mt != null)
625          return searchTerm == null || mt.MemberName == searchTerm;
626       
627        if (searchTerm == null && node is PrimitiveType)
628          return true;
629       
630        TypeDeclaration typeDecl = node as TypeDeclaration;
631        if (typeDecl != null)
632          return searchTerm == null || typeDecl.Name == searchTerm;
633       
634        DelegateDeclaration delegateDecl = node as DelegateDeclaration;
635        if (delegateDecl != null)
636          return searchTerm == null || delegateDecl.Name == searchTerm;
637       
638        return false;
639      }
640     
641      internal override bool IsMatch(ResolveResult rr)
642      {
643        TypeResolveResult trr = rr as TypeResolveResult;
644        return trr != null && typeDefinition.Equals(trr.Type.GetDefinition());
645      }
646    }
647    #endregion
648   
649    #region Find Member References
650    SearchScope FindMemberReferences(IEntity member, Func<IMember, FindMemberReferencesNavigator> factory)
651    {
652      string searchTerm = member.Name;
653      return new SearchScope(
654        searchTerm,
655        delegate(ICompilation compilation) {
656          IMember imported = compilation.Import((IMember)member);
657          return imported != null ? factory(imported) : null;
658        });
659    }
660   
661    class FindMemberReferencesNavigator : FindReferenceNavigator
662    {
663      readonly IMember member;
664      readonly string searchTerm;
665     
666      public FindMemberReferencesNavigator(IMember member)
667      {
668        this.member = member;
669        this.searchTerm = member.Name;
670      }
671     
672      internal override bool CanMatch(AstNode node)
673      {
674        IdentifierExpression ident = node as IdentifierExpression;
675        if (ident != null)
676          return ident.Identifier == searchTerm;
677       
678        MemberReferenceExpression mre = node as MemberReferenceExpression;
679        if (mre != null)
680          return mre.MemberName == searchTerm;
681       
682        PointerReferenceExpression pre = node as PointerReferenceExpression;
683        if (pre != null)
684          return pre.MemberName == searchTerm;
685       
686        NamedExpression ne = node as NamedExpression;
687        if (ne != null)
688          return ne.Name == searchTerm;
689       
690        return false;
691      }
692     
693      internal override bool IsMatch(ResolveResult rr)
694      {
695        MemberResolveResult mrr = rr as MemberResolveResult;
696        return mrr != null && findReferences.IsMemberMatch(member, mrr.Member, mrr.IsVirtualCall);
697      }
698    }
699   
700    IMember NormalizeMember(IMember member)
701    {
702      if (WholeVirtualSlot && member.IsOverride)
703        member = InheritanceHelper.GetBaseMembers(member, false).FirstOrDefault(m => !m.IsOverride) ?? member;
704      if (!FindOnlySpecializedReferences)
705        member = member.MemberDefinition;
706      return member;
707    }
708   
709    bool IsMemberMatch(IMember member, IMember referencedMember, bool isVirtualCall)
710    {
711      referencedMember = NormalizeMember(referencedMember);
712      if (member.Equals(referencedMember))
713        return true;
714      if (FindCallsThroughInterface && member.DeclaringTypeDefinition != null && member.DeclaringTypeDefinition.Kind == TypeKind.Interface) {
715        if (FindOnlySpecializedReferences) {
716          return referencedMember.ImplementedInterfaceMembers.Contains(member);
717        } else {
718          return referencedMember.ImplementedInterfaceMembers.Any(m => m.MemberDefinition.Equals(member));
719        }
720      }
721      if (!isVirtualCall)
722        return false;
723      bool isInterfaceCall = referencedMember.DeclaringTypeDefinition != null && referencedMember.DeclaringTypeDefinition.Kind == TypeKind.Interface;
724      if (FindCallsThroughVirtualBaseMethod && member.IsOverride && !WholeVirtualSlot && !isInterfaceCall) {
725        // Test if 'member' overrides 'referencedMember':
726        foreach (var baseMember in InheritanceHelper.GetBaseMembers(member, false)) {
727          if (FindOnlySpecializedReferences) {
728            if (baseMember.Equals(referencedMember))
729              return true;
730          } else {
731            if (baseMember.MemberDefinition.Equals(referencedMember))
732              return true;
733          }
734          if (!baseMember.IsOverride)
735            break;
736        }
737        return false;
738      } else if (FindCallsThroughInterface && isInterfaceCall) {
739        // Test if 'member' implements 'referencedMember':
740        if (FindOnlySpecializedReferences) {
741          return member.ImplementedInterfaceMembers.Contains(referencedMember);
742        } else {
743          return member.ImplementedInterfaceMembers.Any(m => m.MemberDefinition.Equals(referencedMember));
744        }
745      }
746      return false;
747    }
748   
749    /*
750    bool PerformVirtualLookup(IMember member, IMember referencedMember)
751    {
752      if (FindCallsThroughVirtualBaseMethod && member.IsOverride && !WholeVirtualSlot)
753        return true;
754      var typeDef = referencedMember.DeclaringTypeDefinition;
755      return FindCallsThroughInterface && typeDef != null && typeDef.Kind == TypeKind.Interface;
756    }*/
757   
758    sealed class FindFieldReferences : FindMemberReferencesNavigator
759    {
760      public FindFieldReferences(IField field) : base(field)
761      {
762      }
763     
764      internal override bool CanMatch(AstNode node)
765      {
766        if (node is VariableInitializer) {
767          return node.Parent is FieldDeclaration;
768        }
769        return base.CanMatch(node);
770      }
771    }
772   
773    sealed class FindEnumMemberReferences : FindMemberReferencesNavigator
774    {
775      public FindEnumMemberReferences(IField field) : base(field)
776      {
777      }
778     
779      internal override bool CanMatch(AstNode node)
780      {
781        return node is EnumMemberDeclaration || base.CanMatch(node);
782      }
783    }
784   
785    sealed class FindPropertyReferences : FindMemberReferencesNavigator
786    {
787      public FindPropertyReferences(IProperty property) : base(property)
788      {
789      }
790     
791      internal override bool CanMatch(AstNode node)
792      {
793        return node is PropertyDeclaration || base.CanMatch(node);
794      }
795    }
796   
797    sealed class FindEventReferences : FindMemberReferencesNavigator
798    {
799      public FindEventReferences(IEvent ev) : base(ev)
800      {
801      }
802     
803      internal override bool CanMatch(AstNode node)
804      {
805        if (node is VariableInitializer) {
806          return node.Parent is EventDeclaration;
807        }
808        return node is CustomEventDeclaration || base.CanMatch(node);
809      }
810    }
811    #endregion
812   
813    #region Find References to IEnumerator.Current
814    SearchScope FindEnumeratorCurrentReferences(IProperty property)
815    {
816      return new SearchScope(
817        delegate(ICompilation compilation) {
818          IProperty imported = compilation.Import(property);
819          return imported != null ? new FindEnumeratorCurrentReferencesNavigator(imported) : null;
820        });
821    }
822
823    SearchScope FindAwaiterIsCompletedReferences(IProperty property)
824    {
825      return new SearchScope(
826        delegate(ICompilation compilation) {
827          IProperty imported = compilation.Import(property);
828          return imported != null ? new FindAwaiterIsCompletedReferencesNavigator(imported) : null;
829        });
830    }
831   
832    sealed class FindEnumeratorCurrentReferencesNavigator : FindReferenceNavigator
833    {
834      IProperty property;
835     
836      public FindEnumeratorCurrentReferencesNavigator(IProperty property)
837      {
838        this.property = property;
839      }
840     
841      internal override bool CanMatch(AstNode node)
842      {
843        return node is ForeachStatement;
844      }
845     
846      internal override bool IsMatch(ResolveResult rr)
847      {
848        ForEachResolveResult ferr = rr as ForEachResolveResult;
849        return ferr != null && ferr.CurrentProperty != null && findReferences.IsMemberMatch(property, ferr.CurrentProperty, true);
850      }
851    }
852
853    sealed class FindAwaiterIsCompletedReferencesNavigator : FindReferenceNavigator
854    {
855      IProperty property;
856     
857      public FindAwaiterIsCompletedReferencesNavigator(IProperty property)
858      {
859        this.property = property;
860      }
861     
862      internal override bool CanMatch(AstNode node)
863      {
864        return node is UnaryOperatorExpression;
865      }
866     
867      internal override bool IsMatch(ResolveResult rr)
868      {
869        AwaitResolveResult arr = rr as AwaitResolveResult;
870        return arr != null && arr.IsCompletedProperty != null && findReferences.IsMemberMatch(property, arr.IsCompletedProperty, true);
871      }
872    }
873    #endregion
874   
875    #region Find Method References
876    SearchScope GetSearchScopeForMethod(IMethod method)
877    {
878      Type specialNodeType;
879      switch (method.Name) {
880        case "Add":
881          specialNodeType = typeof(ArrayInitializerExpression);
882          break;
883        case "Where":
884          specialNodeType = typeof(QueryWhereClause);
885          break;
886        case "Select":
887          specialNodeType = typeof(QuerySelectClause);
888          break;
889        case "SelectMany":
890          specialNodeType = typeof(QueryFromClause);
891          break;
892        case "Join":
893        case "GroupJoin":
894          specialNodeType = typeof(QueryJoinClause);
895          break;
896        case "OrderBy":
897        case "OrderByDescending":
898        case "ThenBy":
899        case "ThenByDescending":
900          specialNodeType = typeof(QueryOrdering);
901          break;
902        case "GroupBy":
903          specialNodeType = typeof(QueryGroupClause);
904          break;
905        case "Invoke":
906          if (method.DeclaringTypeDefinition != null && method.DeclaringTypeDefinition.Kind == TypeKind.Delegate)
907            specialNodeType = typeof(InvocationExpression);
908          else
909            specialNodeType = null;
910          break;
911        case "GetEnumerator":
912        case "MoveNext":
913          specialNodeType = typeof(ForeachStatement);
914          break;
915        case "GetAwaiter":
916        case "GetResult":
917        case "OnCompleted":
918        case "UnsafeOnCompleted":
919          specialNodeType = typeof(UnaryOperatorExpression);
920          break;
921        default:
922          specialNodeType = null;
923          break;
924      }
925      // Use searchTerm only if specialNodeType==null
926      string searchTerm = (specialNodeType == null) ? method.Name : null;
927      return new SearchScope(
928        searchTerm,
929        delegate (ICompilation compilation) {
930          IMethod imported = compilation.Import(method);
931          if (imported != null)
932            return new FindMethodReferences(imported, specialNodeType);
933          else
934            return null;
935        });
936    }
937   
938    sealed class FindMethodReferences : FindReferenceNavigator
939    {
940      readonly IMethod method;
941      readonly Type specialNodeType;
942      HashSet<Expression> potentialMethodGroupConversions = new HashSet<Expression>();
943     
944      public FindMethodReferences(IMethod method, Type specialNodeType)
945      {
946        this.method = method;
947        this.specialNodeType = specialNodeType;
948      }
949     
950      internal override bool CanMatch(AstNode node)
951      {
952        if (specialNodeType != null && node.GetType() == specialNodeType)
953          return true;
954       
955        Expression expr = node as Expression;
956        if (expr == null)
957          return node is MethodDeclaration;
958       
959        InvocationExpression ie = node as InvocationExpression;
960        if (ie != null) {
961          Expression target = ParenthesizedExpression.UnpackParenthesizedExpression(ie.Target);
962         
963          IdentifierExpression ident = target as IdentifierExpression;
964          if (ident != null)
965            return ident.Identifier == method.Name;
966         
967          MemberReferenceExpression mre = target as MemberReferenceExpression;
968          if (mre != null)
969            return mre.MemberName == method.Name;
970         
971          PointerReferenceExpression pre = target as PointerReferenceExpression;
972          if (pre != null)
973            return pre.MemberName == method.Name;
974        } else if (expr.Role != Roles.TargetExpression) {
975          // MemberReferences & Identifiers that aren't used in an invocation can still match the method
976          // as delegate name.
977          if (expr.GetChildByRole(Roles.Identifier).Name == method.Name)
978            potentialMethodGroupConversions.Add(expr);
979        }
980        return node is MethodDeclaration;
981      }
982     
983      internal override bool IsMatch(ResolveResult rr)
984      {
985        if (specialNodeType != null) {
986          var ferr = rr as ForEachResolveResult;
987          if (ferr != null) {
988            return IsMatch(ferr.GetEnumeratorCall)
989              || (ferr.MoveNextMethod != null && findReferences.IsMemberMatch(method, ferr.MoveNextMethod, true));
990          }
991          var arr = rr as AwaitResolveResult;
992          if (arr != null) {
993            return IsMatch(arr.GetAwaiterInvocation)
994              || (arr.GetResultMethod != null && findReferences.IsMemberMatch(method, arr.GetResultMethod, true))
995              || (arr.OnCompletedMethod != null && findReferences.IsMemberMatch(method, arr.OnCompletedMethod, true));
996          }
997        }
998        var mrr = rr as MemberResolveResult;
999        return mrr != null && findReferences.IsMemberMatch(method, mrr.Member, mrr.IsVirtualCall);
1000      }
1001     
1002      internal override void NavigatorDone(CSharpAstResolver resolver, CancellationToken cancellationToken)
1003      {
1004        foreach (var expr in potentialMethodGroupConversions) {
1005          var conversion = resolver.GetConversion(expr, cancellationToken);
1006          if (conversion.IsMethodGroupConversion && findReferences.IsMemberMatch(method, conversion.Method, conversion.IsVirtualMethodLookup)) {
1007            IType targetType = resolver.GetExpectedType(expr, cancellationToken);
1008            ResolveResult result = resolver.Resolve(expr, cancellationToken);
1009            ReportMatch(expr, new ConversionResolveResult(targetType, result, conversion));
1010          }
1011        }
1012        base.NavigatorDone(resolver, cancellationToken);
1013      }
1014    }
1015    #endregion
1016   
1017    #region Find Indexer References
1018    SearchScope FindIndexerReferences(IProperty indexer)
1019    {
1020      return new SearchScope(
1021        delegate (ICompilation compilation) {
1022          IProperty imported = compilation.Import(indexer);
1023          if (imported != null)
1024            return new FindIndexerReferencesNavigator(imported);
1025          else
1026            return null;
1027        });
1028    }
1029   
1030    sealed class FindIndexerReferencesNavigator : FindReferenceNavigator
1031    {
1032      readonly IProperty indexer;
1033     
1034      public FindIndexerReferencesNavigator(IProperty indexer)
1035      {
1036        this.indexer = indexer;
1037      }
1038     
1039      internal override bool CanMatch(AstNode node)
1040      {
1041        return node is IndexerExpression || node is IndexerDeclaration;
1042      }
1043     
1044      internal override bool IsMatch(ResolveResult rr)
1045      {
1046        MemberResolveResult mrr = rr as MemberResolveResult;
1047        return mrr != null && findReferences.IsMemberMatch(indexer, mrr.Member, mrr.IsVirtualCall);
1048      }
1049    }
1050    #endregion
1051   
1052    #region Find Operator References
1053    SearchScope GetSearchScopeForOperator(IMethod op)
1054    {
1055      OperatorType? opType = OperatorDeclaration.GetOperatorType(op.Name);
1056      if (opType == null)
1057        return GetSearchScopeForMethod(op);
1058      switch (opType.Value) {
1059        case OperatorType.LogicalNot:
1060          return FindUnaryOperator(op, UnaryOperatorType.Not);
1061        case OperatorType.OnesComplement:
1062          return FindUnaryOperator(op, UnaryOperatorType.BitNot);
1063        case OperatorType.UnaryPlus:
1064          return FindUnaryOperator(op, UnaryOperatorType.Plus);
1065        case OperatorType.UnaryNegation:
1066          return FindUnaryOperator(op, UnaryOperatorType.Minus);
1067        case OperatorType.Increment:
1068          return FindUnaryOperator(op, UnaryOperatorType.Increment);
1069        case OperatorType.Decrement:
1070          return FindUnaryOperator(op, UnaryOperatorType.Decrement);
1071        case OperatorType.True:
1072        case OperatorType.False:
1073          // TODO: implement search for op_True/op_False correctly
1074          return GetSearchScopeForMethod(op);
1075        case OperatorType.Addition:
1076          return FindBinaryOperator(op, BinaryOperatorType.Add);
1077        case OperatorType.Subtraction:
1078          return FindBinaryOperator(op, BinaryOperatorType.Subtract);
1079        case OperatorType.Multiply:
1080          return FindBinaryOperator(op, BinaryOperatorType.Multiply);
1081        case OperatorType.Division:
1082          return FindBinaryOperator(op, BinaryOperatorType.Divide);
1083        case OperatorType.Modulus:
1084          return FindBinaryOperator(op, BinaryOperatorType.Modulus);
1085        case OperatorType.BitwiseAnd:
1086          // TODO: an overloaded bitwise operator can also be called using the corresponding logical operator
1087          // (if op_True/op_False is defined)
1088          return FindBinaryOperator(op, BinaryOperatorType.BitwiseAnd);
1089        case OperatorType.BitwiseOr:
1090          return FindBinaryOperator(op, BinaryOperatorType.BitwiseOr);
1091        case OperatorType.ExclusiveOr:
1092          return FindBinaryOperator(op, BinaryOperatorType.ExclusiveOr);
1093        case OperatorType.LeftShift:
1094          return FindBinaryOperator(op, BinaryOperatorType.ShiftLeft);
1095        case OperatorType.RightShift:
1096          return FindBinaryOperator(op, BinaryOperatorType.ShiftRight);
1097        case OperatorType.Equality:
1098          return FindBinaryOperator(op, BinaryOperatorType.Equality);
1099        case OperatorType.Inequality:
1100          return FindBinaryOperator(op, BinaryOperatorType.InEquality);
1101        case OperatorType.GreaterThan:
1102          return FindBinaryOperator(op, BinaryOperatorType.GreaterThan);
1103        case OperatorType.LessThan:
1104          return FindBinaryOperator(op, BinaryOperatorType.LessThan);
1105        case OperatorType.GreaterThanOrEqual:
1106          return FindBinaryOperator(op, BinaryOperatorType.GreaterThanOrEqual);
1107        case OperatorType.LessThanOrEqual:
1108          return FindBinaryOperator(op, BinaryOperatorType.LessThanOrEqual);
1109        case OperatorType.Implicit:
1110          return FindOperator(op, m => new FindImplicitOperatorNavigator(m));
1111        case OperatorType.Explicit:
1112          return FindOperator(op, m => new FindExplicitOperatorNavigator(m));
1113        default:
1114          throw new InvalidOperationException("Invalid value for OperatorType");
1115      }
1116    }
1117   
1118    SearchScope FindOperator(IMethod op, Func<IMethod, FindReferenceNavigator> factory)
1119    {
1120      return new SearchScope(
1121        delegate (ICompilation compilation) {
1122          IMethod imported = compilation.Import(op);
1123          return imported != null ? factory(imported) : null;
1124        });
1125    }
1126   
1127    SearchScope FindUnaryOperator(IMethod op, UnaryOperatorType operatorType)
1128    {
1129      return FindOperator(op, m => new FindUnaryOperatorNavigator(m, operatorType));
1130    }
1131   
1132    sealed class FindUnaryOperatorNavigator : FindReferenceNavigator
1133    {
1134      readonly IMethod op;
1135      readonly UnaryOperatorType operatorType;
1136     
1137      public FindUnaryOperatorNavigator(IMethod op, UnaryOperatorType operatorType)
1138      {
1139        this.op = op;
1140        this.operatorType = operatorType;
1141      }
1142     
1143      internal override bool CanMatch(AstNode node)
1144      {
1145        UnaryOperatorExpression uoe = node as UnaryOperatorExpression;
1146        if (uoe != null) {
1147          if (operatorType == UnaryOperatorType.Increment)
1148            return uoe.Operator == UnaryOperatorType.Increment || uoe.Operator == UnaryOperatorType.PostIncrement;
1149          else if (operatorType == UnaryOperatorType.Decrement)
1150            return uoe.Operator == UnaryOperatorType.Decrement || uoe.Operator == UnaryOperatorType.PostDecrement;
1151          else
1152            return uoe.Operator == operatorType;
1153        }
1154        return node is OperatorDeclaration;
1155      }
1156     
1157      internal override bool IsMatch(ResolveResult rr)
1158      {
1159        MemberResolveResult mrr = rr as MemberResolveResult;
1160        return mrr != null && findReferences.IsMemberMatch(op, mrr.Member, mrr.IsVirtualCall);
1161      }
1162    }
1163   
1164    SearchScope FindBinaryOperator(IMethod op, BinaryOperatorType operatorType)
1165    {
1166      return FindOperator(op, m => new FindBinaryOperatorNavigator(m, operatorType));
1167    }
1168   
1169    sealed class FindBinaryOperatorNavigator : FindReferenceNavigator
1170    {
1171      readonly IMethod op;
1172      readonly BinaryOperatorType operatorType;
1173     
1174      public FindBinaryOperatorNavigator(IMethod op, BinaryOperatorType operatorType)
1175      {
1176        this.op = op;
1177        this.operatorType = operatorType;
1178      }
1179     
1180      internal override bool CanMatch(AstNode node)
1181      {
1182        BinaryOperatorExpression boe = node as BinaryOperatorExpression;
1183        if (boe != null) {
1184          return boe.Operator == operatorType;
1185        }
1186        return node is OperatorDeclaration;
1187      }
1188     
1189      internal override bool IsMatch(ResolveResult rr)
1190      {
1191        MemberResolveResult mrr = rr as MemberResolveResult;
1192        return mrr != null && findReferences.IsMemberMatch(op, mrr.Member, mrr.IsVirtualCall);
1193      }
1194    }
1195   
1196    sealed class FindImplicitOperatorNavigator : FindReferenceNavigator
1197    {
1198      readonly IMethod op;
1199     
1200      public FindImplicitOperatorNavigator(IMethod op)
1201      {
1202        this.op = op;
1203      }
1204     
1205      internal override bool CanMatch(AstNode node)
1206      {
1207        return true;
1208      }
1209     
1210      internal override bool IsMatch(ResolveResult rr)
1211      {
1212        MemberResolveResult mrr = rr as MemberResolveResult;
1213        return mrr != null && findReferences.IsMemberMatch(op, mrr.Member, mrr.IsVirtualCall);
1214      }
1215     
1216      public override void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
1217      {
1218        if (conversion.IsUserDefined && findReferences.IsMemberMatch(op, conversion.Method, conversion.IsVirtualMethodLookup)) {
1219          ReportMatch(expression, result);
1220        }
1221      }
1222    }
1223   
1224    sealed class FindExplicitOperatorNavigator : FindReferenceNavigator
1225    {
1226      readonly IMethod op;
1227     
1228      public FindExplicitOperatorNavigator(IMethod op)
1229      {
1230        this.op = op;
1231      }
1232     
1233      internal override bool CanMatch(AstNode node)
1234      {
1235        return node is CastExpression;
1236      }
1237     
1238      internal override bool IsMatch(ResolveResult rr)
1239      {
1240        ConversionResolveResult crr = rr as ConversionResolveResult;
1241        return crr != null && crr.Conversion.IsUserDefined
1242          && findReferences.IsMemberMatch(op, crr.Conversion.Method, crr.Conversion.IsVirtualMethodLookup);
1243      }
1244    }
1245    #endregion
1246   
1247    #region Find Constructor References
1248    SearchScope FindObjectCreateReferences(IMethod ctor)
1249    {
1250      string searchTerm = null;
1251      if (KnownTypeReference.GetCSharpNameByTypeCode(ctor.DeclaringTypeDefinition.KnownTypeCode) == null) {
1252        // not a built-in type
1253        searchTerm = ctor.DeclaringTypeDefinition.Name;
1254        if (searchTerm.Length > 9 && searchTerm.EndsWith("Attribute", StringComparison.Ordinal)) {
1255          // we also need to look for the short form
1256          searchTerm = null;
1257        }
1258      }
1259      return new SearchScope(
1260        searchTerm,
1261        delegate (ICompilation compilation) {
1262          IMethod imported = compilation.Import(ctor);
1263          if (imported != null)
1264            return new FindObjectCreateReferencesNavigator(imported);
1265          else
1266            return null;
1267        });
1268    }
1269   
1270    sealed class FindObjectCreateReferencesNavigator : FindReferenceNavigator
1271    {
1272      readonly IMethod ctor;
1273     
1274      public FindObjectCreateReferencesNavigator(IMethod ctor)
1275      {
1276        this.ctor = ctor;
1277      }
1278     
1279      internal override bool CanMatch(AstNode node)
1280      {
1281        return node is ObjectCreateExpression || node is ConstructorDeclaration || node is Attribute;
1282      }
1283     
1284      internal override bool IsMatch(ResolveResult rr)
1285      {
1286        MemberResolveResult mrr = rr as MemberResolveResult;
1287        return mrr != null && findReferences.IsMemberMatch(ctor, mrr.Member, mrr.IsVirtualCall);
1288      }
1289    }
1290   
1291    SearchScope FindChainedConstructorReferences(IMethod ctor)
1292    {
1293      SearchScope searchScope = new SearchScope(
1294        delegate (ICompilation compilation) {
1295          IMethod imported = compilation.Import(ctor);
1296          if (imported != null)
1297            return new FindChainedConstructorReferencesNavigator(imported);
1298          else
1299            return null;
1300        });
1301      if (ctor.DeclaringTypeDefinition.IsSealed)
1302        searchScope.accessibility = Accessibility.Private;
1303      else
1304        searchScope.accessibility = Accessibility.Protected;
1305      searchScope.accessibility = MergeAccessibility(GetEffectiveAccessibility(ctor), searchScope.accessibility);
1306      return searchScope;
1307    }
1308   
1309    sealed class FindChainedConstructorReferencesNavigator : FindReferenceNavigator
1310    {
1311      readonly IMethod ctor;
1312     
1313      public FindChainedConstructorReferencesNavigator(IMethod ctor)
1314      {
1315        this.ctor = ctor;
1316      }
1317     
1318      internal override bool CanMatch(AstNode node)
1319      {
1320        return node is ConstructorInitializer;
1321      }
1322     
1323      internal override bool IsMatch(ResolveResult rr)
1324      {
1325        MemberResolveResult mrr = rr as MemberResolveResult;
1326        return mrr != null && findReferences.IsMemberMatch(ctor, mrr.Member, mrr.IsVirtualCall);
1327      }
1328    }
1329    #endregion
1330   
1331    #region Find Destructor References
1332    SearchScope GetSearchScopeForDestructor(IMethod dtor)
1333    {
1334      var scope = new SearchScope (
1335        delegate (ICompilation compilation) {
1336          IMethod imported = compilation.Import(dtor);
1337          if (imported != null) {
1338            return new FindDestructorReferencesNavigator (imported);
1339          } else {
1340            return null;
1341          }
1342        });
1343      scope.accessibility = Accessibility.Private;
1344      return scope;
1345    }
1346   
1347    sealed class FindDestructorReferencesNavigator : FindReferenceNavigator
1348    {
1349      readonly IMethod dtor;
1350     
1351      public FindDestructorReferencesNavigator (IMethod dtor)
1352      {
1353        this.dtor = dtor;
1354      }
1355     
1356      internal override bool CanMatch(AstNode node)
1357      {
1358        return node is DestructorDeclaration;
1359      }
1360     
1361      internal override bool IsMatch(ResolveResult rr)
1362      {
1363        MemberResolveResult mrr = rr as MemberResolveResult;
1364        return mrr != null && findReferences.IsMemberMatch(dtor, mrr.Member, mrr.IsVirtualCall);
1365      }
1366    }
1367    #endregion
1368
1369    #region Find Local Variable References
1370    /// <summary>
1371    /// Finds all references of a given variable.
1372    /// </summary>
1373    /// <param name="variable">The variable for which to look.</param>
1374    /// <param name="unresolvedFile">The type system representation of the file being searched.</param>
1375    /// <param name="syntaxTree">The syntax tree of the file being searched.</param>
1376    /// <param name="compilation">The compilation.</param>
1377    /// <param name="callback">Callback used to report the references that were found.</param>
1378    /// <param name="cancellationToken">Cancellation token that may be used to cancel the operation.</param>
1379    public void FindLocalReferences(IVariable variable, CSharpUnresolvedFile unresolvedFile, SyntaxTree syntaxTree,
1380                                    ICompilation compilation, FoundReferenceCallback callback, CancellationToken cancellationToken)
1381    {
1382      if (variable == null)
1383        throw new ArgumentNullException("variable");
1384      var searchScope = new SearchScope(c => new FindLocalReferencesNavigator(variable));
1385      searchScope.declarationCompilation = compilation;
1386      FindReferencesInFile(searchScope, unresolvedFile, syntaxTree, compilation, callback, cancellationToken);
1387    }
1388   
1389    SearchScope GetSearchScopeForLocalVariable(IVariable variable)
1390    {
1391      var scope = new SearchScope (
1392        delegate {
1393          return new FindLocalReferencesNavigator(variable);
1394        }
1395      );
1396      scope.fileName = variable.Region.FileName;
1397      return scope;
1398    }
1399   
1400    class FindLocalReferencesNavigator : FindReferenceNavigator
1401    {
1402      readonly IVariable variable;
1403     
1404      public FindLocalReferencesNavigator(IVariable variable)
1405      {
1406        this.variable = variable;
1407      }
1408     
1409      internal override bool CanMatch(AstNode node)
1410      {
1411        var expr = node as IdentifierExpression;
1412        if (expr != null)
1413          return expr.TypeArguments.Count == 0 && variable.Name == expr.Identifier;
1414        var vi = node as VariableInitializer;
1415        if (vi != null)
1416          return vi.Name == variable.Name;
1417        var pd = node as ParameterDeclaration;
1418        if (pd != null)
1419          return pd.Name == variable.Name;
1420        var id = node as Identifier;
1421        if (id != null)
1422          return id.Name == variable.Name;
1423        return false;
1424      }
1425     
1426      internal override bool IsMatch(ResolveResult rr)
1427      {
1428        var lrr = rr as LocalResolveResult;
1429        return lrr != null && lrr.Variable.Name == variable.Name && lrr.Variable.Region == variable.Region;
1430      }
1431    }
1432    #endregion
1433
1434    #region Find Type Parameter References
1435    /// <summary>
1436    /// Finds all references of a given type parameter.
1437    /// </summary>
1438    /// <param name="typeParameter">The type parameter for which to look.</param>
1439    /// <param name="unresolvedFile">The type system representation of the file being searched.</param>
1440    /// <param name="syntaxTree">The syntax tree of the file being searched.</param>
1441    /// <param name="compilation">The compilation.</param>
1442    /// <param name="callback">Callback used to report the references that were found.</param>
1443    /// <param name="cancellationToken">Cancellation token that may be used to cancel the operation.</param>
1444    [Obsolete("Use GetSearchScopes(typeParameter) instead")]
1445    public void FindTypeParameterReferences(IType typeParameter, CSharpUnresolvedFile unresolvedFile, SyntaxTree syntaxTree,
1446                                            ICompilation compilation, FoundReferenceCallback callback, CancellationToken cancellationToken)
1447    {
1448      if (typeParameter == null)
1449        throw new ArgumentNullException("typeParameter");
1450      if (typeParameter.Kind != TypeKind.TypeParameter)
1451        throw new ArgumentOutOfRangeException("typeParameter", "Only type parameters are allowed");
1452      var searchScope = new SearchScope(c => new FindTypeParameterReferencesNavigator((ITypeParameter)typeParameter));
1453      searchScope.declarationCompilation = compilation;
1454      searchScope.accessibility = Accessibility.Private;
1455      FindReferencesInFile(searchScope, unresolvedFile, syntaxTree, compilation, callback, cancellationToken);
1456    }
1457   
1458    SearchScope GetSearchScopeForTypeParameter(ITypeParameter tp)
1459    {
1460      var searchScope = new SearchScope(c => new FindTypeParameterReferencesNavigator(tp));
1461      var compilationProvider = tp as ICompilationProvider;
1462      if (compilationProvider != null)
1463        searchScope.declarationCompilation = compilationProvider.Compilation;
1464      searchScope.topLevelTypeDefinition = GetTopLevelTypeDefinition(tp.Owner);
1465      searchScope.accessibility = Accessibility.Private;
1466      return searchScope;
1467    }
1468
1469    class FindTypeParameterReferencesNavigator : FindReferenceNavigator
1470    {
1471      readonly ITypeParameter typeParameter;
1472     
1473      public FindTypeParameterReferencesNavigator(ITypeParameter typeParameter)
1474      {
1475        this.typeParameter = typeParameter;
1476      }
1477     
1478      internal override bool CanMatch(AstNode node)
1479      {
1480        var type = node as SimpleType;
1481        if (type != null)
1482          return type.Identifier == typeParameter.Name;
1483        var declaration = node as TypeParameterDeclaration;
1484        if (declaration != null)
1485          return declaration.Name == typeParameter.Name;
1486        return false;
1487      }
1488     
1489      internal override bool IsMatch(ResolveResult rr)
1490      {
1491        var lrr = rr as TypeResolveResult;
1492        return lrr != null && lrr.Type.Kind == TypeKind.TypeParameter && ((ITypeParameter)lrr.Type).Region == typeParameter.Region;
1493      }
1494    }
1495    #endregion
1496   
1497    #region Find Namespace References
1498    SearchScope GetSearchScopeForNamespace(INamespace ns)
1499    {
1500      var scope = new SearchScope (
1501        delegate (ICompilation compilation) {
1502          return new FindNamespaceNavigator (ns);
1503        }
1504      );
1505      return scope;
1506    }
1507
1508    sealed class FindNamespaceNavigator : FindReferenceNavigator
1509    {
1510      readonly INamespace ns;
1511
1512      public FindNamespaceNavigator (INamespace ns)
1513      {
1514        this.ns = ns;
1515      }
1516
1517      internal override bool CanMatch(AstNode node)
1518      {
1519        var nsd = node as NamespaceDeclaration;
1520        if (nsd != null && nsd.FullName.StartsWith(ns.FullName, StringComparison.Ordinal))
1521          return true;
1522
1523        var ud = node as UsingDeclaration;
1524        if (ud != null && ud.Namespace == ns.FullName)
1525          return true;
1526
1527        var st = node as SimpleType;
1528        if (st != null && st.Identifier == ns.Name)
1529          return !st.AncestorsAndSelf.TakeWhile (n => n is AstType).Any (m => m.Role == NamespaceDeclaration.NamespaceNameRole);
1530
1531        var mt = node as MemberType;
1532        if (mt != null && mt.MemberName == ns.Name)
1533          return !mt.AncestorsAndSelf.TakeWhile (n => n is AstType).Any (m => m.Role == NamespaceDeclaration.NamespaceNameRole);
1534
1535        var identifer = node as IdentifierExpression;
1536        if (identifer != null && identifer.Identifier == ns.Name)
1537          return true;
1538
1539        var mrr = node as MemberReferenceExpression;
1540        if (mrr != null && mrr.MemberName == ns.Name)
1541          return true;
1542
1543
1544        return false;
1545      }
1546
1547      internal override bool IsMatch(ResolveResult rr)
1548      {
1549        var nsrr = rr as NamespaceResolveResult;
1550        return nsrr != null && nsrr.NamespaceName.StartsWith(ns.FullName, StringComparison.Ordinal);
1551      }
1552    }
1553    #endregion
1554   
1555    #region Find Parameter References
1556
1557    SearchScope GetSearchScopeForParameter(IParameter parameter)
1558    {
1559      var scope = new SearchScope (
1560        delegate {
1561          return new FindParameterReferencesNavigator (parameter);
1562        }
1563      );
1564      if (parameter.Owner == null) {
1565        scope.fileName = parameter.Region.FileName;
1566      }
1567      return scope;
1568    }
1569
1570    class FindParameterReferencesNavigator : FindReferenceNavigator
1571    {
1572      readonly IParameter parameter;
1573
1574      public FindParameterReferencesNavigator(IParameter parameter)
1575      {
1576        this.parameter = parameter;
1577      }
1578
1579      internal override bool CanMatch(AstNode node)
1580      {
1581        var expr = node as IdentifierExpression;
1582        if (expr != null)
1583          return expr.TypeArguments.Count == 0 && parameter.Name == expr.Identifier;
1584        var vi = node as VariableInitializer;
1585        if (vi != null)
1586          return vi.Name == parameter.Name;
1587        var pd = node as ParameterDeclaration;
1588        if (pd != null)
1589          return pd.Name == parameter.Name;
1590        var id = node as Identifier;
1591        if (id != null)
1592          return id.Name == parameter.Name;
1593        var nae = node as NamedArgumentExpression;
1594        if (nae != null)
1595          return nae.Name == parameter.Name;
1596        return false;
1597      }
1598
1599      internal override bool IsMatch(ResolveResult rr)
1600      {
1601        var lrr = rr as LocalResolveResult;
1602        if (lrr != null)
1603          return lrr.Variable.Name == parameter.Name && lrr.Variable.Region == parameter.Region;
1604
1605        var nar = rr as NamedArgumentResolveResult;
1606        return nar != null && nar.Parameter.Name == parameter.Name && nar.Parameter.Region == parameter.Region;
1607      }
1608    }
1609    #endregion
1610  }
1611}
Note: See TracBrowser for help on using the repository browser.