Skip to content

Commit

Permalink
Merge pull request #1399 from SirIntruder/FixIndexerPropertyReferences
Browse files Browse the repository at this point in the history
Fix find references for indexer properties
  • Loading branch information
filipw authored Mar 19, 2019
2 parents c9d45c0 + 8b2c359 commit 0fcefe1
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,49 +28,38 @@ public async Task<QuickFixResponse> 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<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 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));
}
}
}
29 changes: 29 additions & 0 deletions tests/OmniSharp.Roslyn.CSharp.Tests/FindReferencesFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down

0 comments on commit 0fcefe1

Please sign in to comment.