从 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 语句中获取符号?

实际上有两种获取标签语句的方法。

  1. 可以使用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();
    
  2. 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);
    }
}