~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/nrefactory/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
19
using System;
 
20
using System.Collections.Generic;
 
21
using System.Diagnostics;
 
22
using System.Linq;
 
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;
 
29
 
 
30
namespace ICSharpCode.NRefactory.CSharp.Resolver
 
31
{
 
32
        public delegate void FoundReferenceCallback(AstNode astNode, ResolveResult result);
 
33
        
 
34
        /// <summary>
 
35
        /// 'Find references' implementation.
 
36
        /// </summary>
 
37
        /// <remarks>
 
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).
 
41
        /// </remarks>
 
42
        public sealed class FindReferences
 
43
        {
 
44
                #region Properties
 
45
                /// <summary>
 
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>.
 
48
                /// </summary>
 
49
                public bool FindTypeReferencesEvenIfAliased { get; set; }
 
50
                
 
51
                /// <summary>
 
52
                /// Specifies whether find references should only look for specialized matches
 
53
                /// with equal type parameter substitution to the member we are searching for.
 
54
                /// </summary>
 
55
                public bool FindOnlySpecializedReferences { get; set; }
 
56
                
 
57
                /// <summary>
 
58
                /// If this option is enabled, find references on a overridden member
 
59
                /// will find calls to the base member.
 
60
                /// </summary>
 
61
                public bool FindCallsThroughVirtualBaseMethod { get; set; }
 
62
                
 
63
                /// <summary>
 
64
                /// If this option is enabled, find references on a member implementing
 
65
                /// an interface will also find calls to the interface.
 
66
                /// </summary>
 
67
                public bool FindCallsThroughInterface { get; set; }
 
68
                
 
69
                /// <summary>
 
70
                /// If this option is enabled, find references will look for all references
 
71
                /// to the virtual method slot.
 
72
                /// </summary>
 
73
                public bool WholeVirtualSlot { get; set; }
 
74
                
 
75
                /// <summary>
 
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>&lt;param&gt;</c> and <c>&lt;paramref&gt;</c> tags.
 
79
                /// TODO: implement this feature.
 
80
                /// </summary>
 
81
                public bool SearchInDocumentationComments { get; set; }
 
82
                #endregion
 
83
                
 
84
                #region GetEffectiveAccessibility
 
85
                /// <summary>
 
86
                /// Gets the effective accessibility of the specified entity -
 
87
                /// that is, the accessibility viewed from the top level.
 
88
                /// </summary>
 
89
                /// <remarks>
 
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
 
94
                /// </remarks>
 
95
                public static Accessibility GetEffectiveAccessibility(IEntity entity)
 
96
                {
 
97
                        if (entity == null)
 
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);
 
102
                        }
 
103
                        return a;
 
104
                }
 
105
                
 
106
                static Accessibility MergeAccessibility(Accessibility outer, Accessibility inner)
 
107
                {
 
108
                        if (outer == inner)
 
109
                                return 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)
 
115
                                return inner;
 
116
                        if (inner == Accessibility.Public)
 
117
                                return outer;
 
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)
 
121
                                return inner;
 
122
                        if (inner == Accessibility.ProtectedOrInternal)
 
123
                                return outer;
 
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;
 
127
                }
 
128
                #endregion
 
129
                
 
130
                #region class SearchScope
 
131
                sealed class SearchScope : IFindReferenceSearchScope
 
132
                {
 
133
                        readonly Func<ICompilation, FindReferenceNavigator> factory;
 
134
                        
 
135
                        public SearchScope(Func<ICompilation, FindReferenceNavigator> factory)
 
136
                        {
 
137
                                this.factory = factory;
 
138
                        }
 
139
                        
 
140
                        public SearchScope(string searchTerm, Func<ICompilation, FindReferenceNavigator> factory)
 
141
                        {
 
142
                                this.searchTerm = searchTerm;
 
143
                                this.factory = factory;
 
144
                        }
 
145
                        
 
146
                        internal string searchTerm;
 
147
                        internal FindReferences findReferences;
 
148
                        internal ICompilation declarationCompilation;
 
149
                        internal Accessibility accessibility;
 
150
                        internal ITypeDefinition topLevelTypeDefinition;
 
151
                        
 
152
                        IResolveVisitorNavigator IFindReferenceSearchScope.GetNavigator(ICompilation compilation, FoundReferenceCallback callback)
 
153
                        {
 
154
                                FindReferenceNavigator n = factory(compilation);
 
155
                                if (n != null) {
 
156
                                        n.callback = callback;
 
157
                                        n.findReferences = findReferences;
 
158
                                        return n;
 
159
                                } else {
 
160
                                        return new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Skip, null);
 
161
                                }
 
162
                        }
 
163
                        
 
164
                        ICompilation IFindReferenceSearchScope.Compilation {
 
165
                                get { return declarationCompilation; }
 
166
                        }
 
167
                        
 
168
                        string IFindReferenceSearchScope.SearchTerm {
 
169
                                get { return searchTerm; }
 
170
                        }
 
171
                        
 
172
                        Accessibility IFindReferenceSearchScope.Accessibility {
 
173
                                get { return accessibility; }
 
174
                        }
 
175
                        
 
176
                        ITypeDefinition IFindReferenceSearchScope.TopLevelTypeDefinition {
 
177
                                get { return topLevelTypeDefinition; }
 
178
                        }
 
179
                }
 
180
                
 
181
                abstract class FindReferenceNavigator : IResolveVisitorNavigator
 
182
                {
 
183
                        internal FoundReferenceCallback callback;
 
184
                        internal FindReferences findReferences;
 
185
                        
 
186
                        internal abstract bool CanMatch(AstNode node);
 
187
                        internal abstract bool IsMatch(ResolveResult rr);
 
188
                        
 
189
                        ResolveVisitorNavigationMode IResolveVisitorNavigator.Scan(AstNode node)
 
190
                        {
 
191
                                if (CanMatch(node))
 
192
                                        return ResolveVisitorNavigationMode.Resolve;
 
193
                                else
 
194
                                        return ResolveVisitorNavigationMode.Scan;
 
195
                        }
 
196
                        
 
197
                        void IResolveVisitorNavigator.Resolved(AstNode node, ResolveResult result)
 
198
                        {
 
199
                                if (CanMatch(node) && IsMatch(result)) {
 
200
                                        ReportMatch(node, result);
 
201
                                }
 
202
                        }
 
203
                        
 
204
                        public virtual void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
 
205
                        {
 
206
                        }
 
207
                        
 
208
                        protected void ReportMatch(AstNode node, ResolveResult result)
 
209
                        {
 
210
                                if (callback != null)
 
211
                                        callback(node, result);
 
212
                        }
 
213
                        
 
214
                        internal virtual void NavigatorDone(CSharpAstResolver resolver, CancellationToken cancellationToken)
 
215
                        {
 
216
                        }
 
217
                }
 
