| File: FindSymbols\FindReferences\Finders\ExplicitConversionSymbolReferenceFinder.cs | Web Access |
| Project: src\roslyn\src\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj (Microsoft.CodeAnalysis.Workspaces) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindSymbols.Finders; internal sealed partial class ExplicitConversionSymbolReferenceFinder : AbstractMethodOrPropertyOrEventSymbolReferenceFinder<IMethodSymbol> { protected override bool CanFind(IMethodSymbol symbol) => symbol is { MethodKind: MethodKind.Conversion, Name: WellKnownMemberNames.ExplicitConversionName or WellKnownMemberNames.ImplicitConversionName } && GetUnderlyingNamedType(symbol.ReturnType) is not null; private static INamedTypeSymbol? GetUnderlyingNamedType(ITypeSymbol symbol) => UnderlyingNamedTypeVisitor.Instance.Visit(symbol); protected sealed override async Task DetermineDocumentsToSearchAsync<TData>( IMethodSymbol symbol, HashSet<string>? globalAliases, Project project, IImmutableSet<Document>? documents, Action<Document, TData> processResult, TData processResultData, FindReferencesSearchOptions options, CancellationToken cancellationToken) { // Look for documents that both contain an explicit cast in them as well as a reference to the type in the // explicit conversion. i.e. if we have `public static explicit operator Goo(Bar b);` we want to find files // both with `Goo` `and `(...)` in them as we're looking for cases of `(Goo)...`. // // Note that explicit conversions may be to complex types (like arrays). For example: // // public static explicit operator Goo[](Bar b); // // So we need to find the underlying named type `Goo` (if there is one) to find references. var underlyingNamedType = GetUnderlyingNamedType(symbol.ReturnType); Contract.ThrowIfNull(underlyingNamedType); using var _ = PooledHashSet<Document>.GetInstance(out var result); await FindDocumentsAsync(project, documents, StandardCallbacks<Document>.AddToHashSet, result, cancellationToken, underlyingNamedType.Name).ConfigureAwait(false); await FindDocumentsAsync(project, documents, underlyingNamedType.SpecialType.ToPredefinedType(), StandardCallbacks<Document>.AddToHashSet, result, cancellationToken).ConfigureAwait(false); // Ignore any documents that don't also have an explicit cast in them. foreach (var document in result) { var index = await SyntaxTreeIndex.GetRequiredIndexAsync(document, cancellationToken).ConfigureAwait(false); if (index.ContainsConversion) processResult(document, processResultData); } } protected sealed override void FindReferencesInDocument<TData>( IMethodSymbol symbol, FindReferencesDocumentState state, Action<FinderLocation, TData> processResult, TData processResultData, FindReferencesSearchOptions options, CancellationToken cancellationToken) { var tokens = state.Root .DescendantTokens(descendIntoTrivia: true) .WhereAsArray( static (token, state) => IsPotentialReference(state.SyntaxFacts, token), state); FindReferencesInTokens(symbol, state, tokens, processResult, processResultData, cancellationToken); } private static bool IsPotentialReference( ISyntaxFactsService syntaxFacts, SyntaxToken token) { var node = token.GetRequiredParent(); return node.GetFirstToken() == token && syntaxFacts.IsConversionExpression(node); } }