diff --git a/src/Workspaces/Core/Portable/FindSymbols/Extensions.cs b/src/Workspaces/Core/Portable/FindSymbols/Extensions.cs index c0b65eacaea36bc6346c00e183c48e756e22eaed..063807e396852d58101c7c4ec36e13e13ba18780 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/Extensions.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/Extensions.cs @@ -28,35 +28,6 @@ public static async Task> GetConstructorInitializerToke return FindReferenceCache.GetConstructorInitializerTokens(syntaxFacts, model, root, cancellationToken); } - internal static async Task> GetIdentifierOrGlobalNamespaceTokensWithTextAsync( - this Document document, SemanticModel model, string identifier, CancellationToken cancellationToken) - { - // It's very costly to walk an entire tree. So if the tree is simple and doesn't contain - // any unicode escapes in it, then we do simple string matching to find the tokens. - var info = await SyntaxTreeIndex.GetIndexAsync(document, cancellationToken).ConfigureAwait(false); - if (!info.ProbablyContainsIdentifier(identifier)) - { - return ImmutableArray.Empty; - } - - var syntaxFacts = document.GetLanguageService(); - if (syntaxFacts == null) - { - return ImmutableArray.Empty; - } - - var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); - var version = await document.GetSyntaxVersionAsync(cancellationToken).ConfigureAwait(false); - - SourceText text = null; - if (!info.ProbablyContainsEscapedIdentifier(identifier)) - { - text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - } - - return FindReferenceCache.GetIdentifierOrGlobalNamespaceTokensWithText(syntaxFacts, document, version, model, root, text, identifier, cancellationToken); - } - internal static bool TextMatch(this ISyntaxFactsService syntaxFacts, string text1, string text2) => syntaxFacts.StringComparer.Equals(text1, text2); } diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferenceCache.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferenceCache.cs index 2b4c8ec92d7f3cd9a47dc7dea19703e9c0af255c..a579c38b462473e6e9df7a288e75b17de37008b0 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferenceCache.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferenceCache.cs @@ -62,8 +62,14 @@ public static SymbolInfo GetSymbolInfo(SemanticModel model, SyntaxNode node, Can } public static ImmutableArray GetIdentifierOrGlobalNamespaceTokensWithText( - ISyntaxFactsService syntaxFacts, Document document, VersionStamp version, SemanticModel model, SyntaxNode root, SourceText sourceText, - string text, CancellationToken cancellationToken) + ISyntaxFactsService syntaxFacts, + Document document, + VersionStamp version, + SemanticModel model, + SyntaxNode root, + SourceText sourceText, + string text, + CancellationToken cancellationToken) { var normalized = syntaxFacts.IsCaseSensitive ? text : text.ToLowerInvariant(); @@ -82,17 +88,17 @@ public static SymbolInfo GetSymbolInfo(SemanticModel model, SyntaxNode node, Can ISyntaxFactsService syntaxFacts, Document document, VersionStamp version, SyntaxNode root, SourceText sourceText, string text, CancellationToken cancellationToken) { - bool candidate(SyntaxToken t) => - syntaxFacts.IsGlobalNamespaceKeyword(t) || (syntaxFacts.IsIdentifier(t) && syntaxFacts.TextMatch(t.ValueText, text)); - // identifier is not escaped if (sourceText != null) { - return GetTokensFromText(syntaxFacts, document, version, root, sourceText, text, candidate, cancellationToken); + return GetTokensFromText(syntaxFacts, document, version, root, sourceText, text, IsCandidate, cancellationToken); } // identifier is escaped - return root.DescendantTokens(descendIntoTrivia: true).Where(candidate).ToImmutableArray(); + return root.DescendantTokens(descendIntoTrivia: true).Where(IsCandidate).ToImmutableArray(); + + bool IsCandidate(SyntaxToken t) + => syntaxFacts.IsGlobalNamespaceKeyword(t) || (syntaxFacts.IsIdentifier(t) && syntaxFacts.TextMatch(t.ValueText, text)); } private static ImmutableArray GetTokensFromText( diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractReferenceFinder.cs index f98f5709fc2beef3f87efd341f4ba5eb4bc9eaef..d5e126746c80303162c07d7a7b73321d7a2e3ba2 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractReferenceFinder.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindSymbols.Finders @@ -167,7 +168,7 @@ protected static bool IdentifiersMatch(ISyntaxFactsService syntaxFacts, string n Func symbolsMatch, CancellationToken cancellationToken) { - var tokens = await document.GetIdentifierOrGlobalNamespaceTokensWithTextAsync(semanticModel, identifier, cancellationToken).ConfigureAwait(false); + var tokens = await GetIdentifierOrGlobalNamespaceTokensWithTextAsync(document, semanticModel, identifier, cancellationToken).ConfigureAwait(false); var syntaxFacts = document.GetLanguageService(); @@ -180,6 +181,29 @@ protected static bool IdentifiersMatch(ISyntaxFactsService syntaxFacts, string n cancellationToken); } + protected static async Task> GetIdentifierOrGlobalNamespaceTokensWithTextAsync(Document document, SemanticModel semanticModel, string identifier, CancellationToken cancellationToken) + { + // It's very costly to walk an entire tree. So if the tree is simple and doesn't contain + // any unicode escapes in it, then we do simple string matching to find the tokens. + var info = await SyntaxTreeIndex.GetIndexAsync(document, cancellationToken).ConfigureAwait(false); + if (!info.ProbablyContainsIdentifier(identifier)) + return ImmutableArray.Empty; + + var syntaxFacts = document.GetLanguageService(); + if (syntaxFacts == null) + return ImmutableArray.Empty; + + var root = await semanticModel.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); + var version = await document.GetSyntaxVersionAsync(cancellationToken).ConfigureAwait(false); + + SourceText text = null; + if (!info.ProbablyContainsEscapedIdentifier(identifier)) + text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + + return FindReferenceCache.GetIdentifierOrGlobalNamespaceTokensWithText( + syntaxFacts, document, version, semanticModel, root, text, identifier, cancellationToken); + } + protected static Func GetStandardSymbolsMatchFunction( ISymbol symbol, Func findParentNode, Solution solution, CancellationToken cancellationToken) { diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorInitializerSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorInitializerSymbolReferenceFinder.cs index 44e70b5c19cd4b930419cf585e525db116f3f55f..ce5d5d68309928004a9fdb84f56bcc01430d28ae 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorInitializerSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorInitializerSymbolReferenceFinder.cs @@ -62,7 +62,8 @@ protected override bool CanFind(IMethodSymbol symbol) var tokens = await document.GetConstructorInitializerTokensAsync(semanticModel, cancellationToken).ConfigureAwait(false); if (semanticModel.Language == LanguageNames.VisualBasic) { - tokens = tokens.Concat(await document.GetIdentifierOrGlobalNamespaceTokensWithTextAsync(semanticModel, "New", cancellationToken).ConfigureAwait(false)).Distinct(); + tokens = tokens.Concat(await GetIdentifierOrGlobalNamespaceTokensWithTextAsync( + document, semanticModel, "New", cancellationToken).ConfigureAwait(false)).Distinct(); } return FindReferencesInTokens( diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/NamespaceSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/NamespaceSymbolReferenceFinder.cs index 4864a11582a0fadf49155566443d2d14f38fe7d0..735d78b4c5e9a6411e301603735626c794eec891 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/NamespaceSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/NamespaceSymbolReferenceFinder.cs @@ -44,11 +44,13 @@ private static string GetNamespaceIdentifierName(INamespaceSymbol symbol) var identifierName = GetNamespaceIdentifierName(symbol); var syntaxFactsService = document.GetLanguageService(); + var tokens = await GetIdentifierOrGlobalNamespaceTokensWithTextAsync( + document, semanticModel, identifierName, cancellationToken).ConfigureAwait(false); var nonAliasReferences = FindReferencesInTokens(symbol, document, semanticModel, - await document.GetIdentifierOrGlobalNamespaceTokensWithTextAsync(semanticModel, identifierName, cancellationToken).ConfigureAwait(false), - (SyntaxToken t) => syntaxFactsService.TextMatch(t.ValueText, identifierName), + tokens, + t => syntaxFactsService.TextMatch(t.ValueText, identifierName), cancellationToken); var aliasReferences = await FindAliasReferencesAsync(nonAliasReferences, symbol, document, semanticModel, cancellationToken).ConfigureAwait(false);