218
                #endregion
 
219
                
 
220
                #region GetSearchScopes
 
221
                public IList<IFindReferenceSearchScope> GetSearchScopes(IEntity entity)
 
222
                {
 
223
                        if (entity == null)
 
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;
 
231
                        SearchScope scope;
 
232
                        SearchScope additionalScope = null;
 
233
                        switch (entity.EntityType) {
 
234
                                case EntityType.TypeDefinition:
 
235
                                        scope = FindTypeDefinitionReferences((ITypeDefinition)entity, this.FindTypeReferencesEvenIfAliased, out additionalScope);
 
236
                                        break;
 
237
                                case EntityType.Field:
 
238
                                        if (entity.DeclaringTypeDefinition != null && entity.DeclaringTypeDefinition.Kind == TypeKind.Enum)
 
239
                                                scope = FindMemberReferences(entity, m => new FindEnumMemberReferences((IField)m));
 
240
                                        else
 
241
                                                scope = FindMemberReferences(entity, m => new FindFieldReferences((IField)m));
 
242
                                        break;
 
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);
 
249
                                        break;
 
250
                                case EntityType.Event:
 
251
                                        scope = FindMemberReferences(entity, m => new FindEventReferences((IEvent)m));
 
252
                                        break;
 
253
                                case EntityType.Method:
 
254
                                        scope = GetSearchScopeForMethod((IMethod)entity);
 
255
                                        break;
 
256
                                case EntityType.Indexer:
 
257
                                        scope = FindIndexerReferences((IProperty)entity);
 
258
                                        break;
 
259
                                case EntityType.Operator:
 
260
                                        scope = GetSearchScopeForOperator((IMethod)entity);
 
261
                                        break;
 
262
                                case EntityType.Constructor:
 
263
                                        IMethod ctor = (IMethod)entity;
 
264
                                        scope = FindObjectCreateReferences(ctor);
 
265
                                        additionalScope = FindChainedConstructorReferences(ctor);
 
266
                                        break;
 
267
                                case EntityType.Destructor:
 
268
                                        scope = GetSearchScopeForDestructor((IMethod)entity);
 
269
                                        break;
 
270
                                default:
 
271
                                        throw new ArgumentException("Unknown entity type " + entity.EntityType);
 
272
                        }
 
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 };
 
285
                        } else {
 
286
                                return new[] { scope };
 
287
                        }
 
288
                }
 
289
 
 
290
                public IList<IFindReferenceSearchScope> GetSearchScopes(INamespace ns)
 
291
                {
 
292
                        if (ns == null)
 
293
                                throw new ArgumentNullException("ns");
 
294
                        return new[] { GetSearchScopeForNamespace(ns) };
 
295
                }
 
296
 
 
297
                #endregion
 
298
                
 
299
                #region GetInterestingFileNames
 
300
                /// <summary>
 
301
                /// Gets the file names that possibly contain references to the element being searched for.
 
302
                /// </summary>
 
303
                public IEnumerable<CSharpUnresolvedFile> GetInterestingFiles(IFindReferenceSearchScope searchScope, ICompilation compilation)
 
304
                {
 
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;
 
310
                        if (pc == null)
 
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;
 
317
                                }
 
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();
 
323
                                                else
 
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>();
 
330
                                                else
 
331
                                                        return EmptyList<CSharpUnresolvedFile>.Instance;
 
332
                                        case Accessibility.ProtectedAndInternal:
 
333
                                                if (topLevelTypeDef.ParentAssembly.InternalsVisibleTo(compilation.MainAssembly))
 
334
                                                        return GetInterestingFilesProtected(topLevelTypeDef);
 
335
                                                else
 
336
                                                        return EmptyList<CSharpUnresolvedFile>.Instance;
 
337
                                        case Accessibility.ProtectedOrInternal:
 
338
                                                if (topLevelTypeDef.ParentAssembly.InternalsVisibleTo(compilation.MainAssembly))
 
339
                                                        return pc.Files.OfType<CSharpUnresolvedFile>();
 
340
                                                else
 
341
                                                        return GetInterestingFilesProtected(topLevelTypeDef);
 
342
                                        default:
 
343
                                                return pc.Files.OfType<CSharpUnresolvedFile>();
 
344
                                }
 
345
                        } else {
 
346
                                return pc.Files.OfType<CSharpUnresolvedFile>();
 
347
                        }
 
348
                }
 
349
                
 
350
                IEnumerable<CSharpUnresolvedFile> GetInterestingFilesProtected(ITypeDefinition referencedTypeDefinition)
 
351
                {
 
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();
 
357
                }
 
358
                #endregion
 
359
                
 
360
                #region FindReferencesInFile
 
361
                /// <summary>
 
362
                /// Finds all references in the given file.
 
363
                /// </summary>
 
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)
 
372
                {
 
373
                        if (searchScope == null)
 
374
                                throw new ArgumentNullException("searchScope");
 
375
                        FindReferencesInFile(new[] { searchScope }, unresolvedFile, syntaxTree, compilation, callback, cancellationToken);
 
376
                }
 
377
                
 
378
                /// <summary>
 
379
                /// Finds all references in the given file.
 
380
                /// </summary>
 
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)
 
