diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorSymbolReferenceFinder.cs index 155e4ac7b6039..05dcd0c0dc731 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorSymbolReferenceFinder.cs @@ -98,22 +98,17 @@ protected override void FindReferencesInDocument( CancellationToken cancellationToken) { // First just look for this normal constructor references using the name of it's containing type. - var name = methodSymbol.ContainingType.Name; + var containingType = methodSymbol.ContainingType; + var containingTypeName = containingType.Name; AddReferencesInDocumentWorker( - methodSymbol, name, state, processResult, processResultData, cancellationToken); + methodSymbol, containingTypeName, state, processResult, processResultData, cancellationToken); // Next, look for constructor references through a global alias to our containing type. foreach (var globalAlias in state.GlobalAliases) - { - // ignore the cases where the global alias might match the type name (i.e. - // global alias Console = System.Console). We'll already find those references - // above. - if (state.SyntaxFacts.StringComparer.Equals(name, globalAlias)) - continue; + FindReferenceToAlias(methodSymbol, state, processResult, processResultData, containingTypeName, globalAlias, cancellationToken); - AddReferencesInDocumentWorker( - methodSymbol, globalAlias, state, processResult, processResultData, cancellationToken); - } + foreach (var localAlias in state.Cache.SyntaxTreeIndex.GetAliases(containingTypeName, containingType.Arity)) + FindReferenceToAlias(methodSymbol, state, processResult, processResultData, containingTypeName, localAlias, cancellationToken); // Finally, look for constructor references to predefined types (like `new int()`), // implicit object references, and inside global suppression attributes. @@ -127,6 +122,19 @@ protected override void FindReferencesInDocument( methodSymbol, state, processResult, processResultData, cancellationToken); } + private static void FindReferenceToAlias( + IMethodSymbol methodSymbol, FindReferencesDocumentState state, Action processResult, TData processResultData, string name, string alias, CancellationToken cancellationToken) + { + // ignore the cases where the global alias might match the type name (i.e. + // global alias Console = System.Console). We'll already find those references + // above. + if (state.SyntaxFacts.StringComparer.Equals(name, alias)) + return; + + AddReferencesInDocumentWorker( + methodSymbol, alias, state, processResult, processResultData, cancellationToken); + } + /// /// Finds references to in this , but only if it referenced /// though (which might be the actual name of the type, or a global alias to it). diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/NamedTypeSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/NamedTypeSymbolReferenceFinder.cs index b31c93e3911e6..96d55fd773a1e 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/NamedTypeSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/NamedTypeSymbolReferenceFinder.cs @@ -147,16 +147,23 @@ internal static void AddReferencesToTypeOrGlobalAliasToIt( namedType, namedType.Name, state, processResult, processResultData, cancellationToken); foreach (var globalAlias in state.GlobalAliases) - { - // ignore the cases where the global alias might match the type name (i.e. - // global alias Console = System.Console). We'll already find those references - // above. - if (state.SyntaxFacts.StringComparer.Equals(namedType.Name, globalAlias)) - continue; - - AddNonAliasReferences( - namedType, globalAlias, state, processResult, processResultData, cancellationToken); - } + FindReferenceToAlias(namedType, state, processResult, processResultData, globalAlias, cancellationToken); + + foreach (var localAlias in state.Cache.SyntaxTreeIndex.GetAliases(namedType.Name, namedType.Arity)) + FindReferenceToAlias(namedType, state, processResult, processResultData, localAlias, cancellationToken); + } + + private static void FindReferenceToAlias( + INamedTypeSymbol namedType, FindReferencesDocumentState state, Action processResult, TData processResultData, string alias, CancellationToken cancellationToken) + { + // ignore the cases where the global alias might match the type name (i.e. + // global alias Console = System.Console). We'll already find those references + // above. + if (state.SyntaxFacts.StringComparer.Equals(namedType.Name, alias)) + return; + + AddNonAliasReferences( + namedType, alias, state, processResult, processResultData, cancellationToken); } /// diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/NamespaceSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/NamespaceSymbolReferenceFinder.cs index e7ae12e6af02d..a37a5aa784526 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/NamespaceSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/NamespaceSymbolReferenceFinder.cs @@ -72,16 +72,10 @@ protected override void FindReferencesInDocument( symbol, namespaceName, state, StandardCallbacks.AddToArrayBuilder, initialReferences, cancellationToken); foreach (var globalAlias in state.GlobalAliases) - { - // ignore the cases where the global alias might match the namespace name (i.e. - // global alias Collections = System.Collections). We'll already find those references - // above. - if (state.SyntaxFacts.StringComparer.Equals(namespaceName, globalAlias)) - continue; - - AddNamedReferences( - symbol, globalAlias, state, StandardCallbacks.AddToArrayBuilder, initialReferences, cancellationToken); - } + FindReferenceToAlias(symbol, state, initialReferences, namespaceName, globalAlias, cancellationToken); + + foreach (var localAlias in state.Cache.SyntaxTreeIndex.GetAliases(symbol.Name, arity: 0)) + FindReferenceToAlias(symbol, state, initialReferences, namespaceName, localAlias, cancellationToken); // The items in initialReferences need to be both reported and used later to calculate additional results. foreach (var location in initialReferences) @@ -95,6 +89,19 @@ protected override void FindReferencesInDocument( } } + private static void FindReferenceToAlias( + INamespaceSymbol symbol, FindReferencesDocumentState state, ArrayBuilder initialReferences, string namespaceName, string alias, CancellationToken cancellationToken) + { + // ignore the cases where the global alias might match the namespace name (i.e. + // global alias Collections = System.Collections). We'll already find those references + // above. + if (state.SyntaxFacts.StringComparer.Equals(namespaceName, alias)) + return; + + AddNamedReferences( + symbol, alias, state, StandardCallbacks.AddToArrayBuilder, initialReferences, cancellationToken); + } + /// /// Finds references to in this , but only if it referenced /// though (which might be the actual name of the type, or a global alias to it). diff --git a/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs b/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs index d17056acb7686..aaec84b363045 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs @@ -17,7 +17,13 @@ namespace Microsoft.CodeAnalysis.FindSymbols; internal partial class AbstractSyntaxIndex { private static readonly string s_persistenceName = typeof(TIndex).Name; - private static readonly Checksum s_serializationFormatChecksum = CodeAnalysis.Checksum.Create("39"); + + /// + /// Increment this whenever the data format of the changes. This ensures + /// that we will not try to read previously cached data from a prior version of roslyn with a different format and + /// will instead regenerate all the indices with the new format. + /// + private static readonly Checksum s_serializationFormatChecksum = CodeAnalysis.Checksum.Create("40"); /// /// Cache of ParseOptions to a checksum for the contained diff --git a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.cs b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.cs index 904beb0748f02..c84e77f077d74 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.cs @@ -14,20 +14,20 @@ internal sealed partial class SyntaxTreeIndex : AbstractSyntaxIndex? _globalAliasInfo; + private readonly HashSet<(string alias, string name, int arity, bool isGlobal)>? _aliasInfo; private SyntaxTreeIndex( Checksum? checksum, LiteralInfo literalInfo, IdentifierInfo identifierInfo, ContextInfo contextInfo, - HashSet<(string alias, string name, int arity)>? globalAliasInfo) + HashSet<(string alias, string name, int arity, bool isGlobal)>? aliasInfo) : base(checksum) { _literalInfo = literalInfo; _identifierInfo = identifierInfo; _contextInfo = contextInfo; - _globalAliasInfo = globalAliasInfo; + _aliasInfo = aliasInfo; } public static ValueTask GetRequiredIndexAsync(Document document, CancellationToken cancellationToken) diff --git a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Create.cs b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Create.cs index 6c40ce8a69abc..317788f2e468c 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Create.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Create.cs @@ -47,7 +47,7 @@ private static SyntaxTreeIndex CreateIndex( var stringLiterals = StringLiteralHashSetPool.Allocate(); var longLiterals = LongLiteralHashSetPool.Allocate(); - HashSet<(string alias, string name, int arity)>? globalAliasInfo = null; + HashSet<(string alias, string name, int arity, bool isGlobal)>? aliasInfo = null; try { @@ -98,7 +98,7 @@ private static SyntaxTreeIndex CreateIndex( containsConversion = containsConversion || syntaxFacts.IsConversionExpression(node); containsCollectionInitializer = containsCollectionInitializer || syntaxFacts.IsObjectCollectionInitializer(node); - TryAddGlobalAliasInfo(syntaxFacts, ref globalAliasInfo, node); + TryAddAliasInfo(syntaxFacts, ref aliasInfo, node); } else { @@ -186,7 +186,7 @@ private static SyntaxTreeIndex CreateIndex( containsConversion, containsGlobalKeyword, containsCollectionInitializer), - globalAliasInfo); + aliasInfo); } finally { @@ -219,17 +219,15 @@ private static bool IsGlobalSuppressMessageAttribute(ISyntaxFactsService syntaxF syntaxFacts.StringComparer.Equals(identifierName, nameof(SuppressMessageAttribute)); } - private static void TryAddGlobalAliasInfo( + private static void TryAddAliasInfo( ISyntaxFactsService syntaxFacts, - ref HashSet<(string alias, string name, int arity)>? globalAliasInfo, + ref HashSet<(string alias, string name, int arity, bool isGlobal)>? aliasInfo, SyntaxNode node) { if (!syntaxFacts.IsUsingAliasDirective(node)) return; syntaxFacts.GetPartsOfUsingAliasDirective(node, out var globalToken, out var alias, out var usingTarget); - if (globalToken.IsMissing) - return; // if we have `global using X = Y.Z` then walk down the rhs to pull out 'Z'. if (syntaxFacts.IsQualifiedName(usingTarget)) @@ -242,8 +240,9 @@ private static void TryAddGlobalAliasInfo( if (syntaxFacts.IsSimpleName(usingTarget)) { syntaxFacts.GetNameAndArityOfSimpleName(usingTarget, out var name, out var arity); - globalAliasInfo ??= []; - globalAliasInfo.Add((alias.ValueText, name, arity)); + + aliasInfo ??= []; + aliasInfo.Add((alias.ValueText, name, arity, isGlobal: globalToken != default)); } } diff --git a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Forwarders.cs b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Forwarders.cs index 9bd7ec22026ca..787df4cc554e7 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Forwarders.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Forwarders.cs @@ -42,15 +42,22 @@ internal sealed partial class SyntaxTreeIndex /// name="C" and arity=1 will return X. /// public ImmutableArray GetGlobalAliases(string name, int arity) + => GetAliasesWorker(name, arity, isGlobal: true); + + public ImmutableArray GetAliases(string name, int arity) + => GetAliasesWorker(name, arity, isGlobal: false); + + private ImmutableArray GetAliasesWorker( + string name, int arity, bool isGlobal) { - if (_globalAliasInfo == null) + if (_aliasInfo == null) return []; using var result = TemporaryArray.Empty; - foreach (var (alias, aliasName, aliasArity) in _globalAliasInfo) + foreach (var (alias, aliasName, aliasArity, aliasIsGlobal) in _aliasInfo) { - if (aliasName == name && aliasArity == arity) + if (aliasIsGlobal == isGlobal && aliasArity == arity && aliasName == name) result.Add(alias); } diff --git a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Persistence.cs b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Persistence.cs index 9a6c08ffca80a..162867421cee7 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Persistence.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Persistence.cs @@ -25,18 +25,15 @@ public override void WriteTo(ObjectWriter writer) _identifierInfo.WriteTo(writer); _contextInfo.WriteTo(writer); - if (_globalAliasInfo == null) + writer.WriteInt32(_aliasInfo?.Count ?? 0); + if (_aliasInfo != null) { - writer.WriteInt32(0); - } - else - { - writer.WriteInt32(_globalAliasInfo.Count); - foreach (var (alias, name, arity) in _globalAliasInfo) + foreach (var (alias, name, arity, isGlobal) in _aliasInfo) { writer.WriteString(alias); writer.WriteString(name); writer.WriteInt32(arity); + writer.WriteBoolean(isGlobal); } } } @@ -51,19 +48,20 @@ public override void WriteTo(ObjectWriter writer) if (literalInfo == null || identifierInfo == null || contextInfo == null) return null; - var globalAliasInfoCount = reader.ReadInt32(); - HashSet<(string alias, string name, int arity)>? globalAliasInfo = null; + var aliasInfoCount = reader.ReadInt32(); + HashSet<(string alias, string name, int arity, bool isGlobal)>? aliasInfo = null; - if (globalAliasInfoCount > 0) + if (aliasInfoCount > 0) { - globalAliasInfo = []; + aliasInfo = []; - for (var i = 0; i < globalAliasInfoCount; i++) + for (var i = 0; i < aliasInfoCount; i++) { - var alias = reader.ReadRequiredString(); - var name = reader.ReadRequiredString(); - var arity = reader.ReadInt32(); - globalAliasInfo.Add((alias, name, arity)); + aliasInfo.Add(( + reader.ReadRequiredString(), + reader.ReadRequiredString(), + reader.ReadInt32(), + reader.ReadBoolean())); } } @@ -72,6 +70,6 @@ public override void WriteTo(ObjectWriter writer) literalInfo.Value, identifierInfo.Value, contextInfo.Value, - globalAliasInfo); + aliasInfo); } }