Skip to content

Commit 9d5e375

Browse files
Merge pull request #74015 from CyrusNajmabadi/indices
Fix find refs doing too much work lookign for types that had an alias to them in one file.
2 parents 0d03b2e + f7d3357 commit 9d5e375

File tree

8 files changed

+96
-64
lines changed

8 files changed

+96
-64
lines changed

src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorSymbolReferenceFinder.cs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -98,22 +98,17 @@ protected override void FindReferencesInDocument<TData>(
9898
CancellationToken cancellationToken)
9999
{
100100
// First just look for this normal constructor references using the name of it's containing type.
101-
var name = methodSymbol.ContainingType.Name;
101+
var containingType = methodSymbol.ContainingType;
102+
var containingTypeName = containingType.Name;
102103
AddReferencesInDocumentWorker(
103-
methodSymbol, name, state, processResult, processResultData, cancellationToken);
104+
methodSymbol, containingTypeName, state, processResult, processResultData, cancellationToken);
104105

105106
// Next, look for constructor references through a global alias to our containing type.
106107
foreach (var globalAlias in state.GlobalAliases)
107-
{
108-
// ignore the cases where the global alias might match the type name (i.e.
109-
// global alias Console = System.Console). We'll already find those references
110-
// above.
111-
if (state.SyntaxFacts.StringComparer.Equals(name, globalAlias))
112-
continue;
108+
FindReferenceToAlias(methodSymbol, state, processResult, processResultData, containingTypeName, globalAlias, cancellationToken);
113109

114-
AddReferencesInDocumentWorker(
115-
methodSymbol, globalAlias, state, processResult, processResultData, cancellationToken);
116-
}
110+
foreach (var localAlias in state.Cache.SyntaxTreeIndex.GetAliases(containingTypeName, containingType.Arity))
111+
FindReferenceToAlias(methodSymbol, state, processResult, processResultData, containingTypeName, localAlias, cancellationToken);
117112

118113
// Finally, look for constructor references to predefined types (like `new int()`),
119114
// implicit object references, and inside global suppression attributes.
@@ -127,6 +122,19 @@ protected override void FindReferencesInDocument<TData>(
127122
methodSymbol, state, processResult, processResultData, cancellationToken);
128123
}
129124

125+
private static void FindReferenceToAlias<TData>(
126+
IMethodSymbol methodSymbol, FindReferencesDocumentState state, Action<FinderLocation, TData> processResult, TData processResultData, string name, string alias, CancellationToken cancellationToken)
127+
{
128+
// ignore the cases where the global alias might match the type name (i.e.
129+
// global alias Console = System.Console). We'll already find those references
130+
// above.
131+
if (state.SyntaxFacts.StringComparer.Equals(name, alias))
132+
return;
133+
134+
AddReferencesInDocumentWorker(
135+
methodSymbol, alias, state, processResult, processResultData, cancellationToken);
136+
}
137+
130138
/// <summary>
131139
/// Finds references to <paramref name="symbol"/> in this <paramref name="state"/>, but only if it referenced
132140
/// though <paramref name="name"/> (which might be the actual name of the type, or a global alias to it).

src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/NamedTypeSymbolReferenceFinder.cs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -147,16 +147,23 @@ internal static void AddReferencesToTypeOrGlobalAliasToIt<TData>(
147147
namedType, namedType.Name, state, processResult, processResultData, cancellationToken);
148148