389
                {
 
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");
 
398
                        
 
399
                        if (searchScopes.Count == 0)
 
400
                                return;
 
401
                        var navigators = new IResolveVisitorNavigator[searchScopes.Count];
 
402
                        for (int i = 0; i < navigators.Length; i++) {
 
403
                                navigators[i] = searchScopes[i].GetNavigator(compilation, callback);
 
404
                        }
 
405
                        IResolveVisitorNavigator combinedNavigator;
 
406
                        if (searchScopes.Count == 1) {
 
407
                                combinedNavigator = navigators[0];
 
408
                        } else {
 
409
                                combinedNavigator = new CompositeResolveVisitorNavigator(navigators);
 
410
                        }
 
411
                        
 
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;
 
419
                                if (frn != null)
 
420
                                        frn.NavigatorDone(resolver, cancellationToken);
 
421
                        }
 
422
                }
 
423
                #endregion
 
424
                
 
425
                #region Find TypeDefinition References
 
426
                SearchScope FindTypeDefinitionReferences(ITypeDefinition typeDefinition, bool findTypeReferencesEvenIfAliased, out SearchScope additionalScope)
 
427
                {
 
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);
 
438
                                }
 
439
                        }
 
440
                        return FindTypeDefinitionReferences(typeDefinition, searchTerm);
 
441
                }
 
442
                
 
443
                SearchScope FindTypeDefinitionReferences(ITypeDefinition typeDefinition, string searchTerm)
 
444
                {
 
445
                        return new SearchScope(
 
446
                                searchTerm,
 
447
                                delegate (ICompilation compilation) {
 
448
                                        ITypeDefinition imported = compilation.Import(typeDefinition);
 
449
                                        if (imported != null)
 
450
                                                return new FindTypeDefinitionReferencesNavigator(imported, searchTerm);
 
451
                                        else
 
452
                                                return null;
 
453
                                });
 
454
                }
 
455
                
 
456
                sealed class FindTypeDefinitionReferencesNavigator : FindReferenceNavigator
 
457
                {
 
458
                        readonly ITypeDefinition typeDefinition;
 
459
                        readonly string searchTerm;
 
460
                        
 
461
                        public FindTypeDefinitionReferencesNavigator(ITypeDefinition typeDefinition, string searchTerm)
 
462
                        {
 
463
                                this.typeDefinition = typeDefinition;
 
464
                                this.searchTerm = searchTerm;
 
465
                        }
 
466
                        
 
467
                        internal override bool CanMatch(AstNode node)
 
468
                        {
 
469
                                IdentifierExpression ident = node as IdentifierExpression;
 
470
                                if (ident != null)
 
471
                                        return searchTerm == null || ident.Identifier == searchTerm;
 
472
                                
 
473
                                MemberReferenceExpression mre = node as MemberReferenceExpression;
 
474
                                if (mre != null)
 
475
                                        return searchTerm == null || mre.MemberName == searchTerm;
 
476
                                
 
477
                                SimpleType st = node as SimpleType;
 
478
                                if (st != null)
 
479
                                        return searchTerm == null || st.Identifier == searchTerm;
 
480
                                
 
481
                                MemberType mt = node as MemberType;
 
482
                                if (mt != null)
 
483
                                        return searchTerm == null || mt.MemberName == searchTerm;
 
484
                                
 
485
                                if (searchTerm == null && node is PrimitiveType)
 
486
                                        return true;
 
487
                                
 
488
                                TypeDeclaration typeDecl = node as TypeDeclaration;
 
489
                                if (typeDecl != null)
 
490
                                        return searchTerm == null || typeDecl.Name == searchTerm;
 
491
                                
 
492
                                DelegateDeclaration delegateDecl = node as DelegateDeclaration;
 
493
                                if (delegateDecl != null)
 
494
                                        return searchTerm == null || delegateDecl.Name == searchTerm;
 
495
                                
 
496
                                return false;
 
497
                        }
 
498
                        
 
499
                        internal override bool IsMatch(ResolveResult rr)
 
500
                        {
 
501
                                TypeResolveResult trr = rr as TypeResolveResult;
 
502
                                return trr != null && typeDefinition.Equals(trr.Type.GetDefinition());
 
503
                        }
 
504
                }
 
505
                #endregion
 
506
                
 
507
                #region Find Member References
 
508
                SearchScope FindMemberReferences(IEntity member, Func<IMember, FindMemberReferencesNavigator> factory)
 
509
                {
 
510
                        string searchTerm = member.Name;
 
511
                        return new SearchScope(
 
512
                                searchTerm,
 
513
                                delegate(ICompilation compilation) {
 
514
                                        IMember imported = compilation.Import((IMember)member);
 
515
                                        return imported != null ? factory(imported) : null;
 
516
                                });
 
517
                }
 
518
                
 
519
                class FindMemberReferencesNavigator : FindReferenceNavigator
 
520
                {
 
521
                        readonly IMember member;
 
522
                        readonly string searchTerm;
 
523
                        
 
524
                        public FindMemberReferencesNavigator(IMember member)
 
525
                        {
 
526
                                this.member = member;
 
527
                                this.searchTerm = member.Name;
 
528
                        }
 
529
                        
 
530
                        internal override bool CanMatch(AstNode node)
 
531
                        {
 
532
                                IdentifierExpression ident = node as IdentifierExpression;
 
533
                                if (ident != null)
 
534
                                        return ident.Identifier == searchTerm;
 
535
                                
 
536
                                MemberReferenceExpression mre = node as MemberReferenceExpression;
 
537
                                if (mre != null)
 
538
                                        return mre.MemberName == searchTerm;
 
539
                                
 
540
                                PointerReferenceExpression pre = node as PointerReferenceExpression;
 
541
                                if (pre != null)
 
542
                                        return pre.MemberName == searchTerm;
 
543
                                
 
544
                                NamedExpression ne = node as NamedExpression;
 
545
                                if (ne != null)
 
546
                                        return ne.Name == searchTerm;
 
547
                                
 
548
                                return false;
 
549
                        }
 
550
                        
 
551
                        internal override bool IsMatch(ResolveResult rr)
 
552
                        {
 
553
                                MemberResolveResult mrr = rr as MemberResolveResult;
 
554
                                return mrr != null && findReferences.IsMemberMatch(member, mrr.Member, mrr.IsVirtualCall);
 
555
                        }
 
556
                }
 
557
                
 
558
                IMember NormalizeMember(IMember member)
 
