从 Roslyn 的 goto 案例中获取符号
Get symbol from goto case in Roslyn
我正在尝试从 GotoStatementSyntax 获取标签的符号,下面的代码适用于带标签的语句,但不适用于 case 标签:
public override void VisitGotoStatement(GotoStatementSyntax node)
{
var symbol = Model.GetSymbolInfo(node.Expression).Symbol;
}
我发现 here 在 2012 年不受支持。现在仍然如此,还是有办法从 goto case 语句中获取符号?
实际上有两种获取标签语句的方法。
可以使用SemanticModel.LookupLabels
方法获取关联的标注符号。不过找出正确的名称参数有点棘手:
var name = node.CaseOrDefaultKeyword.ValueText != null
? string.Join(" ", new[] { node.CaseOrDefaultKeyword.Text, node.Expression?.ToString() }.Where(x => x != null)) + ":"
: node.Expression.ToString();
var label = Model.LookupLabels(node.SpanStart, name).OfType<ILabelSymbol>().SingleOrDefault();
A GotoStatementSyntax
解析为 IBranchStatement
操作,其中包含对目标标签符号的引用:
var label = ((IBranchStatement)Model.GetOperation(node)).Target;
两个代码片段都给你相同的 ILabelSymbol
。
这是我用来重现问题的 LinqPad 脚本:
async Task Test()
{
var ws = new AdhocWorkspace();
var proj = ws.AddProject("test", "C#");
var tree = SyntaxFactory.ParseSyntaxTree(@"
public class Program
{
public static void Main()
{
var i = System.Environment.GetCommandLineArgs().Length;
switch (i)
{
case 1: goto case 2;
case 2: goto default;
case 3: goto wat;
default: break;
}
wat:
return;
}
}");
var root = tree.GetRoot();
var doc = proj.AddDocument("file1.cs", root);
proj = doc.Project.AddMetadataReference(MetadataReference.CreateFromFile(typeof(object).Assembly.Location));
var compilation = await proj.GetCompilationAsync();
var model = compilation.GetSemanticModel(tree);
var walker = new Walker { Model = model };
walker.Visit(root);
}
class Walker : CSharpSyntaxWalker
{
public SemanticModel Model { get; set; }
public override void VisitGotoStatement(GotoStatementSyntax node)
{
var name = node.CaseOrDefaultKeyword.ValueText != null
? string.Join(" ", new[] { node.CaseOrDefaultKeyword.Text, node.Expression?.ToString() }.Where(x => x != null)) + ":"
: node.Expression.ToString();
var label = Model.LookupLabels(node.SpanStart, name).OfType<ILabelSymbol>().SingleOrDefault();
var label2 = ((IBranchStatement)Model.GetOperation(node)).Target;
// (label == label2).Dump();
base.VisitGotoStatement(node);
}
}
我正在尝试从 GotoStatementSyntax 获取标签的符号,下面的代码适用于带标签的语句,但不适用于 case 标签:
public override void VisitGotoStatement(GotoStatementSyntax node)
{
var symbol = Model.GetSymbolInfo(node.Expression).Symbol;
}
我发现 here 在 2012 年不受支持。现在仍然如此,还是有办法从 goto case 语句中获取符号?
实际上有两种获取标签语句的方法。
可以使用
SemanticModel.LookupLabels
方法获取关联的标注符号。不过找出正确的名称参数有点棘手:var name = node.CaseOrDefaultKeyword.ValueText != null ? string.Join(" ", new[] { node.CaseOrDefaultKeyword.Text, node.Expression?.ToString() }.Where(x => x != null)) + ":" : node.Expression.ToString(); var label = Model.LookupLabels(node.SpanStart, name).OfType<ILabelSymbol>().SingleOrDefault();
A
GotoStatementSyntax
解析为IBranchStatement
操作,其中包含对目标标签符号的引用:var label = ((IBranchStatement)Model.GetOperation(node)).Target;
两个代码片段都给你相同的 ILabelSymbol
。
这是我用来重现问题的 LinqPad 脚本:
async Task Test()
{
var ws = new AdhocWorkspace();
var proj = ws.AddProject("test", "C#");
var tree = SyntaxFactory.ParseSyntaxTree(@"
public class Program
{
public static void Main()
{
var i = System.Environment.GetCommandLineArgs().Length;
switch (i)
{
case 1: goto case 2;
case 2: goto default;
case 3: goto wat;
default: break;
}
wat:
return;
}
}");
var root = tree.GetRoot();
var doc = proj.AddDocument("file1.cs", root);
proj = doc.Project.AddMetadataReference(MetadataReference.CreateFromFile(typeof(object).Assembly.Location));
var compilation = await proj.GetCompilationAsync();
var model = compilation.GetSemanticModel(tree);
var walker = new Walker { Model = model };
walker.Visit(root);
}
class Walker : CSharpSyntaxWalker
{
public SemanticModel Model { get; set; }
public override void VisitGotoStatement(GotoStatementSyntax node)
{
var name = node.CaseOrDefaultKeyword.ValueText != null
? string.Join(" ", new[] { node.CaseOrDefaultKeyword.Text, node.Expression?.ToString() }.Where(x => x != null)) + ":"
: node.Expression.ToString();
var label = Model.LookupLabels(node.SpanStart, name).OfType<ILabelSymbol>().SingleOrDefault();
var label2 = ((IBranchStatement)Model.GetOperation(node)).Target;
// (label == label2).Dump();
base.VisitGotoStatement(node);
}
}