Pawcio
Pawcio

Reputation: 490

How to open Visual Studio code editor at given Roslyn SyntaxNode?

Given a SyntaxNode instance, how can I open appropriate source code file and place cursor at position where the node resides?

I'm writing some simple analyzer. I'm able start it on demand and get a syntax node from current cursor position. But I can't figure out how do I get back to editor from result syntax node. I see the node has a Span property but other than that I don't see any info. The Node I want to show can be in some other file that may not be even opened.

I would like to have behavior similar to "go to..." command for the result of my search.

Upvotes: 3

Views: 311

Answers (2)

Pawcio
Pawcio

Reputation: 490

I spend whole day on this but finally got it.

private void selectNodeInEditor(SyntaxNode n) {
    var cm = (IComponentModel)Package.GetGlobalService(typeof(SComponentModel));
    var tm = (IVsTextManager)Package.GetGlobalService(typeof(SVsTextManager));
    var ws = (Workspace)cm.GetService<VisualStudioWorkspace>();
    var did = ws.CurrentSolution.GetDocumentId(n.SyntaxTree);
    ws.OpenDocument(did);
    tm.GetActiveView(1, null, out var av);
    var sp = n.GetLocation().GetMappedLineSpan().StartLinePosition;
    var ep = n.GetLocation().GetMappedLineSpan().EndLinePosition;
    av.SetSelection(sp.Line, sp.Character, ep.Line, ep.Character);
}

Upvotes: 3

MattB
MattB

Reputation: 149

Syntax nodes have a GetLocation() method, which returns a Microsoft.CodeAnalysis.Location for that syntax node, so that's one way to get a location object from the SyntaxNode.

var nodeLocation = syntaxNode.GetLocation();

You can also get location information from a symbol using the Locations property on the ISymbol interface, if you happen to need the symbol as well. From the docs:

Gets the locations where the symbol was originally defined, either in source or metadata. Some symbols (for example, partial classes) may be defined in more than one location.

https://learn.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.isymbol?view=roslyn-dotnet

This may be prefereable, as depending on the type of the SyntaxNode, you may want to get the symbol's original definition rather than the symbol itself e.g. you could get a class declaration from a field's type. This can be done with the OriginalDefinition property.

// assumes there's a SemanticModel in scope and your node is called synatxNode
var syntaxNodeSymbol = semanticModel.GetSymbolInfo(syntaxNode).Symbol;

// make sure syntaxNodeSymbol is null checked

var nodeLocation = syntaxNodeSymbol.Locations[0];
var originalNodeLocation = syntaxNodeSymbol.OriginalDefinition.Locations[0];

As for actually jumping to the node, this question would probably be a good place to start: Go to definition from text position with roslyn

However, this is already possible in Visual Studio by double clicking on the message in the error list panel. Furthermore, any code fixes you want to make at that location will show up in the code fix window.

Upvotes: 1

Related Questions