559
                {
 
560
                        if (WholeVirtualSlot && member.IsOverride)
 
561
                                member = InheritanceHelper.GetBaseMembers(member, false).FirstOrDefault(m => !m.IsOverride) ?? member;
 
562
                        if (!FindOnlySpecializedReferences)
 
563
                                member = member.MemberDefinition;
 
564
                        return member;
 
565
                }
 
566
                
 
567
                bool IsMemberMatch(IMember member, IMember referencedMember, bool isVirtualCall)
 
568
                {
 
569
                        referencedMember = NormalizeMember(referencedMember);
 
570
                        if (member.Equals(referencedMember))
 
571
                                return true;
 
572
                        if (!isVirtualCall)
 
573
                                return false;
 
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))
 
580
                                                        return true;
 
581
                                        } else {
 
582
                                                if (baseMember.MemberDefinition.Equals(referencedMember))
 
583
                                                        return true;
 
584
                                        }
 
585
                                        if (!baseMember.IsOverride)
 
586
                                                break;
 
587
                                }
 
588
                                return false;
 
589
                        } else if (FindCallsThroughInterface && isInterfaceCall) {
 
590
                                // Test if 'member' implements 'referencedMember':
 
591
                                if (FindOnlySpecializedReferences) {
 
592
                                        return member.ImplementedInterfaceMembers.Contains(referencedMember);
 
593
                                } else {
 
594
                                        return member.ImplementedInterfaceMembers.Any(m => m.MemberDefinition.Equals(referencedMember));
 
595
                                }
 
596
                        }
 
597
                        return false;
 
598
                }
 
599
                
 
600
                bool PerformVirtualLookup(IMember member, IMember referencedMember)
 
601
                {
 
602
                        if (FindCallsThroughVirtualBaseMethod && member.IsOverride && !WholeVirtualSlot)
 
603
                                return true;
 
604
                        var typeDef = referencedMember.DeclaringTypeDefinition;
 
605
                        return FindCallsThroughInterface && typeDef != null && typeDef.Kind == TypeKind.Interface;
 
606
                }
 
607
                
 
608
                sealed class FindFieldReferences : FindMemberReferencesNavigator
 
609
                {
 
610
                        public FindFieldReferences(IField field) : base(field)
 
611
                        {
 
612
                        }
 
613
                        
 
614
                        internal override bool CanMatch(AstNode node)
 
615
                        {
 
616
                                if (node is VariableInitializer) {
 
617
                                        return node.Parent is FieldDeclaration;
 
618
                                }
 
619
                                return base.CanMatch(node);
 
620
                        }
 
621
                }
 
622
                
 
623
                sealed class FindEnumMemberReferences : FindMemberReferencesNavigator
 
624
                {
 
625
                        public FindEnumMemberReferences(IField field) : base(field)
 
626
                        {
 
627
                        }
 
628
                        
 
629
                        internal override bool CanMatch(AstNode node)
 
630
                        {
 
631
                                return node is EnumMemberDeclaration || base.CanMatch(node);
 
632
                        }
 
633
                }
 
634
                
 
635
                sealed class FindPropertyReferences : FindMemberReferencesNavigator
 
636
                {
 
637
                        public FindPropertyReferences(IProperty property) : base(property)
 
638
                        {
 
639
                        }
 
640
                        
 
641
                        internal override bool CanMatch(AstNode node)
 
642
                        {
 
643
                                return node is PropertyDeclaration || base.CanMatch(node);
 
644
                        }
 
645
                }
 
646
                
 
647
                sealed class FindEventReferences : FindMemberReferencesNavigator
 
648
                {
 
649
                        public FindEventReferences(IEvent ev) : base(ev)
 
650
                        {
 
651
                        }
 
652
                        
 
653
                        internal override bool CanMatch(AstNode node)
 
654
                        {
 
655
                                if (node is VariableInitializer) {
 
656
                                        return node.Parent is EventDeclaration;
 
657
                                }
 
658
                                return node is CustomEventDeclaration || base.CanMatch(node);
 
659
                        }
 
660
                }
 
661
                #endregion
 
662
                
 
663
                #region Find References to IEnumerator.Current
 
664
                SearchScope FindEnumeratorCurrentReferences(IProperty property)
 
665
                {
 
666
                        return new SearchScope(
 
667
                                delegate(ICompilation compilation) {
 
668
                                        IProperty imported = compilation.Import(property);
 
669
                                        return imported != null ? new FindEnumeratorCurrentReferencesNavigator(imported) : null;
 
670
                                });
 
671
                }
 
672
 
 
673
                SearchScope FindAwaiterIsCompletedReferences(IProperty property)
 
674
                {
 
675
                        return new SearchScope(
 
676
                                delegate(ICompilation compilation) {
 
677
                                        IProperty imported = compilation.Import(property);
 
678
                                        return imported != null ? new FindAwaiterIsCompletedReferencesNavigator(imported) : null;
 
679
                                });
 
680
                }
 
681
                
 
682
                sealed class FindEnumeratorCurrentReferencesNavigator : FindReferenceNavigator
 
683
                {
 
684
                        IProperty property;
 
685
                        
 
686
                        public FindEnumeratorCurrentReferencesNavigator(IProperty property)
 
687
                        {
 
688
                                this.property = property;
 
689
                        }
 
690
                        
 
691
                        internal override bool CanMatch(AstNode node)
 
692
                        {
 
693
                                return node is ForeachStatement;
 
694
                        }
 
695
                        
 
696
                        internal override bool IsMatch(ResolveResult rr)
 
697
                        {
 
698
                                ForEachResolveResult ferr = rr as ForEachResolveResult;
 
699
                                return ferr != null && ferr.CurrentProperty != null && findReferences.IsMemberMatch(property, ferr.CurrentProperty, true);
 
700
                        }
 
701
                }
 
702
 
 
703
                sealed class FindAwaiterIsCompletedReferencesNavigator : FindReferenceNavigator
 
