diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Navigation/FindUsagesService.cs b/src/OmniSharp.Roslyn.CSharp/Services/Navigation/FindUsagesService.cs index 6b889d16d8..6ac9f32c5c 100644 --- a/src/OmniSharp.Roslyn.CSharp/Services/Navigation/FindUsagesService.cs +++ b/src/OmniSharp.Roslyn.CSharp/Services/Navigation/FindUsagesService.cs @@ -28,49 +28,38 @@ public async Task Handle(FindUsagesRequest request) { // To produce complete list of usages for symbols in the document wait until all projects are loaded. var document = await _workspace.GetDocumentFromFullProjectModelAsync(request.FileName); - var response = new QuickFixResponse(); - if (document != null) + if (document == null) { - var locations = new List(); - var semanticModel = await document.GetSemanticModelAsync(); - var sourceText = await document.GetTextAsync(); - var position = sourceText.Lines.GetPosition(new LinePosition(request.Line, request.Column)); - var symbol = await SymbolFinder.FindSymbolAtPositionAsync(semanticModel, position, _workspace); - var definition = await SymbolFinder.FindSourceDefinitionAsync(symbol, _workspace.CurrentSolution); - var usages = request.OnlyThisFile - ? await SymbolFinder.FindReferencesAsync(definition ?? symbol, _workspace.CurrentSolution, ImmutableHashSet.Create(document)) - : await SymbolFinder.FindReferencesAsync(definition ?? symbol, _workspace.CurrentSolution); - var dontRequireReferenceByName = symbol is IMethodSymbol method && - (method.MethodKind == MethodKind.Constructor || method.MethodKind == MethodKind.UserDefinedOperator); - - foreach (var usage in usages.Where(u => u.Definition.CanBeReferencedByName || dontRequireReferenceByName)) - { - foreach (var location in usage.Locations) - { - locations.Add(location.Location); - } - - if (!request.ExcludeDefinition) - { - var definitionLocations = usage.Definition.Locations - .Where(loc => loc.IsInSource && (!request.OnlyThisFile || loc.SourceTree.FilePath == request.FileName)); + return new QuickFixResponse(); + } - foreach (var location in definitionLocations) - { - locations.Add(location); - } - } - } + var semanticModel = await document.GetSemanticModelAsync(); + var sourceText = await document.GetTextAsync(); + var position = sourceText.Lines.GetPosition(new LinePosition(request.Line, request.Column)); + var symbol = await SymbolFinder.FindSymbolAtPositionAsync(semanticModel, position, _workspace); + var definition = await SymbolFinder.FindSourceDefinitionAsync(symbol, _workspace.CurrentSolution); + var usages = request.OnlyThisFile + ? await SymbolFinder.FindReferencesAsync(definition ?? symbol, _workspace.CurrentSolution, ImmutableHashSet.Create(document)) + : await SymbolFinder.FindReferencesAsync(definition ?? symbol, _workspace.CurrentSolution); + var locations = usages.SelectMany(u => u.Locations).Select(l => l.Location).ToList(); - var quickFixes = locations.Distinct().Select(l => l.GetQuickFix(_workspace)); + if (!request.ExcludeDefinition) + { + // always skip get/set methods of properties from the list of definition locations. + var definitionLocations = usages.Select(u => u.Definition) + .Where(def => !(def is IMethodSymbol method && method.AssociatedSymbol is IPropertySymbol)) + .SelectMany(def => def.Locations) + .Where(loc => loc.IsInSource && (!request.OnlyThisFile || loc.SourceTree.FilePath == request.FileName)); - response = new QuickFixResponse(quickFixes.Distinct() - .OrderBy(q => q.FileName) - .ThenBy(q => q.Line) - .ThenBy(q => q.Column)); + locations.AddRange(definitionLocations); } - return response; + var quickFixes = locations.Distinct().Select(l => l.GetQuickFix(_workspace)); + + return new QuickFixResponse(quickFixes.Distinct() + .OrderBy(q => q.FileName) + .ThenBy(q => q.Line) + .ThenBy(q => q.Column)); } } } diff --git a/tests/OmniSharp.Roslyn.CSharp.Tests/FindReferencesFacts.cs b/tests/OmniSharp.Roslyn.CSharp.Tests/FindReferencesFacts.cs index 3f5a1707c4..1c39a37c5c 100644 --- a/tests/OmniSharp.Roslyn.CSharp.Tests/FindReferencesFacts.cs +++ b/tests/OmniSharp.Roslyn.CSharp.Tests/FindReferencesFacts.cs @@ -159,6 +159,35 @@ public FooConsumer() Assert.Equal(2, usages.QuickFixes.Count()); } + [Fact] + public async Task CanFindReferencesOfPublicIndexerProperty() + { + const string code = @" + public class Foo + { + int prop; + + public int th$$is[int index] + { + get { return prop; } + set { prop = value; } + } + } + + public class FooConsumer + { + public FooConsumer() + { + var foo = new Foo(); + var prop = foo[0]; + foo[0] = prop; + } + }"; + + var usages = await FindUsagesAsync(code); + Assert.Equal(3, usages.QuickFixes.Count()); + } + [Fact] public async Task CanFindReferencesOfClass() {