149149
foreach (var globalAlias in state.GlobalAliases)
150-
{
151-
// ignore the cases where the global alias might match the type name (i.e.
152-
// global alias Console = System.Console). We'll already find those references
153-
// above.
154-
if (state.SyntaxFacts.StringComparer.Equals(namedType.Name, globalAlias))
155-
continue;
156-
157-
AddNonAliasReferences(
158-
namedType, globalAlias, state, processResult, processResultData, cancellationToken);
159-
}
150+
FindReferenceToAlias(namedType, state, processResult, processResultData, globalAlias, cancellationToken);
151+
152+
foreach (var localAlias in state.Cache.SyntaxTreeIndex.GetAliases(namedType.Name, namedType.Arity))
153+
FindReferenceToAlias(namedType, state, processResult, processResultData, localAlias, cancellationToken);
154+
}
155+
156+
private static void FindReferenceToAlias<TData>(
157+
INamedTypeSymbol namedType, FindReferencesDocumentState state, Action<FinderLocation, TData> processResult, TData processResultData, string alias, CancellationToken cancellationToken)
158+
{
159+
// ignore the cases where the global alias might match the type name (i.e.
160+
// global alias Console = System.Console). We'll already find those references
161+
// above.
162+
if (state.SyntaxFacts.StringComparer.Equals(namedType.Name, alias))
163+
return;
164+
165+
AddNonAliasReferences(
166+
namedType, alias, state, processResult, processResultData, cancellationToken);
160167
}
161168

162169
/// <summary>

src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/NamespaceSymbolReferenceFinder.cs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,10 @@ protected override void FindReferencesInDocument<TData>(
7272
symbol, namespaceName, state, StandardCallbacks<FinderLocation>.AddToArrayBuilder, initialReferences, cancellationToken);
7373

7474
foreach (var globalAlias in state.GlobalAliases)
75-
{
76-
// ignore the cases where the global alias might match the namespace name (i.e.
77-
// global alias Collections = System.Collections). We'll already find those references
78-
// above.
79-
if (state.SyntaxFacts.StringComparer.Equals(namespaceName, globalAlias))
80-
continue;
81-
82-
AddNamedReferences(
83-
symbol, globalAlias, state, StandardCallbacks<FinderLocation>.AddToArrayBuilder, initialReferences, cancellationToken);
84-
}
75+
FindReferenceToAlias(symbol, state, initialReferences, namespaceName, globalAlias, cancellationToken);
76+
77+
foreach (var localAlias in state.Cache.SyntaxTreeIndex.GetAliases(symbol.Name, arity: 0))
78+
FindReferenceToAlias(symbol, state, initialReferences, namespaceName, localAlias, cancellationToken);
8579

8680
// The items in initialReferences need to be both reported and used later to calculate additional results.
8781
foreach (var location in initialReferences)
@@ -95,6 +89,19 @@ protected override void FindReferencesInDocument<TData>(
9589
}
9690
}
9791

92+
private static void FindReferenceToAlias(
93+
INamespaceSymbol symbol, FindReferencesDocumentState state, ArrayBuilder<FinderLocation> initialReferences, string namespaceName, string alias, CancellationToken cancellationToken)
94+
{
95+
// ignore the cases where the global alias might match the namespace name (i.e.
96+
// global alias Collections = System.Collections). We'll already find those references
97+
// above.
98+
if (state.SyntaxFacts.StringComparer.Equals(namespaceName, alias))
99+
return;
100+
101+
AddNamedReferences(
102+
symbol, alias, state, StandardCallbacks<FinderLocation>.AddToArrayBuilder, initialReferences, cancellationToken);
103+
}
104+
98105
/// <summary>
99106
/// Finds references to <paramref name="symbol"/> in this <paramref name="state"/>, but only if it referenced
100107
/// though <paramref name="name"/> (which might be the actual name of the type, or a global alias to it).