704
                {
 
705
                        IProperty property;
 
706
                        
 
707
                        public FindAwaiterIsCompletedReferencesNavigator(IProperty property)
 
708
                        {
 
709
                                this.property = property;
 
710
                        }
 
711
                        
 
712
                        internal override bool CanMatch(AstNode node)
 
713
                        {
 
714
                                return node is UnaryOperatorExpression;
 
715
                        }
 
716
                        
 
717
                        internal override bool IsMatch(ResolveResult rr)
 
718
                        {
 
719
                                AwaitResolveResult arr = rr as AwaitResolveResult;
 
720
                                return arr != null && arr.IsCompletedProperty != null && findReferences.IsMemberMatch(property, arr.IsCompletedProperty, true);
 
721
                        }
 
722
                }
 
723
                #endregion
 
724
                
 
725
                #region Find Method References
 
726
                SearchScope GetSearchScopeForMethod(IMethod method)
 
727
                {
 
728
                        Type specialNodeType;
 
729
                        switch (method.Name) {
 
730
                                case "Add":
 
731
                                        specialNodeType = typeof(ArrayInitializerExpression);
 
732
                                        break;
 
733
                                case "Where":
 
734
                                        specialNodeType = typeof(QueryWhereClause);
 
735
                                        break;
 
736
                                case "Select":
 
737
                                        specialNodeType = typeof(QuerySelectClause);
 
738
                                        break;
 
739
                                case "SelectMany":
 
740
                                        specialNodeType = typeof(QueryFromClause);
 
741
                                        break;
 
742
                                case "Join":
 
743
                                case "GroupJoin":
 
744
                                        specialNodeType = typeof(QueryJoinClause);
 
745
                                        break;
 
746
                                case "OrderBy":
 
747
                                case "OrderByDescending":
 
748
                                case "ThenBy":
 
749
                                case "ThenByDescending":
 
750
                                        specialNodeType = typeof(QueryOrdering);
 
751
                                        break;
 
752
                                case "GroupBy":
 
753
                                        specialNodeType = typeof(QueryGroupClause);
 
754
                                        break;
 
755
                                case "Invoke":
 
756
                                        if (method.DeclaringTypeDefinition != null && method.DeclaringTypeDefinition.Kind == TypeKind.Delegate)
 
757
                                                specialNodeType = typeof(InvocationExpression);
 
758
                                        else
 
759
                                                specialNodeType = null;
 
760
                                        break;
 
761
                                case "GetEnumerator":
 
762
                                case "MoveNext":
 
763
                                        specialNodeType = typeof(ForeachStatement);
 
764
                                        break;
 
765
                                case "GetAwaiter":
 
766
                                case "GetResult":
 
767
                                case "OnCompleted":
 
768
                                case "UnsafeOnCompleted":
 
769
                                        specialNodeType = typeof(UnaryOperatorExpression);
 
770
                                        break;
 
771
                                default:
 
772
                                        specialNodeType = null;
 
773
                                        break;
 
774
                        }
 
775
                        // Use searchTerm only if specialNodeType==null
 
776
                        string searchTerm = (specialNodeType == null) ? method.Name : null;
 
777
                        return new SearchScope(
 
778
                                searchTerm,
 
779
                                delegate (ICompilation compilation) {
 
780
                                        IMethod imported = compilation.Import(method);
 
781
                                        if (imported != null)
 
782
                                                return new FindMethodReferences(imported, specialNodeType);
 
783
                                        else
 
784
                                                return null;
 
785
                                });
 
786
                }
 
787
                
 
788
                sealed class FindMethodReferences : FindReferenceNavigator
 
789
                {
 
790
                        readonly IMethod method;
 
791
                        readonly Type specialNodeType;
 
792
                        HashSet<Expression> potentialMethodGroupConversions = new HashSet<Expression>();
 
793
                        
 
794
                        public FindMethodReferences(IMethod method, Type specialNodeType)
 
795
                        {
 
796
                                this.method = method;
 
797
                                this.specialNodeType = specialNodeType;
 
798
                        }
 
799
                        
 
800
                        internal override bool CanMatch(AstNode node)
 
801
                        {
 
802
                                if (specialNodeType != null && node.GetType() == specialNodeType)
 
803
                                        return true;
 
804
                                
 
805
                                Expression expr = node as Expression;
 
806
                                if (expr == null)
 
807
                                        return node is MethodDeclaration;
 
808
                                
 
809
                                InvocationExpression ie = node as InvocationExpression;
 
810
                                if (ie != null) {
 
811
                                        Expression target = ParenthesizedExpression.UnpackParenthesizedExpression(ie.Target);
 
812
                                        
 
813
                                        IdentifierExpression ident = target as IdentifierExpression;
 
814
                                        if (ident != null)
 
815
                                                return ident.Identifier == method.Name;
 
816
                                        
 
817
                                        MemberReferenceExpression mre = target as MemberReferenceExpression;
 
818
                                        if (mre != null)
 
819
                                                return mre.MemberName == method.Name;
 
820
                                        
 
821
                                        PointerReferenceExpression pre = target as PointerReferenceExpression;
 
822
                                        if (pre != null)
 
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
 
826
                                        // as delegate name.
 
827
                                        if (expr.GetChildByRole(Roles.Identifier).Name == method.Name)
 
828
                                                potentialMethodGroupConversions.Add(expr);
 
829
                                }
 
830
                                return node is MethodDeclaration;
 
831
                        }
 
832
                        
 
833
                        internal override bool IsMatch(ResolveResult rr)
 
834
                        {
 
835
                                if (specialNodeType != null) {
 
836
                                        var ferr = rr as ForEachResolveResult;
 
837
                                        if (ferr != null) {
 
838
                                                return IsMatch(ferr.GetEnumeratorCall)
 
839
                                                        || (ferr.MoveNextMethod != null && findReferences.IsMemberMatch(method, ferr.MoveNextMethod, true));
 
840
                                        }
 
841
                                        var arr = rr as AwaitResolveResult;
 
842
                                        if (arr != null) {
 
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));
 
846
                                        }
 
847
                                }
 
848
                                var mrr = rr as MemberResolveResult;
 
849
                                return mrr != null && findReferences.IsMemberMatch(method, mrr.Member, mrr.IsVirtualCall);
 
850
                        }
 
851
                        
 
852
                        internal override void NavigatorDone(CSharpAstResolver resolver, CancellationToken cancellationToken)
 
853
                        {
 
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));
 
