2

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.

Pawcio
  • 399
  • 5
  • 15

2 Answers2

3

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);
}
Pawcio
  • 399
  • 5
  • 15
1

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.

MattB
  • 159
  • 2
  • 8
  • Thank you, I found file path in location but still don't know who to open code editor for it. The thing is I don't produce any error/warning nor provide any code fix. I have created my own window for result of the analysis and want to open location from there... – Pawcio Aug 05 '19 at 08:09
  • Do you want to open a new Visual Studio, or Visual Studio code window? It's not entirely clear from the title of your question. – MattB Aug 05 '19 at 08:39
  • Ideally I would like the file to be opened exactly like "Go To Definition" does. I've just tried `DTE.ItemsOperations.Navigate()` and `DTE.ItemsOperations.OpenFile()` with no success – Pawcio Aug 05 '19 at 08:44