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