860
                                        }
 
861
                                }
 
862
                                base.NavigatorDone(resolver, cancellationToken);
 
863
                        }
 
864
                }
 
865
                #endregion
 
866
                
 
867
                #region Find Indexer References
 
868
                SearchScope FindIndexerReferences(IProperty indexer)
 
869
                {
 
870
                        return new SearchScope(
 
871
                                delegate (ICompilation compilation) {
 
872
                                        IProperty imported = compilation.Import(indexer);
 
873
                                        if (imported != null)
 
874
                                                return new FindIndexerReferencesNavigator(imported);
 
875
                                        else
 
876
                                                return null;
 
877
                                });
 
878
                }
 
879
                
 
880
                sealed class FindIndexerReferencesNavigator : FindReferenceNavigator
 
881
                {
 
882
                        readonly IProperty indexer;
 
883
                        
 
884
                        public FindIndexerReferencesNavigator(IProperty indexer)
 
885
                        {
 
886
                                this.indexer = indexer;
 
887
                        }
 
888
                        
 
889
                        internal override bool CanMatch(AstNode node)
 
890
                        {
 
891
                                return node is IndexerExpression || node is IndexerDeclaration;
 
892
                        }
 
893
                        
 
894
                        internal override bool IsMatch(ResolveResult rr)
 
895
                        {
 
896
                                MemberResolveResult mrr = rr as MemberResolveResult;
 
897
                                return mrr != null && findReferences.IsMemberMatch(indexer, mrr.Member, mrr.IsVirtualCall);
 
898
                        }
 
899
                }
 
900
                #endregion
 
901
                
 
902
                #region Find Operator References
 
903
                SearchScope GetSearchScopeForOperator(IMethod op)
 
904
                {
 
905
                        OperatorType? opType = OperatorDeclaration.GetOperatorType(op.Name);
 
906
                        if (opType == null)
 
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));
 
963
                                default:
 
964
                                        throw new InvalidOperationException("Invalid value for OperatorType");
 
965
                        }
 
966
                }
 
967
                
 
968
                SearchScope FindOperator(IMethod op, Func<IMethod, FindReferenceNavigator> factory)
 
969
                {
 
970
                        return new SearchScope(
 
971
                                delegate (ICompilation compilation) {
 
972
                                        IMethod imported = compilation.Import(op);
 
973
                                        return imported != null ? factory(imported) : null;
 
974
                                });
 
975
                }
 
976
                
 
977
                SearchScope FindUnaryOperator(IMethod op, UnaryOperatorType operatorType)
 
978
                {
 
979
                        return FindOperator(op, m => new FindUnaryOperatorNavigator(m, operatorType));
 
980
                }
 
981
                
 
982
                sealed class FindUnaryOperatorNavigator : FindReferenceNavigator
 
983
                {
 
984
                        readonly IMethod op;
 
985
                        readonly UnaryOperatorType operatorType;
 
986
                        
 
987
                        public FindUnaryOperatorNavigator(IMethod op, UnaryOperatorType operatorType)
 
988
                        {
 
989
                                this.op = op;
 
990
                                this.operatorType = operatorType;
 
991
                        }
 
992
                        
 
993
                        internal override bool CanMatch(AstNode node)
 
994
                        {
 
995
                                UnaryOperatorExpression uoe = node as UnaryOperatorExpression;
 
996
                                if (uoe != null) {
 
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;
 
1001
                                        else
 
1002
                                                return uoe.Operator == operatorType;
 
1003
                                }
 
1004
                                return node is OperatorDeclaration;
 
1005
                        }
 
1006
                        
 
1007
                        internal override bool IsMatch(ResolveResult rr)
 
1008
                        {
 
1009
                                MemberResolveResult mrr = rr as MemberResolveResult;
 
1010
                                return mrr != null && findReferences.IsMemberMatch(op, mrr.Member, mrr.IsVirtualCall);
 
1011
                        }
 
1012
                }
 
1013
                
 
1014
                SearchScope FindBinaryOperator(IMethod op, BinaryOperatorType operatorType)
 
1015
                {
 
1016
                        return FindOperator(op, m => new FindBinaryOperatorNavigator(m, operatorType));
 
1017
                }
 
1018
                
 
1019
                sealed class FindBinaryOperatorNavigator : FindReferenceNavigator
 
1020
                {
 
1021
                        readonly IMethod op;
 
1022
                        readonly BinaryOperatorType operatorType;
 
1023
                        
 
1024
                        public FindBinaryOperatorNavigator(IMethod op, BinaryOperatorType operatorType)
 
1025
                        {
 
1026
                                this.op = op;
 
1027
                                this.operatorType = operatorType;
 
1028
                        }
 
1029
                        
 
1030
                        internal override bool CanMatch(AstNode node)
 
1031
                        {
 
1032
                                BinaryOperatorExpression boe = node as BinaryOperatorExpression;
 
1033
                                if (boe != null) {
 
1034
                                        return boe.Operator == operatorType;
 
1035
                                }
 
1036
                                return node is OperatorDeclaration;
 
1037
                        }
 
1038
                        
 
1039
                        internal override bool IsMatch(ResolveResult rr)
 
1040
                        {
 
1041
                                MemberResolveResult mrr = rr as MemberResolveResult;
 
1042
                                return mrr != null && findReferences.IsMemberMatch(op, mrr.Member, mrr.IsVirtualCall);
 
1043
                        }
 
1044
                }
 
1045
                
 
1046
                sealed class FindImplicitOperatorNavigator : FindReferenceNavigator
 
1047
                {
 
1048
                        readonly IMethod op;
 
1049
                        
 
1050
                        public FindImplicitOperatorNavigator(IMethod op)
 
1051
                        {
 
1052
                                this.op = op;
 
1053
                        }
 
1054
                        
 
1055
                        internal override bool CanMatch(AstNode node)
 
1056
                        {
 
1057
                                return true;
 
1058
                        }
 
1059
                        
 
1060
                        internal override bool IsMatch(ResolveResult rr)
 
1061
                        {
 
1062
                                MemberResolveResult mrr = rr as MemberResolveResult;
 
1063
                                return mrr != null && findReferences.IsMemberMatch(op, mrr.Member, mrr.IsVirtualCall);
 
1064
                        }
 
1065
                        
 
1066
                        public override void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
 
1067
                        {
 
1068
                                if (conversion.IsUserDefined && findReferences.IsMemberMatch(op, conversion.Method, conversion.IsVirtualMethodLookup)) {
 
1069
                                        ReportMatch(expression, result);
 
1070
                                }
 
1071
                        }
 
1072
                }
 