src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,13 @@ namespace Microsoft.CodeAnalysis.FindSymbols;
1717
internal partial class AbstractSyntaxIndex<TIndex>
1818
{
1919
private static readonly string s_persistenceName = typeof(TIndex).Name;
20-
private static readonly Checksum s_serializationFormatChecksum = CodeAnalysis.Checksum.Create("39");
20+
21+
/// <summary>
22+
/// Increment this whenever the data format of the <see cref="AbstractSyntaxIndex{TIndex}"/> changes. This ensures
23+
/// that we will not try to read previously cached data from a prior version of roslyn with a different format and
24+
/// will instead regenerate all the indices with the new format.
25+
/// </summary>
26+
private static readonly Checksum s_serializationFormatChecksum = CodeAnalysis.Checksum.Create("40");
2127

2228
/// <summary>
2329
/// Cache of ParseOptions to a checksum for the <see cref="ParseOptions.PreprocessorSymbolNames"/> contained

src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,20 @@ internal sealed partial class SyntaxTreeIndex : AbstractSyntaxIndex<SyntaxTreeIn
1414
private readonly LiteralInfo _literalInfo;
1515
private readonly IdentifierInfo _identifierInfo;
1616
private readonly ContextInfo _contextInfo;
17-
private readonly HashSet<(string alias, string name, int arity)>? _globalAliasInfo;
17+
private readonly HashSet<(string alias, string name, int arity, bool isGlobal)>? _aliasInfo;
1818

1919
private SyntaxTreeIndex(
2020
Checksum? checksum,
2121
LiteralInfo literalInfo,
2222
IdentifierInfo identifierInfo,
2323
ContextInfo contextInfo,
24-
HashSet<(string alias, string name, int arity)>? globalAliasInfo)
24+
HashSet<(string alias, string name, int arity, bool isGlobal)>? aliasInfo)
2525
: base(checksum)
2626
{
2727
_literalInfo = literalInfo;
2828
_identifierInfo = identifierInfo;
2929
_contextInfo = contextInfo;
30-
_globalAliasInfo = globalAliasInfo;
30+
_aliasInfo = aliasInfo;
3131
}
3232

3333
public static ValueTask<SyntaxTreeIndex> GetRequiredIndexAsync(Document document, CancellationToken cancellationToken)

