1
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
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:
9
// The above copyright notice and this permission notice shall be included in all copies or
10
// substantial portions of the Software.
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.
20
using System.Collections.Generic;
21
using System.Diagnostics;
23
using System.Threading;
24
using ICSharpCode.NRefactory.CSharp.Refactoring;
25
using ICSharpCode.NRefactory.CSharp.TypeSystem;
26
using ICSharpCode.NRefactory.Semantics;
27
using ICSharpCode.NRefactory.TypeSystem;
28
using ICSharpCode.NRefactory.Utils;
30
namespace ICSharpCode.NRefactory.CSharp.Resolver
32
public delegate void FoundReferenceCallback(AstNode astNode, ResolveResult result);
35
/// 'Find references' implementation.
38
/// This class is thread-safe.
39
/// The intended multi-threaded usage is to call GetSearchScopes() once, and then
40
/// call FindReferencesInFile() concurrently on multiple threads (parallel foreach over all interesting files).
42
public sealed class FindReferences
46
/// Specifies whether to find type references even if an alias is being used.
47
/// Aliases may be <c>var</c> or <c>using Alias = ...;</c>.
49
public bool FindTypeReferencesEvenIfAliased { get; set; }
52
/// Specifies whether find references should only look for specialized matches
53
/// with equal type parameter substitution to the member we are searching for.
55
public bool FindOnlySpecializedReferences { get; set; }
58
/// If this option is enabled, find references on a overridden member
59
/// will find calls to the base member.
61
public bool FindCallsThroughVirtualBaseMethod { get; set; }
64
/// If this option is enabled, find references on a member implementing
65
/// an interface will also find calls to the interface.
67
public bool FindCallsThroughInterface { get; set; }
70
/// If this option is enabled, find references will look for all references
71
/// to the virtual method slot.
73
public bool WholeVirtualSlot { get; set; }
76
/// Specifies whether to look for references in documentation comments.
77
/// This will find entity references in <c>cref</c> attributes and
78
/// parameter references in <c><param></c> and <c><paramref></c> tags.
79
/// TODO: implement this feature.
81
public bool SearchInDocumentationComments { get; set; }
84
#region GetEffectiveAccessibility
86
/// Gets the effective accessibility of the specified entity -
87
/// that is, the accessibility viewed from the top level.
90
/// internal member in public class -> internal
91
/// public member in internal class -> internal
92
/// protected member in public class -> protected
93
/// protected member in internal class -> protected and internal
95
public static Accessibility GetEffectiveAccessibility(IEntity entity)
98
throw new ArgumentNullException("entity");
99
Accessibility a = entity.Accessibility;
100
for (ITypeDefinition declType = entity.DeclaringTypeDefinition; declType != null; declType = declType.DeclaringTypeDefinition) {
101
a = MergeAccessibility(declType.Accessibility, a);
106
static Accessibility MergeAccessibility(Accessibility outer, Accessibility inner)
110
if (outer == Accessibility.None || inner == Accessibility.None)
111
return Accessibility.None;
112
if (outer == Accessibility.Private || inner == Accessibility.Private)
113
return Accessibility.Private;
114
if (outer == Accessibility.Public)
116
if (inner == Accessibility.Public)
118
// Inner and outer are both in { protected, internal, protected and internal, protected or internal }
119
// (but they aren't both the same)
120
if (outer == Accessibility.ProtectedOrInternal)
122
if (inner == Accessibility.ProtectedOrInternal)
124
// Inner and outer are both in { protected, internal, protected and internal },
125
// but aren't both the same, so the result is protected and internal.
126
return Accessibility.ProtectedAndInternal;
130
#region class SearchScope
131
sealed class SearchScope : IFindReferenceSearchScope
133
readonly Func<ICompilation, FindReferenceNavigator> factory;
135
public SearchScope(Func<ICompilation, FindReferenceNavigator> factory)
137
this.factory = factory;
140
public SearchScope(string searchTerm, Func<ICompilation, FindReferenceNavigator> factory)
142
this.searchTerm = searchTerm;
143
this.factory = factory;
146
internal string searchTerm;
147
internal FindReferences findReferences;
148
internal ICompilation declarationCompilation;
149
internal Accessibility accessibility;
150
internal ITypeDefinition topLevelTypeDefinition;
152
IResolveVisitorNavigator IFindReferenceSearchScope.GetNavigator(ICompilation compilation, FoundReferenceCallback callback)
154
FindReferenceNavigator n = factory(compilation);
156
n.callback = callback;
157
n.findReferences = findReferences;
160
return new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Skip, null);
164
ICompilation IFindReferenceSearchScope.Compilation {
165
get { return declarationCompilation; }
168
string IFindReferenceSearchScope.SearchTerm {
169
get { return searchTerm; }
172
Accessibility IFindReferenceSearchScope.Accessibility {
173
get { return accessibility; }
176
ITypeDefinition IFindReferenceSearchScope.TopLevelTypeDefinition {
177
get { return topLevelTypeDefinition; }
181
abstract class FindReferenceNavigator : IResolveVisitorNavigator
183
internal FoundReferenceCallback callback;
184
internal FindReferences findReferences;
186
internal abstract bool CanMatch(AstNode node);
187
internal abstract bool IsMatch(ResolveResult rr);
189
ResolveVisitorNavigationMode IResolveVisitorNavigator.Scan(AstNode node)
192
return ResolveVisitorNavigationMode.Resolve;
194
return ResolveVisitorNavigationMode.Scan;
197
void IResolveVisitorNavigator.Resolved(AstNode node, ResolveResult result)
199
if (CanMatch(node) && IsMatch(result)) {
200
ReportMatch(node, result);
204
public virtual void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
208
protected void ReportMatch(AstNode node, ResolveResult result)
210
if (callback != null)
211
callback(node, result);
214
internal virtual void NavigatorDone(CSharpAstResolver resolver, CancellationToken cancellationToken)
220
#region GetSearchScopes
221
public IList<IFindReferenceSearchScope> GetSearchScopes(IEntity entity)
224
throw new ArgumentNullException("entity");
225
if (entity is IMember)
226
entity = NormalizeMember((IMember)entity);
227
Accessibility effectiveAccessibility = GetEffectiveAccessibility(entity);
228
ITypeDefinition topLevelTypeDefinition = entity.DeclaringTypeDefinition;
229
while (topLevelTypeDefinition != null && topLevelTypeDefinition.DeclaringTypeDefinition != null)
230
topLevelTypeDefinition = topLevelTypeDefinition.DeclaringTypeDefinition;
232
SearchScope additionalScope = null;
233
switch (entity.EntityType) {
234
case EntityType.TypeDefinition:
235
scope = FindTypeDefinitionReferences((ITypeDefinition)entity, this.FindTypeReferencesEvenIfAliased, out additionalScope);
237
case EntityType.Field:
238
if (entity.DeclaringTypeDefinition != null && entity.DeclaringTypeDefinition.Kind == TypeKind.Enum)
239
scope = FindMemberReferences(entity, m => new FindEnumMemberReferences((IField)m));
241
scope = FindMemberReferences(entity, m => new FindFieldReferences((IField)m));
243
case EntityType.Property:
244
scope = FindMemberReferences(entity, m => new FindPropertyReferences((IProperty)m));
245
if (entity.Name == "Current")
246
additionalScope = FindEnumeratorCurrentReferences((IProperty)entity);
247
else if (entity.Name == "IsCompleted")
248
additionalScope = FindAwaiterIsCompletedReferences((IProperty)entity);
250
case EntityType.Event:
251
scope = FindMemberReferences(entity, m => new FindEventReferences((IEvent)m));
253
case EntityType.Method:
254
scope = GetSearchScopeForMethod((IMethod)entity);
256
case EntityType.Indexer:
257
scope = FindIndexerReferences((IProperty)entity);
259
case EntityType.Operator:
260
scope = GetSearchScopeForOperator((IMethod)entity);
262
case EntityType.Constructor:
263
IMethod ctor = (IMethod)entity;
264
scope = FindObjectCreateReferences(ctor);
265
additionalScope = FindChainedConstructorReferences(ctor);
267
case EntityType.Destructor:
268
scope = GetSearchScopeForDestructor((IMethod)entity);
271
throw new ArgumentException("Unknown entity type " + entity.EntityType);
273
if (scope.accessibility == Accessibility.None)
274
scope.accessibility = effectiveAccessibility;
275
scope.declarationCompilation = entity.Compilation;
276
scope.topLevelTypeDefinition = topLevelTypeDefinition;
277
scope.findReferences = this;
278
if (additionalScope != null) {
279
if (additionalScope.accessibility == Accessibility.None)
280
additionalScope.accessibility = effectiveAccessibility;
281
additionalScope.declarationCompilation = entity.Compilation;
282
additionalScope.topLevelTypeDefinition = topLevelTypeDefinition;
283
additionalScope.findReferences = this;
284
return new[] { scope, additionalScope };
286
return new[] { scope };
290
public IList<IFindReferenceSearchScope> GetSearchScopes(INamespace ns)
293
throw new ArgumentNullException("ns");
294
return new[] { GetSearchScopeForNamespace(ns) };
299
#region GetInterestingFileNames
301
/// Gets the file names that possibly contain references to the element being searched for.
303
public IEnumerable<CSharpUnresolvedFile> GetInterestingFiles(IFindReferenceSearchScope searchScope, ICompilation compilation)
305
if (searchScope == null)
306
throw new ArgumentNullException("searchScope");
307
if (compilation == null)
308
throw new ArgumentNullException("compilation");
309
var pc = compilation.MainAssembly.UnresolvedAssembly as IProjectContent;
311
throw new ArgumentException("Main assembly is not a project content");
312
if (searchScope.TopLevelTypeDefinition != null) {
313
ITypeDefinition topLevelTypeDef = compilation.Import(searchScope.TopLevelTypeDefinition);
314
if (topLevelTypeDef == null) {
315
// This compilation cannot have references to the target entity.
316
return EmptyList<CSharpUnresolvedFile>.Instance;
318
switch (searchScope.Accessibility) {
319
case Accessibility.None:
320
case Accessibility.Private:
321
if (topLevelTypeDef.ParentAssembly == compilation.MainAssembly)
322
return topLevelTypeDef.Parts.Select(p => p.UnresolvedFile).OfType<CSharpUnresolvedFile>().Distinct();
324
return EmptyList<CSharpUnresolvedFile>.Instance;
325
case Accessibility.Protected:
326
return GetInterestingFilesProtected(topLevelTypeDef);
327
case Accessibility.Internal:
328
if (topLevelTypeDef.ParentAssembly.InternalsVisibleTo(compilation.MainAssembly))
329
return pc.Files.OfType<CSharpUnresolvedFile>();
331
return EmptyList<CSharpUnresolvedFile>.Instance;
332
case Accessibility.ProtectedAndInternal:
333
if (topLevelTypeDef.ParentAssembly.InternalsVisibleTo(compilation.MainAssembly))
334
return GetInterestingFilesProtected(topLevelTypeDef);
336
return EmptyList<CSharpUnresolvedFile>.Instance;
337
case Accessibility.ProtectedOrInternal:
338
if (topLevelTypeDef.ParentAssembly.InternalsVisibleTo(compilation.MainAssembly))
339
return pc.Files.OfType<CSharpUnresolvedFile>();
341
return GetInterestingFilesProtected(topLevelTypeDef);
343
return pc.Files.OfType<CSharpUnresolvedFile>();
346
return pc.Files.OfType<CSharpUnresolvedFile>();
350
IEnumerable<CSharpUnresolvedFile> GetInterestingFilesProtected(ITypeDefinition referencedTypeDefinition)
352
return (from typeDef in referencedTypeDefinition.Compilation.MainAssembly.GetAllTypeDefinitions()
353
where typeDef.IsDerivedFrom(referencedTypeDefinition)
354
from part in typeDef.Parts
355
select part.UnresolvedFile
356
).OfType<CSharpUnresolvedFile>().Distinct();
360
#region FindReferencesInFile
362
/// Finds all references in the given file.
364
/// <param name="searchScope">The search scope for which to look.</param>
365
/// <param name="unresolvedFile">The type system representation of the file being searched.</param>
366
/// <param name="syntaxTree">The syntax tree of the file being searched.</param>
367
/// <param name="compilation">The compilation for the project that contains the file.</param>
368
/// <param name="callback">Callback used to report the references that were found.</param>
369
/// <param name="cancellationToken">CancellationToken that may be used to cancel the operation.</param>
370
public void FindReferencesInFile(IFindReferenceSearchScope searchScope, CSharpUnresolvedFile unresolvedFile, SyntaxTree syntaxTree,
371
ICompilation compilation, FoundReferenceCallback callback, CancellationToken cancellationToken)
373
if (searchScope == null)
374
throw new ArgumentNullException("searchScope");
375
FindReferencesInFile(new[] { searchScope }, unresolvedFile, syntaxTree, compilation, callback, cancellationToken);
379
/// Finds all references in the given file.
381
/// <param name="searchScopes">The search scopes for which to look.</param>
382
/// <param name="unresolvedFile">The type system representation of the file being searched.</param>
383
/// <param name="syntaxTree">The syntax tree of the file being searched.</param>
384
/// <param name="compilation">The compilation for the project that contains the file.</param>
385
/// <param name="callback">Callback used to report the references that were found.</param>
386
/// <param name="cancellationToken">CancellationToken that may be used to cancel the operation.</param>
387
public void FindReferencesInFile(IList<IFindReferenceSearchScope> searchScopes, CSharpUnresolvedFile unresolvedFile, SyntaxTree syntaxTree,
388
ICompilation compilation, FoundReferenceCallback callback, CancellationToken cancellationToken)
390
if (searchScopes == null)
391
throw new ArgumentNullException("searchScopes");
392
if (syntaxTree == null)
393
throw new ArgumentNullException("syntaxTree");
394
if (compilation == null)
395
throw new ArgumentNullException("compilation");
396
if (callback == null)
397
throw new ArgumentNullException("callback");
399
if (searchScopes.Count == 0)
401
var navigators = new IResolveVisitorNavigator[searchScopes.Count];
402
for (int i = 0; i < navigators.Length; i++) {
403
navigators[i] = searchScopes[i].GetNavigator(compilation, callback);
405
IResolveVisitorNavigator combinedNavigator;
406
if (searchScopes.Count == 1) {
407
combinedNavigator = navigators[0];
409
combinedNavigator = new CompositeResolveVisitorNavigator(navigators);
412
cancellationToken.ThrowIfCancellationRequested();
413
combinedNavigator = new DetectSkippableNodesNavigator(combinedNavigator, syntaxTree);
414
cancellationToken.ThrowIfCancellationRequested();
415
CSharpAstResolver resolver = new CSharpAstResolver(compilation, syntaxTree, unresolvedFile);
416
resolver.ApplyNavigator(combinedNavigator, cancellationToken);
417
foreach (var n in navigators) {
418
var frn = n as FindReferenceNavigator;
420
frn.NavigatorDone(resolver, cancellationToken);
425
#region Find TypeDefinition References
426
SearchScope FindTypeDefinitionReferences(ITypeDefinition typeDefinition, bool findTypeReferencesEvenIfAliased, out SearchScope additionalScope)
428
string searchTerm = null;
429
additionalScope = null;
430
if (!findTypeReferencesEvenIfAliased && KnownTypeReference.GetCSharpNameByTypeCode(typeDefinition.KnownTypeCode) == null) {
431
// We can optimize the search by looking only for the type references with the right identifier,
432
// but only if it's not a primitive type and we're not looking for indirect references (through an alias)
433
searchTerm = typeDefinition.Name;
434
if (searchTerm.Length > 9 && searchTerm.EndsWith("Attribute", StringComparison.Ordinal)) {
435
// The type might be an attribute, so we also need to look for the short form:
436
string shortForm = searchTerm.Substring(0, searchTerm.Length - 9);
437
additionalScope = FindTypeDefinitionReferences(typeDefinition, shortForm);
440
return FindTypeDefinitionReferences(typeDefinition, searchTerm);
443
SearchScope FindTypeDefinitionReferences(ITypeDefinition typeDefinition, string searchTerm)
445
return new SearchScope(
447
delegate (ICompilation compilation) {
448
ITypeDefinition imported = compilation.Import(typeDefinition);
449
if (imported != null)
450
return new FindTypeDefinitionReferencesNavigator(imported, searchTerm);
456
sealed class FindTypeDefinitionReferencesNavigator : FindReferenceNavigator
458
readonly ITypeDefinition typeDefinition;
459
readonly string searchTerm;
461
public FindTypeDefinitionReferencesNavigator(ITypeDefinition typeDefinition, string searchTerm)
463
this.typeDefinition = typeDefinition;
464
this.searchTerm = searchTerm;
467
internal override bool CanMatch(AstNode node)
469
IdentifierExpression ident = node as IdentifierExpression;
471
return searchTerm == null || ident.Identifier == searchTerm;
473
MemberReferenceExpression mre = node as MemberReferenceExpression;
475
return searchTerm == null || mre.MemberName == searchTerm;
477
SimpleType st = node as SimpleType;
479
return searchTerm == null || st.Identifier == searchTerm;
481
MemberType mt = node as MemberType;
483
return searchTerm == null || mt.MemberName == searchTerm;
485
if (searchTerm == null && node is PrimitiveType)
488
TypeDeclaration typeDecl = node as TypeDeclaration;
489
if (typeDecl != null)
490
return searchTerm == null || typeDecl.Name == searchTerm;
492
DelegateDeclaration delegateDecl = node as DelegateDeclaration;
493
if (delegateDecl != null)
494
return searchTerm == null || delegateDecl.Name == searchTerm;
499
internal override bool IsMatch(ResolveResult rr)
501
TypeResolveResult trr = rr as TypeResolveResult;
502
return trr != null && typeDefinition.Equals(trr.Type.GetDefinition());
507
#region Find Member References
508
SearchScope FindMemberReferences(IEntity member, Func<IMember, FindMemberReferencesNavigator> factory)
510
string searchTerm = member.Name;
511
return new SearchScope(
513
delegate(ICompilation compilation) {
514
IMember imported = compilation.Import((IMember)member);
515
return imported != null ? factory(imported) : null;
519
class FindMemberReferencesNavigator : FindReferenceNavigator
521
readonly IMember member;
522
readonly string searchTerm;
524
public FindMemberReferencesNavigator(IMember member)
526
this.member = member;
527
this.searchTerm = member.Name;
530
internal override bool CanMatch(AstNode node)
532
IdentifierExpression ident = node as IdentifierExpression;
534
return ident.Identifier == searchTerm;
536
MemberReferenceExpression mre = node as MemberReferenceExpression;
538
return mre.MemberName == searchTerm;
540
PointerReferenceExpression pre = node as PointerReferenceExpression;
542
return pre.MemberName == searchTerm;
544
NamedExpression ne = node as NamedExpression;
546
return ne.Name == searchTerm;
551
internal override bool IsMatch(ResolveResult rr)
553
MemberResolveResult mrr = rr as MemberResolveResult;
554
return mrr != null && findReferences.IsMemberMatch(member, mrr.Member, mrr.IsVirtualCall);
558
IMember NormalizeMember(IMember member)
560
if (WholeVirtualSlot && member.IsOverride)
561
member = InheritanceHelper.GetBaseMembers(member, false).FirstOrDefault(m => !m.IsOverride) ?? member;
562
if (!FindOnlySpecializedReferences)
563
member = member.MemberDefinition;
567
bool IsMemberMatch(IMember member, IMember referencedMember, bool isVirtualCall)
569
referencedMember = NormalizeMember(referencedMember);
570
if (member.Equals(referencedMember))
574
bool isInterfaceCall = referencedMember.DeclaringTypeDefinition != null && referencedMember.DeclaringTypeDefinition.Kind == TypeKind.Interface;
575
if (FindCallsThroughVirtualBaseMethod && member.IsOverride && !WholeVirtualSlot && !isInterfaceCall) {
576
// Test if 'member' overrides 'referencedMember':
577
foreach (var baseMember in InheritanceHelper.GetBaseMembers(member, false)) {
578
if (FindOnlySpecializedReferences) {
579
if (baseMember.Equals(referencedMember))
582
if (baseMember.MemberDefinition.Equals(referencedMember))
585
if (!baseMember.IsOverride)
589
} else if (FindCallsThroughInterface && isInterfaceCall) {
590
// Test if 'member' implements 'referencedMember':
591
if (FindOnlySpecializedReferences) {
592
return member.ImplementedInterfaceMembers.Contains(referencedMember);
594
return member.ImplementedInterfaceMembers.Any(m => m.MemberDefinition.Equals(referencedMember));
600
bool PerformVirtualLookup(IMember member, IMember referencedMember)
602
if (FindCallsThroughVirtualBaseMethod && member.IsOverride && !WholeVirtualSlot)
604
var typeDef = referencedMember.DeclaringTypeDefinition;
605
return FindCallsThroughInterface && typeDef != null && typeDef.Kind == TypeKind.Interface;
608
sealed class FindFieldReferences : FindMemberReferencesNavigator
610
public FindFieldReferences(IField field) : base(field)
614
internal override bool CanMatch(AstNode node)
616
if (node is VariableInitializer) {
617
return node.Parent is FieldDeclaration;
619
return base.CanMatch(node);
623
sealed class FindEnumMemberReferences : FindMemberReferencesNavigator
625
public FindEnumMemberReferences(IField field) : base(field)
629
internal override bool CanMatch(AstNode node)
631
return node is EnumMemberDeclaration || base.CanMatch(node);
635
sealed class FindPropertyReferences : FindMemberReferencesNavigator
637
public FindPropertyReferences(IProperty property) : base(property)
641
internal override bool CanMatch(AstNode node)
643
return node is PropertyDeclaration || base.CanMatch(node);
647
sealed class FindEventReferences : FindMemberReferencesNavigator
649
public FindEventReferences(IEvent ev) : base(ev)
653
internal override bool CanMatch(AstNode node)
655
if (node is VariableInitializer) {
656
return node.Parent is EventDeclaration;
658
return node is CustomEventDeclaration || base.CanMatch(node);
663
#region Find References to IEnumerator.Current
664
SearchScope FindEnumeratorCurrentReferences(IProperty property)
666
return new SearchScope(
667
delegate(ICompilation compilation) {
668
IProperty imported = compilation.Import(property);
669
return imported != null ? new FindEnumeratorCurrentReferencesNavigator(imported) : null;
673
SearchScope FindAwaiterIsCompletedReferences(IProperty property)
675
return new SearchScope(
676
delegate(ICompilation compilation) {
677
IProperty imported = compilation.Import(property);
678
return imported != null ? new FindAwaiterIsCompletedReferencesNavigator(imported) : null;
682
sealed class FindEnumeratorCurrentReferencesNavigator : FindReferenceNavigator
686
public FindEnumeratorCurrentReferencesNavigator(IProperty property)
688
this.property = property;
691
internal override bool CanMatch(AstNode node)
693
return node is ForeachStatement;
696
internal override bool IsMatch(ResolveResult rr)
698
ForEachResolveResult ferr = rr as ForEachResolveResult;
699
return ferr != null && ferr.CurrentProperty != null && findReferences.IsMemberMatch(property, ferr.CurrentProperty, true);
703
sealed class FindAwaiterIsCompletedReferencesNavigator : FindReferenceNavigator
707
public FindAwaiterIsCompletedReferencesNavigator(IProperty property)
709
this.property = property;
712
internal override bool CanMatch(AstNode node)
714
return node is UnaryOperatorExpression;
717
internal override bool IsMatch(ResolveResult rr)
719
AwaitResolveResult arr = rr as AwaitResolveResult;
720
return arr != null && arr.IsCompletedProperty != null && findReferences.IsMemberMatch(property, arr.IsCompletedProperty, true);
725
#region Find Method References
726
SearchScope GetSearchScopeForMethod(IMethod method)
728
Type specialNodeType;
729
switch (method.Name) {
731
specialNodeType = typeof(ArrayInitializerExpression);
734
specialNodeType = typeof(QueryWhereClause);
737
specialNodeType = typeof(QuerySelectClause);
740
specialNodeType = typeof(QueryFromClause);
744
specialNodeType = typeof(QueryJoinClause);
747
case "OrderByDescending":
749
case "ThenByDescending":
750
specialNodeType = typeof(QueryOrdering);
753
specialNodeType = typeof(QueryGroupClause);
756
if (method.DeclaringTypeDefinition != null && method.DeclaringTypeDefinition.Kind == TypeKind.Delegate)
757
specialNodeType = typeof(InvocationExpression);
759
specialNodeType = null;
761
case "GetEnumerator":
763
specialNodeType = typeof(ForeachStatement);
768
case "UnsafeOnCompleted":
769
specialNodeType = typeof(UnaryOperatorExpression);
772
specialNodeType = null;
775
// Use searchTerm only if specialNodeType==null
776
string searchTerm = (specialNodeType == null) ? method.Name : null;
777
return new SearchScope(
779
delegate (ICompilation compilation) {
780
IMethod imported = compilation.Import(method);
781
if (imported != null)
782
return new FindMethodReferences(imported, specialNodeType);
788
sealed class FindMethodReferences : FindReferenceNavigator
790
readonly IMethod method;
791
readonly Type specialNodeType;
792
HashSet<Expression> potentialMethodGroupConversions = new HashSet<Expression>();
794
public FindMethodReferences(IMethod method, Type specialNodeType)
796
this.method = method;
797
this.specialNodeType = specialNodeType;
800
internal override bool CanMatch(AstNode node)
802
if (specialNodeType != null && node.GetType() == specialNodeType)
805
Expression expr = node as Expression;
807
return node is MethodDeclaration;
809
InvocationExpression ie = node as InvocationExpression;
811
Expression target = ParenthesizedExpression.UnpackParenthesizedExpression(ie.Target);
813
IdentifierExpression ident = target as IdentifierExpression;
815
return ident.Identifier == method.Name;
817
MemberReferenceExpression mre = target as MemberReferenceExpression;
819
return mre.MemberName == method.Name;
821
PointerReferenceExpression pre = target as PointerReferenceExpression;
823
return pre.MemberName == method.Name;
824
} else if (expr.Role != Roles.TargetExpression) {
825
// MemberReferences & Identifiers that aren't used in an invocation can still match the method
827
if (expr.GetChildByRole(Roles.Identifier).Name == method.Name)
828
potentialMethodGroupConversions.Add(expr);
830
return node is MethodDeclaration;
833
internal override bool IsMatch(ResolveResult rr)
835
if (specialNodeType != null) {
836
var ferr = rr as ForEachResolveResult;
838
return IsMatch(ferr.GetEnumeratorCall)
839
|| (ferr.MoveNextMethod != null && findReferences.IsMemberMatch(method, ferr.MoveNextMethod, true));
841
var arr = rr as AwaitResolveResult;
843
return IsMatch(arr.GetAwaiterInvocation)
844
|| (arr.GetResultMethod != null && findReferences.IsMemberMatch(method, arr.GetResultMethod, true))
845
|| (arr.OnCompletedMethod != null && findReferences.IsMemberMatch(method, arr.OnCompletedMethod, true));
848
var mrr = rr as MemberResolveResult;
849
return mrr != null && findReferences.IsMemberMatch(method, mrr.Member, mrr.IsVirtualCall);
852
internal override void NavigatorDone(CSharpAstResolver resolver, CancellationToken cancellationToken)
854
foreach (var expr in potentialMethodGroupConversions) {
855
var conversion = resolver.GetConversion(expr, cancellationToken);
856
if (conversion.IsMethodGroupConversion && findReferences.IsMemberMatch(method, conversion.Method, conversion.IsVirtualMethodLookup)) {
857
IType targetType = resolver.GetExpectedType(expr, cancellationToken);
858
ResolveResult result = resolver.Resolve(expr, cancellationToken);
859
ReportMatch(expr, new ConversionResolveResult(targetType, result, conversion));
862
base.NavigatorDone(resolver, cancellationToken);
867
#region Find Indexer References
868
SearchScope FindIndexerReferences(IProperty indexer)
870
return new SearchScope(
871
delegate (ICompilation compilation) {
872
IProperty imported = compilation.Import(indexer);
873
if (imported != null)
874
return new FindIndexerReferencesNavigator(imported);
880
sealed class FindIndexerReferencesNavigator : FindReferenceNavigator
882
readonly IProperty indexer;
884
public FindIndexerReferencesNavigator(IProperty indexer)
886
this.indexer = indexer;
889
internal override bool CanMatch(AstNode node)
891
return node is IndexerExpression || node is IndexerDeclaration;
894
internal override bool IsMatch(ResolveResult rr)
896
MemberResolveResult mrr = rr as MemberResolveResult;
897
return mrr != null && findReferences.IsMemberMatch(indexer, mrr.Member, mrr.IsVirtualCall);
902
#region Find Operator References
903
SearchScope GetSearchScopeForOperator(IMethod op)
905
OperatorType? opType = OperatorDeclaration.GetOperatorType(op.Name);
907
return GetSearchScopeForMethod(op);
908
switch (opType.Value) {
909
case OperatorType.LogicalNot:
910
return FindUnaryOperator(op, UnaryOperatorType.Not);
911
case OperatorType.OnesComplement:
912
return FindUnaryOperator(op, UnaryOperatorType.BitNot);
913
case OperatorType.UnaryPlus:
914
return FindUnaryOperator(op, UnaryOperatorType.Plus);
915
case OperatorType.UnaryNegation:
916
return FindUnaryOperator(op, UnaryOperatorType.Minus);
917
case OperatorType.Increment:
918
return FindUnaryOperator(op, UnaryOperatorType.Increment);
919
case OperatorType.Decrement:
920
return FindUnaryOperator(op, UnaryOperatorType.Decrement);
921
case OperatorType.True:
922
case OperatorType.False:
923
// TODO: implement search for op_True/op_False correctly
924
return GetSearchScopeForMethod(op);
925
case OperatorType.Addition:
926
return FindBinaryOperator(op, BinaryOperatorType.Add);
927
case OperatorType.Subtraction:
928
return FindBinaryOperator(op, BinaryOperatorType.Subtract);
929
case OperatorType.Multiply:
930
return FindBinaryOperator(op, BinaryOperatorType.Multiply);
931
case OperatorType.Division:
932
return FindBinaryOperator(op, BinaryOperatorType.Divide);
933
case OperatorType.Modulus:
934
return FindBinaryOperator(op, BinaryOperatorType.Modulus);
935
case OperatorType.BitwiseAnd:
936
// TODO: an overloaded bitwise operator can also be called using the corresponding logical operator
937
// (if op_True/op_False is defined)
938
return FindBinaryOperator(op, BinaryOperatorType.BitwiseAnd);
939
case OperatorType.BitwiseOr:
940
return FindBinaryOperator(op, BinaryOperatorType.BitwiseOr);
941
case OperatorType.ExclusiveOr:
942
return FindBinaryOperator(op, BinaryOperatorType.ExclusiveOr);
943
case OperatorType.LeftShift:
944
return FindBinaryOperator(op, BinaryOperatorType.ShiftLeft);
945
case OperatorType.RightShift:
946
return FindBinaryOperator(op, BinaryOperatorType.ShiftRight);
947
case OperatorType.Equality:
948
return FindBinaryOperator(op, BinaryOperatorType.Equality);
949
case OperatorType.Inequality:
950
return FindBinaryOperator(op, BinaryOperatorType.InEquality);
951
case OperatorType.GreaterThan:
952
return FindBinaryOperator(op, BinaryOperatorType.GreaterThan);
953
case OperatorType.LessThan:
954
return FindBinaryOperator(op, BinaryOperatorType.LessThan);
955
case OperatorType.GreaterThanOrEqual:
956
return FindBinaryOperator(op, BinaryOperatorType.GreaterThanOrEqual);
957
case OperatorType.LessThanOrEqual:
958
return FindBinaryOperator(op, BinaryOperatorType.LessThanOrEqual);
959
case OperatorType.Implicit:
960
return FindOperator(op, m => new FindImplicitOperatorNavigator(m));
961
case OperatorType.Explicit:
962
return FindOperator(op, m => new FindExplicitOperatorNavigator(m));
964
throw new InvalidOperationException("Invalid value for OperatorType");
968
SearchScope FindOperator(IMethod op, Func<IMethod, FindReferenceNavigator> factory)
970
return new SearchScope(
971
delegate (ICompilation compilation) {
972
IMethod imported = compilation.Import(op);
973
return imported != null ? factory(imported) : null;
977
SearchScope FindUnaryOperator(IMethod op, UnaryOperatorType operatorType)
979
return FindOperator(op, m => new FindUnaryOperatorNavigator(m, operatorType));
982
sealed class FindUnaryOperatorNavigator : FindReferenceNavigator
985
readonly UnaryOperatorType operatorType;
987
public FindUnaryOperatorNavigator(IMethod op, UnaryOperatorType operatorType)
990
this.operatorType = operatorType;
993
internal override bool CanMatch(AstNode node)
995
UnaryOperatorExpression uoe = node as UnaryOperatorExpression;
997
if (operatorType == UnaryOperatorType.Increment)
998
return uoe.Operator == UnaryOperatorType.Increment || uoe.Operator == UnaryOperatorType.PostIncrement;
999
else if (operatorType == UnaryOperatorType.Decrement)
1000
return uoe.Operator == UnaryOperatorType.Decrement || uoe.Operator == UnaryOperatorType.PostDecrement;
1002
return uoe.Operator == operatorType;
1004
return node is OperatorDeclaration;
1007
internal override bool IsMatch(ResolveResult rr)
1009
MemberResolveResult mrr = rr as MemberResolveResult;
1010
return mrr != null && findReferences.IsMemberMatch(op, mrr.Member, mrr.IsVirtualCall);
1014
SearchScope FindBinaryOperator(IMethod op, BinaryOperatorType operatorType)
1016
return FindOperator(op, m => new FindBinaryOperatorNavigator(m, operatorType));
1019
sealed class FindBinaryOperatorNavigator : FindReferenceNavigator
1021
readonly IMethod op;
1022
readonly BinaryOperatorType operatorType;
1024
public FindBinaryOperatorNavigator(IMethod op, BinaryOperatorType operatorType)
1027
this.operatorType = operatorType;
1030
internal override bool CanMatch(AstNode node)
1032
BinaryOperatorExpression boe = node as BinaryOperatorExpression;
1034
return boe.Operator == operatorType;
1036
return node is OperatorDeclaration;
1039
internal override bool IsMatch(ResolveResult rr)
1041
MemberResolveResult mrr = rr as MemberResolveResult;
1042
return mrr != null && findReferences.IsMemberMatch(op, mrr.Member, mrr.IsVirtualCall);
1046
sealed class FindImplicitOperatorNavigator : FindReferenceNavigator
1048
readonly IMethod op;
1050
public FindImplicitOperatorNavigator(IMethod op)
1055
internal override bool CanMatch(AstNode node)
1060
internal override bool IsMatch(ResolveResult rr)
1062
MemberResolveResult mrr = rr as MemberResolveResult;
1063
return mrr != null && findReferences.IsMemberMatch(op, mrr.Member, mrr.IsVirtualCall);
1066
public override void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
1068
if (conversion.IsUserDefined && findReferences.IsMemberMatch(op, conversion.Method, conversion.IsVirtualMethodLookup)) {
1069
ReportMatch(expression, result);
1074
sealed class FindExplicitOperatorNavigator : FindReferenceNavigator
1076
readonly IMethod op;
1078
public FindExplicitOperatorNavigator(IMethod op)
1083
internal override bool CanMatch(AstNode node)
1085
return node is CastExpression;
1088
internal override bool IsMatch(ResolveResult rr)
1090
ConversionResolveResult crr = rr as ConversionResolveResult;
1091
return crr != null && crr.Conversion.IsUserDefined
1092
&& findReferences.IsMemberMatch(op, crr.Conversion.Method, crr.Conversion.IsVirtualMethodLookup);
1097
#region Find Constructor References
1098
SearchScope FindObjectCreateReferences(IMethod ctor)
1100
string searchTerm = null;
1101
if (KnownTypeReference.GetCSharpNameByTypeCode(ctor.DeclaringTypeDefinition.KnownTypeCode) == null) {
1102
// not a built-in type
1103
searchTerm = ctor.DeclaringTypeDefinition.Name;
1104
if (searchTerm.Length > 9 && searchTerm.EndsWith("Attribute", StringComparison.Ordinal)) {
1105
// we also need to look for the short form
1109
return new SearchScope(
1111
delegate (ICompilation compilation) {
1112
IMethod imported = compilation.Import(ctor);
1113
if (imported != null)
1114
return new FindObjectCreateReferencesNavigator(imported);
1120
sealed class FindObjectCreateReferencesNavigator : FindReferenceNavigator
1122
readonly IMethod ctor;
1124
public FindObjectCreateReferencesNavigator(IMethod ctor)
1129
internal override bool CanMatch(AstNode node)
1131
return node is ObjectCreateExpression || node is ConstructorDeclaration || node is Attribute;
1134
internal override bool IsMatch(ResolveResult rr)
1136
MemberResolveResult mrr = rr as MemberResolveResult;
1137
return mrr != null && findReferences.IsMemberMatch(ctor, mrr.Member, mrr.IsVirtualCall);
1141
SearchScope FindChainedConstructorReferences(IMethod ctor)
1143
SearchScope searchScope = new SearchScope(
1144
delegate (ICompilation compilation) {
1145
IMethod imported = compilation.Import(ctor);
1146
if (imported != null)
1147
return new FindChainedConstructorReferencesNavigator(imported);
1151
if (ctor.DeclaringTypeDefinition.IsSealed)
1152
searchScope.accessibility = Accessibility.Private;
1154
searchScope.accessibility = Accessibility.Protected;
1155
searchScope.accessibility = MergeAccessibility(GetEffectiveAccessibility(ctor), searchScope.accessibility);
1159
sealed class FindChainedConstructorReferencesNavigator : FindReferenceNavigator
1161
readonly IMethod ctor;
1163
public FindChainedConstructorReferencesNavigator(IMethod ctor)
1168
internal override bool CanMatch(AstNode node)
1170
return node is ConstructorInitializer;
1173
internal override bool IsMatch(ResolveResult rr)
1175
MemberResolveResult mrr = rr as MemberResolveResult;
1176
return mrr != null && findReferences.IsMemberMatch(ctor, mrr.Member, mrr.IsVirtualCall);
1181
#region Find Destructor References
1182
SearchScope GetSearchScopeForDestructor(IMethod dtor)
1184
var scope = new SearchScope (
1185
delegate (ICompilation compilation) {
1186
IMethod imported = compilation.Import(dtor);
1187
if (imported != null) {
1188
return new FindDestructorReferencesNavigator (imported);
1193
scope.accessibility = Accessibility.Private;
1197
sealed class FindDestructorReferencesNavigator : FindReferenceNavigator
1199
readonly IMethod dtor;
1201
public FindDestructorReferencesNavigator (IMethod dtor)
1206
internal override bool CanMatch(AstNode node)
1208
return node is DestructorDeclaration;
1211
internal override bool IsMatch(ResolveResult rr)
1213
MemberResolveResult mrr = rr as MemberResolveResult;
1214
return mrr != null && findReferences.IsMemberMatch(dtor, mrr.Member, mrr.IsVirtualCall);
1219
#region Find Local Variable References
1221
/// Finds all references of a given variable.
1223
/// <param name="variable">The variable for which to look.</param>
1224
/// <param name="unresolvedFile">The type system representation of the file being searched.</param>
1225
/// <param name="syntaxTree">The syntax tree of the file being searched.</param>
1226
/// <param name="compilation">The compilation.</param>
1227
/// <param name="callback">Callback used to report the references that were found.</param>
1228
/// <param name="cancellationToken">Cancellation token that may be used to cancel the operation.</param>
1229
public void FindLocalReferences(IVariable variable, CSharpUnresolvedFile unresolvedFile, SyntaxTree syntaxTree,
1230
ICompilation compilation, FoundReferenceCallback callback, CancellationToken cancellationToken)
1232
if (variable == null)
1233
throw new ArgumentNullException("variable");
1234
var searchScope = new SearchScope(c => new FindLocalReferencesNavigator(variable));
1235
searchScope.declarationCompilation = compilation;
1236
FindReferencesInFile(searchScope, unresolvedFile, syntaxTree, compilation, callback, cancellationToken);
1239
class FindLocalReferencesNavigator : FindReferenceNavigator
1241
readonly IVariable variable;
1243
public FindLocalReferencesNavigator(IVariable variable)
1245
this.variable = variable;
1248
internal override bool CanMatch(AstNode node)
1250
var expr = node as IdentifierExpression;
1252
return expr.TypeArguments.Count == 0 && variable.Name == expr.Identifier;
1253
var vi = node as VariableInitializer;
1255
return vi.Name == variable.Name;
1256
var pd = node as ParameterDeclaration;
1258
return pd.Name == variable.Name;
1259
var id = node as Identifier;
1261
return id.Name == variable.Name;
1265
internal override bool IsMatch(ResolveResult rr)
1267
var lrr = rr as LocalResolveResult;
1268
return lrr != null && lrr.Variable.Name == variable.Name && lrr.Variable.Region == variable.Region;
1273
#region Find Type Parameter References
1275
/// Finds all references of a given type parameter.
1277
/// <param name="typeParameter">The type parameter for which to look.</param>
1278
/// <param name="unresolvedFile">The type system representation of the file being searched.</param>
1279
/// <param name="syntaxTree">The syntax tree of the file being searched.</param>
1280
/// <param name="compilation">The compilation.</param>
1281
/// <param name="callback">Callback used to report the references that were found.</param>
1282
/// <param name="cancellationToken">Cancellation token that may be used to cancel the operation.</param>
1283
public void FindTypeParameterReferences(IType typeParameter, CSharpUnresolvedFile unresolvedFile, SyntaxTree syntaxTree,
1284
ICompilation compilation, FoundReferenceCallback callback, CancellationToken cancellationToken)
1286
if (typeParameter == null)
1287
throw new ArgumentNullException("typeParameter");
1288
if (typeParameter.Kind != TypeKind.TypeParameter)
1289
throw new ArgumentOutOfRangeException("typeParameter", "Only type parameters are allowed");
1290
var searchScope = new SearchScope(c => new FindTypeParameterReferencesNavigator((ITypeParameter)typeParameter));
1291
searchScope.declarationCompilation = compilation;
1292
searchScope.accessibility = Accessibility.Private;
1293
FindReferencesInFile(searchScope, unresolvedFile, syntaxTree, compilation, callback, cancellationToken);
1296
class FindTypeParameterReferencesNavigator : FindReferenceNavigator
1298
readonly ITypeParameter typeParameter;
1300
public FindTypeParameterReferencesNavigator(ITypeParameter typeParameter)
1302
this.typeParameter = typeParameter;
1305
internal override bool CanMatch(AstNode node)
1307
var type = node as SimpleType;
1309
return type.Identifier == typeParameter.Name;
1310
var declaration = node as TypeParameterDeclaration;
1311
if (declaration != null)
1312
return declaration.Name == typeParameter.Name;
1316
internal override bool IsMatch(ResolveResult rr)
1318
var lrr = rr as TypeResolveResult;
1319
return lrr != null && lrr.Type.Kind == TypeKind.TypeParameter && ((ITypeParameter)lrr.Type).Region == typeParameter.Region;
1324
#region Find Namespace References
1325
SearchScope GetSearchScopeForNamespace(INamespace ns)
1327
var scope = new SearchScope (
1328
delegate (ICompilation compilation) {
1329
return new FindNamespaceNavigator (ns);
1335
sealed class FindNamespaceNavigator : FindReferenceNavigator
1337
readonly INamespace ns;
1339
public FindNamespaceNavigator (INamespace ns)
1344
internal override bool CanMatch(AstNode node)
1346
var nsd = node as NamespaceDeclaration;
1347
if (nsd != null && nsd.FullName.StartsWith(ns.FullName, StringComparison.Ordinal))
1350
var ud = node as UsingDeclaration;
1351
if (ud != null && ud.Namespace == ns.FullName)
1354
var st = node as SimpleType;
1355
if (st != null && st.Identifier == ns.Name)
1358
var mt = node as MemberType;
1359
if (mt != null && mt.MemberName == ns.Name)
1362
var identifer = node as IdentifierExpression;
1363
if (identifer != null && identifer.Identifier == ns.Name)
1366
var mrr = node as MemberReferenceExpression;
1367
if (mrr != null && mrr.MemberName == ns.Name)
1374
internal override bool IsMatch(ResolveResult rr)
1376
var nsrr = rr as NamespaceResolveResult;
1377
return nsrr != null && nsrr.NamespaceName.StartsWith(ns.FullName, StringComparison.Ordinal);