1073
                
 
1074
                sealed class FindExplicitOperatorNavigator : FindReferenceNavigator
 
1075
                {
 
1076
                        readonly IMethod op;
 
1077
                        
 
1078
                        public FindExplicitOperatorNavigator(IMethod op)
 
1079
                        {
 
1080
                                this.op = op;
 
1081
                        }
 
1082
                        
 
1083
                        internal override bool CanMatch(AstNode node)
 
1084
                        {
 
1085
                                return node is CastExpression;
 
1086
                        }
 
1087
                        
 
1088
                        internal override bool IsMatch(ResolveResult rr)
 
1089
                        {
 
1090
                                ConversionResolveResult crr = rr as ConversionResolveResult;
 
1091
                                return crr != null && crr.Conversion.IsUserDefined 
 
1092
                                        && findReferences.IsMemberMatch(op, crr.Conversion.Method, crr.Conversion.IsVirtualMethodLookup);
 
1093
                        }
 
1094
                }
 
1095
                #endregion
 
1096
                
 
1097
                #region Find Constructor References
 
1098
                SearchScope FindObjectCreateReferences(IMethod ctor)
 
1099
                {
 
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
 
1106
                                        searchTerm = null;
 
1107
                                }
 
1108
                        }
 
1109
                        return new SearchScope(
 
1110
                                searchTerm,
 
1111
                                delegate (ICompilation compilation) {
 
1112
                                        IMethod imported = compilation.Import(ctor);
 
1113
                                        if (imported != null)
 
1114
                                                return new FindObjectCreateReferencesNavigator(imported);
 
1115
                                        else
 
1116
                                                return null;
 
1117
                                });
 
1118
                }
 
1119
                
 
1120
                sealed class FindObjectCreateReferencesNavigator : FindReferenceNavigator
 
1121
                {
 
1122
                        readonly IMethod ctor;
 
1123
                        
 
1124
                        public FindObjectCreateReferencesNavigator(IMethod ctor)
 
1125
                        {
 
1126
                                this.ctor = ctor;
 
1127
                        }
 
1128
                        
 
1129
                        internal override bool CanMatch(AstNode node)
 
1130
                        {
 
1131
                                return node is ObjectCreateExpression || node is ConstructorDeclaration || node is Attribute;
 
1132
                        }
 
1133
                        
 
1134
                        internal override bool IsMatch(ResolveResult rr)
 
1135
                        {
 
1136
                                MemberResolveResult mrr = rr as MemberResolveResult;
 
1137
                                return mrr != null && findReferences.IsMemberMatch(ctor, mrr.Member, mrr.IsVirtualCall);
 
1138
                        }
 
1139
                }
 
1140
                
 
1141
                SearchScope FindChainedConstructorReferences(IMethod ctor)
 
1142
                {
 
1143
                        SearchScope searchScope = new SearchScope(
 
1144
                                delegate (ICompilation compilation) {
 
1145
                                        IMethod imported = compilation.Import(ctor);
 
1146
                                        if (imported != null)
 
1147
                                                return new FindChainedConstructorReferencesNavigator(imported);
 
1148
                                        else
 
1149
                                                return null;
 
1150
                                });
 
1151
                        if (ctor.DeclaringTypeDefinition.IsSealed)
 
1152
                                searchScope.accessibility = Accessibility.Private;
 
1153
                        else
 
1154
                                searchScope.accessibility = Accessibility.Protected;
 
1155
                        searchScope.accessibility = MergeAccessibility(GetEffectiveAccessibility(ctor), searchScope.accessibility);
 
1156
                        return searchScope;
 
1157
                }
 
1158
                
 
1159
                sealed class FindChainedConstructorReferencesNavigator : FindReferenceNavigator
 
1160
                {
 
1161
                        readonly IMethod ctor;
 
1162
                        
 
1163
                        public FindChainedConstructorReferencesNavigator(IMethod ctor)
 
1164
                        {
 
1165
                                this.ctor = ctor;
 
1166
                        }
 
1167
                        
 
1168
                        internal override bool CanMatch(AstNode node)
 
1169
                        {
 
1170
                                return node is ConstructorInitializer;
 
1171
                        }
 
1172
                        
 
1173
                        internal override bool IsMatch(ResolveResult rr)
 
1174
                        {
 
1175
                                MemberResolveResult mrr = rr as MemberResolveResult;
 
1176
                                return mrr != null && findReferences.IsMemberMatch(ctor, mrr.Member, mrr.IsVirtualCall);
 
1177
                        }
 
1178
                }
 
1179
                #endregion
 
1180
                
 
1181
                #region Find Destructor References
 
1182
                SearchScope GetSearchScopeForDestructor(IMethod dtor)
 
1183
                {
 
1184
                        var scope = new SearchScope (
 
1185
                                delegate (ICompilation compilation) {
 
1186
                                        IMethod imported = compilation.Import(dtor);
 
1187
                                        if (imported != null) {
 
1188
                                                return new FindDestructorReferencesNavigator (imported);
 
1189
                                        } else {
 
1190
                                                return null;
 
1191
                                        }
 
1192
                                });
 
1193
                        scope.accessibility = Accessibility.Private;
 
1194
                        return scope;
 
1195
                }
 
1196
                
 
1197
                sealed class FindDestructorReferencesNavigator : FindReferenceNavigator
 
1198
                {
 
1199
                        readonly IMethod dtor;
 
1200
                        
 
1201
                        public FindDestructorReferencesNavigator (IMethod dtor)
 
1202
                        {
 
1203
                                this.dtor = dtor;
 
1204
                        }
 
1205
                        
 
1206
                        internal override bool CanMatch(AstNode node)
 
1207
                        {
 
1208
                                return node is DestructorDeclaration;
 
1209
                        }
 
1210
                        
 
1211
                        internal override bool IsMatch(ResolveResult rr)
 
1212
                        {
 
1213
                                MemberResolveResult mrr = rr as MemberResolveResult;
 
1214
                                return mrr != null && findReferences.IsMemberMatch(dtor, mrr.Member, mrr.IsVirtualCall);
 
1215
                        }
 
1216
                }
 