src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Create.cs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ private static SyntaxTreeIndex CreateIndex(
4747
var stringLiterals = StringLiteralHashSetPool.Allocate();
4848
var longLiterals = LongLiteralHashSetPool.Allocate();
4949

50-
HashSet<(string alias, string name, int arity)>? globalAliasInfo = null;
50+
HashSet<(string alias, string name, int arity, bool isGlobal)>? aliasInfo = null;
5151

5252
try
5353
{
@@ -98,7 +98,7 @@ private static SyntaxTreeIndex CreateIndex(
9898
containsConversion = containsConversion || syntaxFacts.IsConversionExpression(node);
9999
containsCollectionInitializer = containsCollectionInitializer || syntaxFacts.IsObjectCollectionInitializer(node);
100100

101-
TryAddGlobalAliasInfo(syntaxFacts, ref globalAliasInfo, node);
101+
TryAddAliasInfo(syntaxFacts, ref aliasInfo, node);
102102
}
103103
else
104104
{
@@ -186,7 +186,7 @@ private static SyntaxTreeIndex CreateIndex(
186186
containsConversion,
187187
containsGlobalKeyword,
188188
containsCollectionInitializer),
189-
globalAliasInfo);
189+
aliasInfo);
190190
}
191191
finally
192192
{
@@ -219,17 +219,15 @@ private static bool IsGlobalSuppressMessageAttribute(ISyntaxFactsService syntaxF
219219
syntaxFacts.StringComparer.Equals(identifierName, nameof(SuppressMessageAttribute));
220220
}
221221

222-
private static void TryAddGlobalAliasInfo(
222+
private static void TryAddAliasInfo(
223223
ISyntaxFactsService syntaxFacts,
224-
ref HashSet<(string alias, string name, int arity)>? globalAliasInfo,
224+
ref HashSet<(string alias, string name, int arity, bool isGlobal)>? aliasInfo,
225225
SyntaxNode node)
226226
{
227227
if (!syntaxFacts.IsUsingAliasDirective(node))
228228
return;
229229

230230
syntaxFacts.GetPartsOfUsingAliasDirective(node, out var globalToken, out var alias, out var usingTarget);
231-
if (globalToken.IsMissing)
232-
return;
233231

234232
// if we have `global using X = Y.Z` then walk down the rhs to pull out 'Z'.
235233
if (syntaxFacts.IsQualifiedName(usingTarget))
@@ -242,8 +240,9 @@ private static void TryAddGlobalAliasInfo(
242240
if (syntaxFacts.IsSimpleName(usingTarget))
243241
{
244242
syntaxFacts.GetNameAndArityOfSimpleName(usingTarget, out var name, out var arity);
245-
globalAliasInfo ??= [];
246-
globalAliasInfo.Add((alias.ValueText, name, arity));
243+
244+
aliasInfo ??= [];
245+
aliasInfo.Add((alias.ValueText, name, arity, isGlobal: globalToken != default));
247246
}
248247
}
249248

src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Forwarders.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,22 @@ internal sealed partial class SyntaxTreeIndex
4242
/// <c>name="C"</c> and arity=1 will return <c>X</c>.
4343
/// </summary>
4444
public ImmutableArray<string> GetGlobalAliases(string name, int arity)
45+
=> GetAliasesWorker(name, arity, isGlobal: true);
46+
47+
public ImmutableArray<string> GetAliases(string name, int arity)
48+
=> GetAliasesWorker(name, arity, isGlobal: false);
49+
50+
private ImmutableArray<string> GetAliasesWorker(
51+
string name, int arity, bool isGlobal)
4552
{
46-
if (_globalAliasInfo == null)
53+
if (_aliasInfo == null)
4754
return [];
4855

4956
using var result = TemporaryArray<string>.Empty;
5057

51-
foreach (var (alias, aliasName, aliasArity) in _globalAliasInfo)
58+
foreach (var (alias, aliasName, aliasArity, aliasIsGlobal) in _aliasInfo)
5259
{
53-
if (aliasName == name && aliasArity == arity)
60+
if (aliasIsGlobal == isGlobal && aliasArity == arity && aliasName == name)
5461
result.Add(alias);
5562
}
5663

src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Persistence.cs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,15 @@ public override void WriteTo(ObjectWriter writer)
2525
_identifierInfo.WriteTo(writer);
2626
_contextInfo.WriteTo(writer);
2727

28-
if (_globalAliasInfo == null)
28+
writer.WriteInt32(_aliasInfo?.Count ?? 0);
29+
if (_aliasInfo != null)
2930
{
30-
writer.WriteInt32(0);
31-
}
32-
else
33-
{
34-
writer.WriteInt32(_globalAliasInfo.Count);
35-
foreach (var (alias, name, arity) in _globalAliasInfo)
31+
foreach (var (alias, name, arity, isGlobal) in _aliasInfo)
3632
{
3733
writer.WriteString(alias);
3834
writer.WriteString(name);
3935
writer.WriteInt32(arity);
36+
writer.WriteBoolean(isGlobal);
4037
}
4138
}
4239
}
@@ -51,19 +48,20 @@ public override void WriteTo(ObjectWriter writer)
5148
if (literalInfo == null || identifierInfo == null || contextInfo == null)
5249
return null;
5350

54-
var globalAliasInfoCount = reader.ReadInt32();
55-
HashSet<(string alias, string name, int arity)>? globalAliasInfo = null;
51+
var aliasInfoCount = reader.ReadInt32();
52+
HashSet<(string alias, string name, int arity, bool isGlobal)>? aliasInfo = null;
5653

57-
if (globalAliasInfoCount > 0)
54+
if (aliasInfoCount > 0)
5855
{
59-
globalAliasInfo = [];
56+
aliasInfo = [];
6057

61-
for (var i = 0; i < globalAliasInfoCount; i++)
58+
for (var i = 0; i < aliasInfoCount; i++)
6259
{
63-
var alias = reader.ReadRequiredString();
64-
var name = reader.ReadRequiredString();
65-
var arity = reader.ReadInt32();
66-
globalAliasInfo.Add((alias, name, arity));
60+
aliasInfo.Add((
61+
reader.ReadRequiredString(),
62+
reader.ReadRequiredString(),
63+
reader.ReadInt32(),
64+
reader.ReadBoolean()));
6765
}
6866
}
6967

@@ -72,6 +70,6 @@ public override void WriteTo(ObjectWriter writer)
7270
literalInfo.Value,
7371
identifierInfo.Value,
7472
contextInfo.Value,
75-
globalAliasInfo);
73+
aliasInfo);
7674
}
7775
}

0 commit comments

Comments
 (0)