如何在给定的 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);
}
给定一个 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);
}