Skip to content

Commit

Permalink
Have go-to-def flip between partial definition and implementation (#7…
Browse files Browse the repository at this point in the history
  • Loading branch information
CyrusNajmabadi authored Dec 3, 2024
2 parents 64aa047 + 46a8af2 commit 6c2553e
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -126,23 +126,21 @@ async ValueTask<ImmutableArray<DefinitionItem>> GetInterceptorDefinitionsAsync(
{
var solution = project.Solution;

var sourceLocations = symbol.Locations.WhereAsArray(loc => loc.IsInSource);
if (sourceLocations.Length != 1)
if (symbol.DeclaringSyntaxReferences is not [{ SyntaxTree: { } definitionTree, Span: var definitionSpan }])
return null;

var definitionLocation = sourceLocations[0];
if (!definitionLocation.SourceSpan.IntersectsWith(position))
if (!definitionSpan.IntersectsWith(position))
return null;

var definitionTree = definitionLocation.SourceTree;
var definitionDocument = solution.GetDocument(definitionTree);
if (definitionDocument != originalDocument)
return null;

// Ok, we were already on the definition. Look for better symbols we could show results for instead. This can be
// expanded with other mappings in the future if appropriate.
return await TryGetExplicitInterfaceLocationAsync().ConfigureAwait(false) ??
await TryGetInterceptedLocationAsync().ConfigureAwait(false);
await TryGetInterceptedLocationAsync().ConfigureAwait(false) ??
await TryGetOtherPartOfPartialAsync().ConfigureAwait(false);

async ValueTask<INavigableLocation?> TryGetExplicitInterfaceLocationAsync()
{
Expand Down Expand Up @@ -251,6 +249,24 @@ async ValueTask<ImmutableArray<DefinitionItem>> GetInterceptorDefinitionsAsync(
});
}
}
async ValueTask<INavigableLocation?> TryGetOtherPartOfPartialAsync()
{
ISymbol? otherPart = symbol is IMethodSymbol method ? method.PartialDefinitionPart ?? method.PartialImplementationPart : null;
otherPart ??= symbol is IPropertySymbol property ? property.PartialDefinitionPart ?? property.PartialImplementationPart : null;

if (otherPart is null || Equals(symbol, otherPart))
return null;

if (otherPart.Locations is not [{ SourceTree: { } sourceTree, SourceSpan: var span }])
return null;

var document = solution.GetDocument(sourceTree);
if (document is null)
return null;

var documentSpan = new DocumentSpan(document, span);
return await documentSpan.GetNavigableLocationAsync(cancellationToken).ConfigureAwait(false);
}
}

private static async Task<bool> IsThirdPartyNavigationAllowedAsync(
Expand Down
118 changes: 118 additions & 0 deletions src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb
Original file line number Diff line number Diff line change
Expand Up @@ -4153,6 +4153,124 @@ public partial class Program
End Using
End Function

<WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/76156")>
Public Async Function TestCSharpGotoDefinitionOnPartialMethodDefinition() As Task
Dim workspace =
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
partial class Test
{
partial void $$M();
}
</Document>
<Document>
partial class Test
{
partial void [|M|]()
{
throw new NotImplementedException();
}
}
</Document>
</Project>
</Workspace>

Await TestAsync(workspace)
End Function

<WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/76156")>
Public Async Function TestCSharpGotoDefinitionOnPartialMethodImplementation() As Task
Dim workspace =
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
partial class Test
{
partial void [|M|]();
}
</Document>
<Document>
partial class Test
{
partial void $$M()
{
throw new NotImplementedException();
}
}
</Document>
</Project>
</Workspace>

Await TestAsync(workspace)
End Function

<WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/76156")>
Public Async Function TestCSharpGotoDefinitionOnPartialPropertyDefinition() As Task
Dim workspace =
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
partial class Test
{
public partial string $$Prop { get; set; }
}
</Document>
<Document>
partial class Test
{
public partial string [|Prop|]
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
}
</Document>
</Project>
</Workspace>

Await TestAsync(workspace)
End Function

<WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/76156")>
Public Async Function TestCSharpGotoDefinitionOnPartialPropertyImplementation() As Task
Dim workspace =
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
partial class Test
{
public partial string [|Prop|] { get; set; }
}
</Document>
<Document>
partial class Test
{
public partial string $$Prop
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
}
</Document>
</Project>
</Workspace>

Await TestAsync(workspace)
End Function

#Enable Warning RSEXPERIMENTAL002 ' Type is for evaluation purposes only and is subject to change or removal in future updates.
End Class
End Namespace
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@ Imports Microsoft.CodeAnalysis.GoToDefinition
Imports Microsoft.CodeAnalysis.Navigation
Imports Microsoft.CodeAnalysis.Options
Imports Microsoft.CodeAnalysis.Shared.TestHooks
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.VisualStudio.Text
Imports Microsoft.VisualStudio.Text.Editor.Commanding.Commands
Imports Microsoft.VisualStudio.Utilities
Imports Roslyn.Utilities

Namespace Microsoft.CodeAnalysis.Editor.UnitTests.GoToDefinition
<UseExportProvider, Trait(Traits.Feature, Traits.Features.GoToDefinition)>
Public Class GoToDefinitionCommandHandlerTests
Public NotInheritable Class GoToDefinitionCommandHandlerTests
<WpfFact>
Public Async Function TestInLinkedFiles() As Task
Dim definition =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ public bool IsBindableToken(SyntaxToken token)
{
if (this.IsWord(token) || this.IsLiteral(token) || this.IsOperator(token))
{
switch ((SyntaxKind)token.RawKind)
switch (token.Kind())
{
case SyntaxKind.DelegateKeyword:
case SyntaxKind.VoidKeyword:
Expand Down

0 comments on commit 6c2553e

Please sign in to comment.