Skip to content

Commit

Permalink
Merge pull request #74015 from CyrusNajmabadi/indices
Browse files Browse the repository at this point in the history
Fix find refs doing too much work lookign for types that had an alias to them in one file.
  • Loading branch information
CyrusNajmabadi authored Jun 16, 2024
2 parents 0d03b2e + f7d3357 commit 9d5e375
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,22 +98,17 @@ protected override void FindReferencesInDocument<TData>(
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.
Expand All @@ -127,6 +122,19 @@ protected override void FindReferencesInDocument<TData>(
methodSymbol, state, processResult, processResultData, cancellationToken);
}

private static void FindReferenceToAlias<TData>(
IMethodSymbol methodSymbol, FindReferencesDocumentState state, Action<FinderLocation, TData> 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);
}

/// <summary>
/// Finds references to <paramref name="symbol"/> in this <paramref name="state"/>, but only if it referenced
/// though <paramref name="name"/> (which might be the actual name of the type, or a global alias to it).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,16 +147,23 @@ internal static void AddReferencesToTypeOrGlobalAliasToIt<TData>(
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<TData>(
INamedTypeSymbol namedType, FindReferencesDocumentState state, Action<FinderLocation, TData> 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);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,10 @@ protected override void FindReferencesInDocument<TData>(
symbol, namespaceName, state, StandardCallbacks<FinderLocation>.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<FinderLocation>.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)
Expand All @@ -95,6 +89,19 @@ protected override void FindReferencesInDocument<TData>(
}
}

private static void FindReferenceToAlias(
INamespaceSymbol symbol, FindReferencesDocumentState state, ArrayBuilder<FinderLocation> 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<FinderLocation>.AddToArrayBuilder, initialReferences, cancellationToken);
}

/// <summary>
/// Finds references to <paramref name="symbol"/> in this <paramref name="state"/>, but only if it referenced
/// though <paramref name="name"/> (which might be the actual name of the type, or a global alias to it).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ namespace Microsoft.CodeAnalysis.FindSymbols;
internal partial class AbstractSyntaxIndex<TIndex>
{
private static readonly string s_persistenceName = typeof(TIndex).Name;
private static readonly Checksum s_serializationFormatChecksum = CodeAnalysis.Checksum.Create("39");

/// <summary>
/// Increment this whenever the data format of the <see cref="AbstractSyntaxIndex{TIndex}"/> 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.
/// </summary>
private static readonly Checksum s_serializationFormatChecksum = CodeAnalysis.Checksum.Create("40");

/// <summary>
/// Cache of ParseOptions to a checksum for the <see cref="ParseOptions.PreprocessorSymbolNames"/> contained
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,20 @@ internal sealed partial class SyntaxTreeIndex : AbstractSyntaxIndex<SyntaxTreeIn
private readonly LiteralInfo _literalInfo;
private readonly IdentifierInfo _identifierInfo;
private readonly ContextInfo _contextInfo;
private readonly HashSet<(string alias, string name, int arity)>? _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<SyntaxTreeIndex> GetRequiredIndexAsync(Document document, CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -186,7 +186,7 @@ private static SyntaxTreeIndex CreateIndex(
containsConversion,
containsGlobalKeyword,
containsCollectionInitializer),
globalAliasInfo);
aliasInfo);
}
finally
{
Expand Down Expand Up @@ -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))
Expand All @@ -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));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,22 @@ internal sealed partial class SyntaxTreeIndex
/// <c>name="C"</c> and arity=1 will return <c>X</c>.
/// </summary>
public ImmutableArray<string> GetGlobalAliases(string name, int arity)
=> GetAliasesWorker(name, arity, isGlobal: true);

public ImmutableArray<string> GetAliases(string name, int arity)
=> GetAliasesWorker(name, arity, isGlobal: false);

private ImmutableArray<string> GetAliasesWorker(
string name, int arity, bool isGlobal)
{
if (_globalAliasInfo == null)
if (_aliasInfo == null)
return [];

using var result = TemporaryArray<string>.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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
Expand All @@ -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()));
}
}

Expand All @@ -72,6 +70,6 @@ public override void WriteTo(ObjectWriter writer)
literalInfo.Value,
identifierInfo.Value,
contextInfo.Value,
globalAliasInfo);
aliasInfo);
}
}

0 comments on commit 9d5e375

Please sign in to comment.