ISanych
ISanych

Reputation: 22680

Get symbol from goto case in Roslyn

I'm trying to get Symbol for label from GotoStatementSyntax, below code works for labeled statements, but not for case labels:

    public override void VisitGotoStatement(GotoStatementSyntax node)
    {
        var symbol = Model.GetSymbolInfo(node.Expression).Symbol;
    }

I found here that is was not supported in 2012. Is it still the case or there is a way to get a symbol from goto case statement?

Upvotes: 2

Views: 227

Answers (1)

m0sa
m0sa

Reputation: 10940

There are actually two ways of getting the labeled statements.

  1. You can use the SemanticModel.LookupLabels method to get the associated label symbol. Finding out the correct name parameter is a bit tricky though:

    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 resolves to an IBranchStatement operation, which contains a reference to the targeted label symbol:

    var label = ((IBranchStatement)Model.GetOperation(node)).Target;
    

Both code snippets give you the same ILabelSymbol.

Here's the LinqPad script I used to repro the question:

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

Upvotes: 1

Related Questions