如何在给定的 Roslyn SyntaxNode 处打开 Visual Studio 代码编辑器?

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

给定一个 SyntaxNode 实例,我如何打开适当的源代码文件并将光标放在节点所在的位置?

我正在编写一些简单的分析器。我可以按需启动它并从当前光标位置获取语法节点。但我不知道如何从结果语法节点返回到编辑器。我看到节点有一个 Span 属性 但除此之外我没有看到任何信息。我要显示的节点可以位于其他一些甚至可能无法打开的文件中。

我希望搜索结果的行为类似于 "go to..." 命令。

语法节点有一个 GetLocation() 方法,该方法 returns 一个 Microsoft.CodeAnalysis.Location 用于该语法节点,因此这是从 SyntaxNode 获取位置对象的一种方法。

var nodeLocation = syntaxNode.GetLocation();

您还可以使用 ISymbol 界面上的 Locations 属性 从符号中获取位置信息,如果您恰好也需要该符号。来自文档:

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://docs.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.isymbol?view=roslyn-dotnet

这可能是更可取的,因为根据 SyntaxNode 的类型,您可能想要获取符号的原始定义而不是符号本身,例如您可以从字段的类型中获得 class 声明。这可以通过 OriginalDefinition 属性.

来完成
// 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];

至于实际跳转到节点,这个问题可能是一个很好的起点: Go to definition from text position with roslyn

但是,在 Visual Studio 中已经可以通过双击错误列表面板中的消息来实现。此外,您要在该位置进行的任何代码修复都将显示在代码修复 window.

我花了一整天的时间终于搞定了。

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);
}