1217
                #endregion
 
1218
 
 
1219
                #region Find Local Variable References
 
1220
                /// <summary>
 
1221
                /// Finds all references of a given variable.
 
1222
                /// </summary>
 
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)
 
1231
                {
 
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);
 
1237
                }
 
1238
                
 
1239
                class FindLocalReferencesNavigator : FindReferenceNavigator
 
1240
                {
 
1241
                        readonly IVariable variable;
 
1242
                        
 
1243
                        public FindLocalReferencesNavigator(IVariable variable)
 
1244
                        {
 
1245
                                this.variable = variable;
 
1246
                        }
 
1247
                        
 
1248
                        internal override bool CanMatch(AstNode node)
 
1249
                        {
 
1250
                                var expr = node as IdentifierExpression;
 
1251
                                if (expr != null)
 
1252
                                        return expr.TypeArguments.Count == 0 && variable.Name == expr.Identifier;
 
1253
                                var vi = node as VariableInitializer;
 
1254
                                if (vi != null)
 
1255
                                        return vi.Name == variable.Name;
 
1256
                                var pd = node as ParameterDeclaration;
 
1257
                                if (pd != null)
 
1258
                                        return pd.Name == variable.Name;
 
1259
                                var id = node as Identifier;
 
1260
                                if (id != null)
 
1261
                                        return id.Name == variable.Name;
 
1262
                                return false;
 
1263
                        }
 
1264
                        
 
1265
                        internal override bool IsMatch(ResolveResult rr)
 
1266
                        {
 
1267
                                var lrr = rr as LocalResolveResult;
 
1268
                                return lrr != null && lrr.Variable.Name == variable.Name && lrr.Variable.Region == variable.Region;
 
1269
                        }
 
1270
                }
 
1271
                #endregion
 
1272
 
 
1273
                #region Find Type Parameter References
 
1274
                /// <summary>
 
1275
                /// Finds all references of a given type parameter.
 
1276
                /// </summary>
 
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)
 
1285
                {
 
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);
 
1294
                }
 
1295
                
 
1296
                class FindTypeParameterReferencesNavigator : FindReferenceNavigator
 
1297
                {
 
1298
                        readonly ITypeParameter typeParameter;
 
1299
                        
 
1300
                        public FindTypeParameterReferencesNavigator(ITypeParameter typeParameter)
 
1301
                        {
 
1302
                                this.typeParameter = typeParameter;
 
1303
                        }
 
1304
                        
 
1305
                        internal override bool CanMatch(AstNode node)
 
1306
                        {
 
1307
                                var type = node as SimpleType;
 
1308
                                if (type != null)
 
1309
                                        return type.Identifier == typeParameter.Name;
 
1310
                                var declaration = node as TypeParameterDeclaration;
 
1311
                                if (declaration != null)
 
1312
                                        return declaration.Name == typeParameter.Name;
 
1313
                                return false;
 
1314
                        }
 
1315
                        
 
1316
                        internal override bool IsMatch(ResolveResult rr)
 
1317
                        {
 
1318
                                var lrr = rr as TypeResolveResult;
 
1319
                                return lrr != null && lrr.Type.Kind == TypeKind.TypeParameter && ((ITypeParameter)lrr.Type).Region == typeParameter.Region;
 
1320
                        }
 
1321
                }
 
1322
                #endregion
 
1323
        
 
1324
                #region Find Namespace References
 
1325
                SearchScope GetSearchScopeForNamespace(INamespace ns)
 
1326
                {
 
1327
                        var scope = new SearchScope (
 
1328
                                delegate (ICompilation compilation) {
 
1329
                                return new FindNamespaceNavigator (ns);
 
1330
                        }
 
1331
                        );
 
1332
                        return scope;
 
1333
                }
 
1334
 
 
1335
                sealed class FindNamespaceNavigator : FindReferenceNavigator
 
1336
                {
 
1337
                        readonly INamespace ns;
 
1338
 
 
1339
                        public FindNamespaceNavigator (INamespace ns)
 
1340
                        {
 
1341
                                this.ns = ns;
 
1342
                        }
 
1343
 
 
1344
                        internal override bool CanMatch(AstNode node)
 
1345
                        {
 
1346
                                var nsd = node as NamespaceDeclaration;
 
1347
                                if (nsd != null && nsd.FullName.StartsWith(ns.FullName, StringComparison.Ordinal))
 
1348
                                        return true;
 
1349
 
 
1350
                                var ud = node as UsingDeclaration;
 
1351
                                if (ud != null && ud.Namespace == ns.FullName)
 
1352
                                        return true;
 
1353
 
 
1354
                                var st = node as SimpleType;
 
1355
                                if (st != null && st.Identifier == ns.Name)
 
1356
                                        return true;
 
1357
 
 
1358
                                var mt = node as MemberType;
 
1359
                                if (mt != null && mt.MemberName == ns.Name)
 
1360
                                        return true;
 
1361
 
 
1362
                                var identifer = node as IdentifierExpression;
 
1363
                                if (identifer != null && identifer.Identifier == ns.Name)
 
1364
                                        return true;
 
1365
 
 
1366
                                var mrr = node as MemberReferenceExpression;
 
1367
                                if (mrr != null && mrr.MemberName == ns.Name)
 
1368
                                        return true;
 
1369
 
 
1370
 
 
1371
                                return false;
 
1372
                        }
 
1373
 
 
1374
                        internal override bool IsMatch(ResolveResult rr)
 
1375
                        {
 
1376
                                var nsrr = rr as NamespaceResolveResult;
 
1377
                                return nsrr != null && nsrr.NamespaceName.StartsWith(ns.FullName, StringComparison.Ordinal);
 
1378
                        }
 
1379
                }
 
1380
                #endregion
 
1381
        }
 
1382
}