提交 023a2719 编写于 作者: C Cyrus Najmabadi

Support indexer accessors.

上级 e9b3cb6f
......@@ -585,6 +585,50 @@ class Usages
Await TestStreamingFeature(input)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.FindReferences)>
Public Async Function TestCSharpAccessor_Indexer1() As Task
Dim input =
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
interface IC
{
int this[int i] { {|Definition:$$get|} => 0; set { } }
}
class C : IC
{
public virtual int this[int i] { {|Definition:get|} => 0; set { } }
}
class D : C
{
public override int this[int i] { {|Definition:get|} => base[||][i]; set { base[i] = value; } }
}
class Usages
{
void M()
{
IC ic;
var v1 = ic[||][0]
ic[0] = 1
C c;
var v1 = c[||][0]
c[0] = 1
D d;
var v1 = d[||][0]
d[0] = 1
}
}
</Document>
</Project>
</Workspace>
Await TestStreamingFeature(input)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.FindReferences)>
Public Async Function TestVBAccessor_Get_Feature1() As Task
Dim input =
......
......@@ -71,7 +71,7 @@ protected override bool CanFind(IMethodSymbol symbol)
return Task.FromResult(project.Documents.ToImmutableArray());
}
protected override async Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
protected override async Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
IMethodSymbol methodSymbol,
Document document,
SemanticModel semanticModel,
......@@ -104,7 +104,7 @@ protected override bool CanFind(IMethodSymbol symbol)
.Where(e => semanticModel.GetSymbolInfo(e, cancellationToken).Symbol.OriginalDefinition == methodSymbol);
var result = invocations.Concat(convertedAnonymousFunctions).Select(
e => new ReferenceLocation(document, null, e.GetLocation(), isImplicit: false, isWrittenTo: false, candidateReason: CandidateReason.None));
n => (n, new ReferenceLocation(document, null, n.GetLocation(), isImplicit: false, isWrittenTo: false, candidateReason: CandidateReason.None)));
return result.ToImmutableArray();
}
......
......@@ -657,11 +657,12 @@ public SyntaxNode GetExpressionOfMemberAccessExpression(SyntaxNode node, bool al
public SyntaxNode GetExpressionOfConditionalAccessExpression(SyntaxNode node)
=> (node as ConditionalAccessExpressionSyntax)?.Expression;
public SyntaxNode GetExpressionOfElementAccessExpression(SyntaxNode node)
=> (node as ElementAccessExpressionSyntax)?.Expression;
public SyntaxNode GetArgumentListOfElementAccessExpression(SyntaxNode node)
=> (node as ElementAccessExpressionSyntax)?.ArgumentList;
public void GetPartsOfElementAccessExpression(SyntaxNode node, out SyntaxNode expression, out SyntaxNode argumentList)
{
var elementAccess = node as ElementAccessExpressionSyntax;
expression = elementAccess?.Expression;
argumentList = elementAccess?.ArgumentList;
}
public SyntaxNode GetExpressionOfInterpolation(SyntaxNode node)
=> (node as InterpolationSyntax)?.Expression;
......
......@@ -61,7 +61,7 @@ internal partial class FindReferencesSearchEngine
symbolAndProjectId, document, semanticModel, _options, _cancellationToken).ConfigureAwait(false);
foreach (var location in references)
{
await HandleLocationAsync(symbolAndProjectId, location).ConfigureAwait(false);
await HandleLocationAsync(symbolAndProjectId, location.location).ConfigureAwait(false);
}
}
finally
......
......@@ -47,7 +47,7 @@ protected sealed override bool CanFind(TSymbol symbol)
return Task.FromResult(ImmutableArray.Create(document));
}
protected override async Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
protected override async Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
TSymbol symbol,
Document document,
SemanticModel semanticModel,
......@@ -71,7 +71,7 @@ protected sealed override bool CanFind(TSymbol symbol)
symbol, document, semanticModel, tokens, cancellationToken).ConfigureAwait(false);
}
return ImmutableArray<ReferenceLocation>.Empty;
return ImmutableArray<(SyntaxNode node, ReferenceLocation location)>.Empty;
}
private static ISymbol GetContainer(ISymbol symbol)
......@@ -109,7 +109,7 @@ private static ISymbol GetContainer(ISymbol symbol)
return null;
}
protected Task<ImmutableArray<ReferenceLocation>> FindReferencesInTokensWithSymbolNameAsync(
protected Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInTokensWithSymbolNameAsync(
TSymbol symbol,
Document document,
SemanticModel semanticModel,
......@@ -121,7 +121,7 @@ private static ISymbol GetContainer(ISymbol symbol)
findParentNode: null, cancellationToken: cancellationToken);
}
protected Task<ImmutableArray<ReferenceLocation>> FindReferencesInTokensWithSymbolNameAsync(
protected Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInTokensWithSymbolNameAsync(
TSymbol symbol,
Document document,
SemanticModel semanticModel,
......@@ -142,7 +142,7 @@ private static ISymbol GetContainer(ISymbol symbol)
cancellationToken);
}
private Task<ImmutableArray<ReferenceLocation>> FindReferencesInContainerAsync(
private Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInContainerAsync(
TSymbol symbol,
ISymbol container,
Document document,
......@@ -154,7 +154,7 @@ private static ISymbol GetContainer(ISymbol symbol)
findParentNode: null, cancellationToken: cancellationToken);
}
private Task<ImmutableArray<ReferenceLocation>> FindReferencesInContainerAsync(
private Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInContainerAsync(
TSymbol symbol,
ISymbol container,
Document document,
......
......@@ -59,9 +59,18 @@ protected AbstractMethodOrPropertyOrEventSymbolReferenceFinder()
}
protected ImmutableArray<IMethodSymbol> GetReferencedAccessorSymbols(
ISemanticFactsService semanticFacts, SemanticModel model,
IPropertySymbol property, SyntaxNode node, CancellationToken cancellationToken)
ISyntaxFactsService syntaxFacts, ISemanticFactsService semanticFacts,
SemanticModel model, IPropertySymbol property, SyntaxNode node, CancellationToken cancellationToken)
{
if (syntaxFacts.IsForEachStatement(node))
{
var symbols = semanticFacts.GetForEachSymbols(model, node);
// the only accessor method referenced in a foreach-statement is the .Current's
// get-accessor
return ImmutableArray.Create(symbols.CurrentProperty.GetMethod);
}
if (semanticFacts.IsWrittenTo(model, node, cancellationToken))
{
// if it was only written to, then only the setter was referenced.
......
......@@ -49,7 +49,7 @@ protected override bool CanFind(IMethodSymbol symbol)
}, cancellationToken);
}
protected override async Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
protected override async Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
IMethodSymbol methodSymbol,
Document document,
SemanticModel semanticModel,
......
......@@ -55,7 +55,7 @@ protected override bool CanFind(IMethodSymbol symbol)
predefinedType == actualType;
}
protected override Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
protected override Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
IMethodSymbol methodSymbol,
Document document,
SemanticModel semanticModel,
......@@ -65,7 +65,7 @@ protected override bool CanFind(IMethodSymbol symbol)
return FindAllReferencesInDocumentAsync(methodSymbol, document, semanticModel, cancellationToken);
}
internal async Task<ImmutableArray<ReferenceLocation>> FindAllReferencesInDocumentAsync(
internal async Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindAllReferencesInDocumentAsync(
IMethodSymbol methodSymbol,
Document document,
SemanticModel semanticModel,
......@@ -87,7 +87,7 @@ protected override bool CanFind(IMethodSymbol symbol)
return t => syntaxFacts.GetBindableParent(t);
}
private async Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentWorkerAsync(
private async Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentWorkerAsync(
IMethodSymbol symbol,
Document document,
SemanticModel semanticModel,
......@@ -101,7 +101,7 @@ protected override bool CanFind(IMethodSymbol symbol)
return ordinaryRefs.Concat(attributeRefs).Concat(predefinedTypeRefs);
}
private Task<ImmutableArray<ReferenceLocation>> FindOrdinaryReferencesAsync(
private Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindOrdinaryReferencesAsync(
IMethodSymbol symbol,
Document document,
SemanticModel semanticModel,
......@@ -113,7 +113,7 @@ protected override bool CanFind(IMethodSymbol symbol)
symbol, name, document, semanticModel, findParentNode, cancellationToken);
}
private Task<ImmutableArray<ReferenceLocation>> FindPredefinedTypeReferencesAsync(
private Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindPredefinedTypeReferencesAsync(
IMethodSymbol symbol,
Document document,
SemanticModel semanticModel,
......@@ -122,7 +122,7 @@ protected override bool CanFind(IMethodSymbol symbol)
var predefinedType = symbol.ContainingType.SpecialType.ToPredefinedType();
if (predefinedType == PredefinedType.None)
{
return SpecializedTasks.EmptyImmutableArray<ReferenceLocation>();
return SpecializedTasks.EmptyImmutableArray<(SyntaxNode node, ReferenceLocation location)>();
}
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
......@@ -132,7 +132,7 @@ protected override bool CanFind(IMethodSymbol symbol)
cancellationToken);
}
private Task<ImmutableArray<ReferenceLocation>> FindAttributeReferencesAsync(
private Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindAttributeReferencesAsync(
IMethodSymbol symbol,
Document document,
SemanticModel semanticModel,
......@@ -141,7 +141,7 @@ protected override bool CanFind(IMethodSymbol symbol)
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
return TryGetNameWithoutAttributeSuffix(symbol.ContainingType.Name, syntaxFacts, out var simpleName)
? FindReferencesInDocumentUsingIdentifierAsync(symbol, simpleName, document, semanticModel, cancellationToken)
: SpecializedTasks.EmptyImmutableArray<ReferenceLocation>();
: SpecializedTasks.EmptyImmutableArray<(SyntaxNode node, ReferenceLocation location)>();
}
}
}
......@@ -34,14 +34,14 @@ protected override bool CanFind(IMethodSymbol symbol)
return SpecializedTasks.EmptyImmutableArray<Document>();
}
protected override Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
protected override Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
IMethodSymbol methodSymbol,
Document document,
SemanticModel semanticModel,
FindReferencesSearchOptions options,
CancellationToken cancellationToken)
{
return SpecializedTasks.EmptyImmutableArray<ReferenceLocation>();
return SpecializedTasks.EmptyImmutableArray<(SyntaxNode node, ReferenceLocation location)>();
}
}
}
......@@ -53,7 +53,7 @@ protected override bool CanFind(IEventSymbol symbol)
return FindDocumentsAsync(project, documents, cancellationToken, symbol.Name);
}
protected override Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
protected override Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
IEventSymbol symbol,
Document document,
SemanticModel semanticModel,
......
......@@ -40,7 +40,7 @@ protected override bool CanFind(IMethodSymbol symbol)
return SpecializedTasks.EmptyImmutableArray<Document>();
}
protected override Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
protected override Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
IMethodSymbol symbol,
Document document,
SemanticModel semanticModel,
......@@ -48,7 +48,7 @@ protected override bool CanFind(IMethodSymbol symbol)
CancellationToken cancellationToken)
{
// An explicit method can't be referenced anywhere.
return SpecializedTasks.EmptyImmutableArray<ReferenceLocation>();
return SpecializedTasks.EmptyImmutableArray<(SyntaxNode node, ReferenceLocation location)>();
}
}
}
......@@ -43,7 +43,7 @@ protected override bool CanFind(IFieldSymbol symbol)
return FindDocumentsAsync(project, documents, cancellationToken, symbol.Name);
}
protected override Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
protected override Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
IFieldSymbol symbol,
Document document,
SemanticModel semanticModel,
......
......@@ -66,7 +66,7 @@ internal interface IReferenceFinder
///
/// Implementations of this method must be thread-safe.
/// </summary>
Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
SymbolAndProjectId symbolAndProjectId, Document document, SemanticModel semanticModel,
FindReferencesSearchOptions options, CancellationToken cancellationToken);
}
......
......@@ -75,11 +75,11 @@ public Task<ImmutableArray<Project>> DetermineProjectsToSearchAsync(ISymbol symb
return SpecializedTasks.EmptyImmutableArray<Project>();
}
public Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
public Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
SymbolAndProjectId symbolAndProjectId, Document document, SemanticModel semanticModel,
FindReferencesSearchOptions options, CancellationToken cancellationToken)
{
return SpecializedTasks.EmptyImmutableArray<ReferenceLocation>();
return SpecializedTasks.EmptyImmutableArray<(SyntaxNode node, ReferenceLocation location)>();
}
}
}
......@@ -74,7 +74,7 @@ private static string GetMemberNameWithoutInterfaceName(string fullName)
: fullName;
}
protected override Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
protected override Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
ITypeParameterSymbol symbol,
Document document,
SemanticModel semanticModel,
......
......@@ -79,29 +79,29 @@ protected override bool CanFind(INamedTypeSymbol symbol)
predefinedType == actualType;
}
protected override async Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
protected override async Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
INamedTypeSymbol namedType,
Document document,
SemanticModel semanticModel,
FindReferencesSearchOptions options,
CancellationToken cancellationToken)
{
var namedTypereferences = await FindReferencesInDocumentWorker(
var namedTypeReferences = await FindReferencesInDocumentWorker(
namedType, document, semanticModel, cancellationToken).ConfigureAwait(false);
// Mark any references that are also Constructor references. Some callers
// will want to know about these so they won't display duplicates.
return await MarkConstructorReferences(
namedType, document, semanticModel, namedTypereferences, cancellationToken).ConfigureAwait(false);
namedType, document, semanticModel, namedTypeReferences, cancellationToken).ConfigureAwait(false);
}
private async Task<ImmutableArray<ReferenceLocation>> MarkConstructorReferences(
private async Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> MarkConstructorReferences(
INamedTypeSymbol namedType, Document document,
SemanticModel semanticModel,
ImmutableArray<ReferenceLocation> namedTypereferences,
ImmutableArray<(SyntaxNode node, ReferenceLocation location)> namedTypeReferences,
CancellationToken cancellationToken)
{
var constructorReferences = ArrayBuilder<ReferenceLocation>.GetInstance();
var constructorReferences = ArrayBuilder<(SyntaxNode node, ReferenceLocation location)>.GetInstance();
foreach (var constructor in namedType.Constructors)
{
var references = await ConstructorSymbolReferenceFinder.Instance.FindAllReferencesInDocumentAsync(
......@@ -109,13 +109,13 @@ protected override bool CanFind(INamedTypeSymbol symbol)
constructorReferences.AddRange(references);
}
var result = ArrayBuilder<ReferenceLocation>.GetInstance();
foreach (var reference in namedTypereferences)
var result = ArrayBuilder<(SyntaxNode node, ReferenceLocation location)>.GetInstance();
foreach (var reference in namedTypeReferences)
{
if (Contains(constructorReferences, reference))
{
var localReference = reference;
localReference.IsDuplicateReferenceLocation = true;
localReference.location.IsDuplicateReferenceLocation = true;
result.Add(localReference);
}
else
......@@ -128,12 +128,12 @@ protected override bool CanFind(INamedTypeSymbol symbol)
}
private bool Contains(
ArrayBuilder<ReferenceLocation> constructorReferences,
ReferenceLocation reference)
ArrayBuilder<(SyntaxNode node, ReferenceLocation location)> constructorReferences,
(SyntaxNode node, ReferenceLocation location) reference)
{
foreach (var constructorRef in constructorReferences)
{
if (reference.Location == constructorRef.Location)
if (reference.location.Location == constructorRef.location.Location)
{
return true;
}
......@@ -142,7 +142,7 @@ protected override bool CanFind(INamedTypeSymbol symbol)
return false;
}
private static async Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentWorker(
private static async Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentWorker(
INamedTypeSymbol namedType,
Document document,
SemanticModel semanticModel,
......@@ -154,7 +154,7 @@ protected override bool CanFind(INamedTypeSymbol symbol)
return nonAliasReferences.Concat(aliasReferences);
}
internal static async Task<ImmutableArray<ReferenceLocation>> FindNonAliasReferencesAsync(
internal static async Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindNonAliasReferencesAsync(
INamedTypeSymbol symbol,
Document document,
SemanticModel semanticModel,
......@@ -166,7 +166,7 @@ protected override bool CanFind(INamedTypeSymbol symbol)
return ordinaryRefs.Concat(attributeRefs).Concat(predefinedTypeRefs);
}
private static Task<ImmutableArray<ReferenceLocation>> FindOrdinaryReferencesAsync(
private static Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindOrdinaryReferencesAsync(
INamedTypeSymbol namedType,
Document document,
SemanticModel semanticModel,
......@@ -178,7 +178,7 @@ protected override bool CanFind(INamedTypeSymbol symbol)
namedType.Name, document, semanticModel, symbolsMatch, cancellationToken);
}
private static Task<ImmutableArray<ReferenceLocation>> FindPredefinedTypeReferencesAsync(
private static Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindPredefinedTypeReferencesAsync(
INamedTypeSymbol symbol,
Document document,
SemanticModel semanticModel,
......@@ -187,7 +187,7 @@ protected override bool CanFind(INamedTypeSymbol symbol)
var predefinedType = symbol.SpecialType.ToPredefinedType();
if (predefinedType == PredefinedType.None)
{
return SpecializedTasks.EmptyImmutableArray<ReferenceLocation>();
return SpecializedTasks.EmptyImmutableArray<(SyntaxNode node, ReferenceLocation location)>();
}
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
......@@ -197,7 +197,7 @@ protected override bool CanFind(INamedTypeSymbol symbol)
cancellationToken);
}
private static Task<ImmutableArray<ReferenceLocation>> FindAttributeReferencesAsync(
private static Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindAttributeReferencesAsync(
INamedTypeSymbol namedType,
Document document,
SemanticModel semanticModel,
......@@ -207,7 +207,7 @@ protected override bool CanFind(INamedTypeSymbol symbol)
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
return TryGetNameWithoutAttributeSuffix(namedType.Name, syntaxFacts, out var simpleName)
? FindReferencesInDocumentUsingIdentifierAsync(simpleName, document, semanticModel, symbolsMatch, cancellationToken)
: SpecializedTasks.EmptyImmutableArray<ReferenceLocation>();
: SpecializedTasks.EmptyImmutableArray<(SyntaxNode node, ReferenceLocation location)>();
}
}
}
......@@ -37,7 +37,7 @@ private static string GetNamespaceIdentifierName(INamespaceSymbol symbol, Projec
: symbol.Name;
}
protected override async Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
protected override async Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
INamespaceSymbol symbol,
Document document,
SemanticModel semanticModel,
......
......@@ -27,7 +27,7 @@ protected override bool CanFind(IMethodSymbol symbol)
return FindDocumentsAsync(project, documents, op, cancellationToken);
}
protected override Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
protected override Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
IMethodSymbol symbol,
Document document,
SemanticModel semanticModel,
......
......@@ -120,7 +120,7 @@ private bool IsDeconstructMethod(IMethodSymbol methodSymbol)
private bool IsGetAwaiterMethod(IMethodSymbol methodSymbol)
=> methodSymbol.Name == WellKnownMemberNames.GetAwaiter;
protected override async Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
protected override async Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
IMethodSymbol symbol,
Document document,
SemanticModel semanticModel,
......
......@@ -35,7 +35,7 @@ protected override bool CanFind(IParameterSymbol symbol)
return FindDocumentsAsync(project, documents, cancellationToken, symbol.Name);
}
protected override Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
protected override Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
IParameterSymbol symbol,
Document document,
SemanticModel semanticModel,
......
......@@ -44,20 +44,28 @@ protected override bool CanFind(IMethodSymbol symbol)
var result = await FindDocumentsAsync(
project, documents, cancellationToken, symbol.Name).ConfigureAwait(false);
if (options.AssociatePropertyReferencesWithSpecificAccessor)
if (symbol.AssociatedSymbol is IPropertySymbol property &&
options.AssociatePropertyReferencesWithSpecificAccessor)
{
// we want to associate normal property references with the specific
// accessor being referenced. So we also need to include documents
// with our property's name.
var propDocuments = await FindDocumentsAsync(
project, documents, cancellationToken, symbol.AssociatedSymbol.Name).ConfigureAwait(false);
result = result.AddRange(propDocuments);
result = await ReferenceFinders.Property.DetermineDocumentsToSearchAsync(
property, project, documents,
options.WithAssociatePropertyReferencesWithSpecificAccessor(false),
cancellationToken).ConfigureAwait(false);
}
return result;
}
protected override async Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
private Task<ImmutableArray<Document>> FindDocumentWithElementAccessExpressionsAsync(
Project project, IImmutableSet<Document> documents, CancellationToken cancellationToken)
{
return FindDocumentsWithPredicateAsync(project, documents, info => info.ContainsElementAccessExpression, cancellationToken);
}
protected override async Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
IMethodSymbol symbol, Document document, SemanticModel semanticModel,
FindReferencesSearchOptions options, CancellationToken cancellationToken)
{
......@@ -67,19 +75,19 @@ protected override bool CanFind(IMethodSymbol symbol)
if (symbol.AssociatedSymbol is IPropertySymbol property &&
options.AssociatePropertyReferencesWithSpecificAccessor)
{
var propertyReferences = await ReferenceFinders.Property.FindReferencesInDocumentAsync(
SymbolAndProjectId.Create(property, document.Project.Id),
document, semanticModel, options.WithAssociatePropertyReferencesWithSpecificAccessor(false),
var propertyReferences = await PropertySymbolReferenceFinder.Instance.FindAllReferencesInDocumentAsync(
property, document, semanticModel,
options.WithAssociatePropertyReferencesWithSpecificAccessor(false),
cancellationToken).ConfigureAwait(false);
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
var semanticFacts = document.GetLanguageService<ISemanticFactsService>();
var accessorReferences = propertyReferences.WhereAsArray(
loc =>
{
var accessors = GetReferencedAccessorSymbols(
semanticFacts, semanticModel, property,
loc.Location.FindNode(getInnermostNodeForTie: true, cancellationToken),
cancellationToken);
syntaxFacts, semanticFacts, semanticModel, property, loc.node, cancellationToken);
return accessors.Contains(symbol);
});
......
......@@ -15,6 +15,12 @@ namespace Microsoft.CodeAnalysis.FindSymbols.Finders
{
internal class PropertySymbolReferenceFinder : AbstractMethodOrPropertyOrEventSymbolReferenceFinder<IPropertySymbol>
{
public static readonly PropertySymbolReferenceFinder Instance = new PropertySymbolReferenceFinder();
private PropertySymbolReferenceFinder()
{
}
protected override bool CanFind(IPropertySymbol symbol)
{
return true;
......@@ -83,12 +89,16 @@ private static bool IsForEachProperty(IPropertySymbol symbol)
return symbol.Name == WellKnownMemberNames.CurrentPropertyName;
}
protected override async Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
IPropertySymbol symbol,
Document document,
SemanticModel semanticModel,
FindReferencesSearchOptions options,
CancellationToken cancellationToken)
protected override Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
IPropertySymbol symbol, Document document, SemanticModel semanticModel,
FindReferencesSearchOptions options, CancellationToken cancellationToken)
{
return FindAllReferencesInDocumentAsync(symbol, document, semanticModel, options, cancellationToken);
}
internal async Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindAllReferencesInDocumentAsync(
IPropertySymbol symbol, Document document, SemanticModel semanticModel,
FindReferencesSearchOptions options, CancellationToken cancellationToken)
{
var nameReferences = await FindReferencesInDocumentUsingSymbolNameAsync(
symbol, document, semanticModel, cancellationToken).ConfigureAwait(false);
......@@ -98,101 +108,121 @@ private static bool IsForEachProperty(IPropertySymbol symbol)
// We want to associate property references to a specific accessor (if an accessor
// is being referenced). Check if this reference would match an accessor. If so, do
// not add it. It will be added by PropertyAccessorSymbolReferenceFinder.
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
var semanticFacts = document.GetLanguageService<ISemanticFactsService>();
nameReferences = nameReferences.WhereAsArray(loc =>
{
var accessors = GetReferencedAccessorSymbols(
semanticFacts, semanticModel, symbol,
loc.Location.FindNode(getInnermostNodeForTie: true, cancellationToken),
cancellationToken);
syntaxFacts, semanticFacts, semanticModel, symbol, loc.node, cancellationToken);
return accessors.Length == 0;
});
}
var forEachReferences = IsForEachProperty(symbol)
? await FindReferencesInForEachStatementsAsync(symbol, document, semanticModel, cancellationToken).ConfigureAwait(false)
: ImmutableArray<ReferenceLocation>.Empty;
: ImmutableArray<(SyntaxNode, ReferenceLocation)>.Empty;
var elementAccessReferences = symbol.IsIndexer
? await FindElementAccessReferencesAndIndexerMemberCrefReferencesAsync(symbol, document, semanticModel, cancellationToken).ConfigureAwait(false)
: ImmutableArray<ReferenceLocation>.Empty;
? await FindElementAccessReferencesAsync(symbol, document, semanticModel, options, cancellationToken).ConfigureAwait(false)
: ImmutableArray<(SyntaxNode, ReferenceLocation)>.Empty;
var indexerCrefReferences = symbol.IsIndexer
? await FindIndexerCrefReferencesAsync(symbol, document, semanticModel, options, cancellationToken)
: ImmutableArray<(SyntaxNode, ReferenceLocation)>.Empty;
return nameReferences.Concat(forEachReferences)
.Concat(elementAccessReferences);
.Concat(elementAccessReferences)
.Concat(indexerCrefReferences);
}
private Task<ImmutableArray<Document>> FindDocumentWithElementAccessExpressionsAsync(
Project project, IImmutableSet<Document> documents, CancellationToken cancellationToken)
{
return FindDocumentsAsync(project, documents, async (d, c) =>
{
var info = await SyntaxTreeIndex.GetIndexAsync(d, c).ConfigureAwait(false);
return info.ContainsElementAccessExpression;
}, cancellationToken);
return FindDocumentsWithPredicateAsync(project, documents, info => info.ContainsElementAccessExpression, cancellationToken);
}
private Task<ImmutableArray<Document>> FindDocumentWithIndexerMemberCrefAsync(
Project project, IImmutableSet<Document> documents, CancellationToken cancellationToken)
{
return FindDocumentsAsync(project, documents, async (d, c) =>
{
var info = await SyntaxTreeIndex.GetIndexAsync(d, c).ConfigureAwait(false);
return info.ContainsIndexerMemberCref;
}, cancellationToken);
return FindDocumentsWithPredicateAsync(project, documents, info => info.ContainsIndexerMemberCref, cancellationToken);
}
private async Task<ImmutableArray<ReferenceLocation>> FindElementAccessReferencesAndIndexerMemberCrefReferencesAsync(
IPropertySymbol symbol,
Document document,
SemanticModel semanticModel,
CancellationToken cancellationToken)
private async Task<ImmutableArray<(SyntaxNode, ReferenceLocation)>> FindElementAccessReferencesAsync(
IPropertySymbol symbol, Document document, SemanticModel semanticModel,
FindReferencesSearchOptions options, CancellationToken cancellationToken)
{
if (options.AssociatePropertyReferencesWithSpecificAccessor)
{
// Looking for individual get/set references. Don't find anything here.
// these results will be provided by the PropertyAccessorSymbolReferenceFinder
return ImmutableArray<(SyntaxNode, ReferenceLocation)>.Empty;
}
var symbolsMatch = GetStandardSymbolsNodeMatchFunction(symbol, document.Project.Solution, cancellationToken);
var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
// Now that we have Doc Comments in place, We are searching for References in the Trivia as well by setting descendIntoTrivia: true
var elementAccessExpressions = syntaxRoot.DescendantNodes().Where(syntaxFacts.IsElementAccessExpression);
var indexerMemberCref = syntaxRoot.DescendantNodes(descendIntoTrivia: true).Where(syntaxFacts.IsIndexerMemberCRef);
var elementAccessExpressionsAndIndexerMemberCref = elementAccessExpressions.Concat(indexerMemberCref);
var locations = ArrayBuilder<(SyntaxNode, ReferenceLocation)>.GetInstance();
var locations = ArrayBuilder<ReferenceLocation>.GetInstance();
foreach (var node in elementAccessExpressionsAndIndexerMemberCref)
foreach (var node in elementAccessExpressions)
{
cancellationToken.ThrowIfCancellationRequested();
var match = symbolsMatch(node, semanticModel);
if (match.matched)
var (matched, reason) = symbolsMatch(node, semanticModel);
if (matched)
{
SyntaxNode nodeToBeReferenced = null;
syntaxFacts.GetPartsOfElementAccessExpression(node, out var expression, out var argumentList);
if (syntaxFacts.IsIndexerMemberCRef(node))
if (symbolsMatch(expression, semanticModel).matched)
{
nodeToBeReferenced = node;
}
else
{
var childNodes = node.ChildNodes();
var leftOfInvocation = childNodes.First();
if (symbolsMatch(leftOfInvocation, semanticModel).matched)
{
// Element access with explicit member name (allowed in VB).
// We have already added a reference location for the member name identifier, so skip this one.
continue;
}
nodeToBeReferenced = childNodes.Skip(1).FirstOrDefault();
// Element access with explicit member name (allowed in VB).
// We have already added a reference location for the member name identifier, so skip this one.
continue;
}
if (nodeToBeReferenced != null)
{
var location = nodeToBeReferenced.SyntaxTree.GetLocation(new TextSpan(nodeToBeReferenced.SpanStart, 0));
locations.Add(new ReferenceLocation(document, null, location, isImplicit: false, isWrittenTo: false, candidateReason: match.reason));
}
var location = argumentList.SyntaxTree.GetLocation(new TextSpan(argumentList.SpanStart, 0));
locations.Add(
(node, new ReferenceLocation(document, null, location, isImplicit: false, isWrittenTo: false, candidateReason: reason)));
}
}
return locations.ToImmutableAndFree();
}
private async Task<ImmutableArray<(SyntaxNode, ReferenceLocation)>> FindIndexerCrefReferencesAsync(
IPropertySymbol symbol, Document document, SemanticModel semanticModel,
FindReferencesSearchOptions options, CancellationToken cancellationToken)
{
if (options.AssociatePropertyReferencesWithSpecificAccessor)
{
// can't find indexer get/set accessors in a cref.
return ImmutableArray<(SyntaxNode, ReferenceLocation)>.Empty;
}
var symbolsMatch = GetStandardSymbolsNodeMatchFunction(symbol, document.Project.Solution, cancellationToken);
var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
// Now that we have Doc Comments in place, We are searching for References in the Trivia as well by setting descendIntoTrivia: true
var indexerMemberCrefs = syntaxRoot.DescendantNodes(descendIntoTrivia: true)
.Where(syntaxFacts.IsIndexerMemberCRef);
var locations = ArrayBuilder<(SyntaxNode, ReferenceLocation)>.GetInstance();
foreach (var node in indexerMemberCrefs)
{
cancellationToken.ThrowIfCancellationRequested();
var match = symbolsMatch(node, semanticModel);
if (match.matched)
{
var location = node.SyntaxTree.GetLocation(new TextSpan(node.SpanStart, 0));
locations.Add(
(node, new ReferenceLocation(document, null, location, isImplicit: false, isWrittenTo: false, candidateReason: match.reason)));
}
}
......
......@@ -21,7 +21,7 @@ internal static class ReferenceFinders
public static readonly IReferenceFinder Operator = new OperatorSymbolReferenceFinder();
public static readonly IReferenceFinder OrdinaryMethod = new OrdinaryMethodReferenceFinder();
public static readonly IReferenceFinder Parameter = new ParameterSymbolReferenceFinder();
public static readonly IReferenceFinder Property = new PropertySymbolReferenceFinder();
public static readonly IReferenceFinder Property = PropertySymbolReferenceFinder.Instance;
public static readonly IReferenceFinder PropertyAccessor = new PropertyAccessorSymbolReferenceFinder();
public static readonly IReferenceFinder RangeVariable = new RangeVariableSymbolReferenceFinder();
public static readonly IReferenceFinder TypeParameter = new TypeParameterSymbolReferenceFinder();
......
......@@ -31,7 +31,7 @@ protected override bool CanFind(ITypeParameterSymbol symbol)
return FindDocumentsAsync(project, documents, cancellationToken, symbol.Name, symbol.ContainingType.Name);
}
protected override Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentAsync(
protected override Task<ImmutableArray<(SyntaxNode node, ReferenceLocation location)>> FindReferencesInDocumentAsync(
ITypeParameterSymbol symbol,
Document document,
SemanticModel semanticModel,
......
......@@ -165,8 +165,7 @@ internal interface ISyntaxFactsService : ILanguageService
SyntaxNode GetExpressionOfConditionalAccessExpression(SyntaxNode node);
SyntaxNode GetExpressionOfElementAccessExpression(SyntaxNode node);
SyntaxNode GetArgumentListOfElementAccessExpression(SyntaxNode node);
void GetPartsOfElementAccessExpression(SyntaxNode node, out SyntaxNode expression, out SyntaxNode argumentList);
SyntaxNode GetExpressionOfArgument(SyntaxNode node);
SyntaxNode GetExpressionOfInterpolation(SyntaxNode node);
......
......@@ -139,5 +139,16 @@ public static bool IsAnonymousOrLocalFunctionStatement(this ISyntaxFactsService
=> syntaxFacts.IsAnonymousFunction(node) ||
syntaxFacts.IsLocalFunctionStatement(node);
public static SyntaxNode GetExpressionOfElementAccessExpression(this ISyntaxFactsService syntaxFacts, SyntaxNode node)
{
syntaxFacts.GetPartsOfElementAccessExpression(node, out var expression, out _);
return expression;
}
public static SyntaxNode GetArgumentListOfElementAccessExpression(this ISyntaxFactsService syntaxFacts, SyntaxNode node)
{
syntaxFacts.GetPartsOfElementAccessExpression(node, out _, out var argumentList);
return argumentList;
}
}
}
......@@ -601,13 +601,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return TryCast(node, ConditionalAccessExpressionSyntax)?.Expression
End Function
Public Function GetExpressionOfElementAccessExpression(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetExpressionOfElementAccessExpression
Return TryCast(node, InvocationExpressionSyntax)?.Expression
End Function
Public Function GetArgumentListOfElementAccessExpression(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetArgumentListOfElementAccessExpression
Return TryCast(node, InvocationExpressionSyntax)?.ArgumentList
End Function
Public Sub GetPartsOfElementAccessExpression(node As SyntaxNode, ByRef expression As SyntaxNode, ByRef argumentList As SyntaxNode) Implements ISyntaxFactsService.GetPartsOfElementAccessExpression
Dim invocation = TryCast(node, InvocationExpressionSyntax)
expression = invocation?.Expression
argumentList = invocation?.ArgumentList
End Sub
Public Function GetExpressionOfInterpolation(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetExpressionOfInterpolation
Return TryCast(node, InterpolationSyntax)?.Expression
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册