Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the type of an argument in Roslyn?

Tags:

c#

roslyn

So I am trying to know the type of some variables in the argument when calling a method. Such as in:

class Program
{
    static void Main(string[] args)
    {
        string a = "astring"
        string.Format("zzzz{0}", a);
    }
}

So I want to know the type of variable a in string.Format("zzzz{0}, a"); I am trying to change some code so I am using rewriter and here is what I got:

public class CustomFormatRewriter : CSharpSyntaxRewriter{

    public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax rootNode){
        if (null != rootNode){
            var arguments =
            from n in secondNode.DescendantNodes()
            where (n.Kind() == SyntaxKind.Argument)
            select n;

            foreach (var argument in arguments)
            {
               var compilation = CSharpCompilation.Create("arg")
                                                            .AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location))
                                                     .AddSyntaxTrees(rootNode.SyntaxTree);

               var model = compilation.GetSemanticModel(rootNode.SyntaxTree);
               var symbolInfo = model.GetSymbolInfo(argument);
               Console.WriteLine(symbolInfo.Symbol);
            }
        }  
        return rootNode;
    }

}

But the symbolInfo.Symbol I got is null.

Any idea? Thanks!!

like image 907
Cyan.F Avatar asked Aug 26 '15 16:08

Cyan.F


2 Answers

If you want to know the type of something, you can call SemanticModel.GetTypeInfo. This works for all expressions, not just ones that are directly a variable. So not only will passing the expression for a give you the type of a, but a.SomeMethod() will figure out which overload of SomeMethod is being called on a, and will give you the type of the return. If your expression is just a number, it'll tell you the type is Int32.

GetSymbolInfo only works if the thing you're passing in directly is a reference to a symbol, i.e. it's the name of a local or field or something. In your case, the first argument that's a string isn't going to give you a symbol. It has a type (notably, System.String), but it's not a symbol.

like image 197
Jason Malinowski Avatar answered Sep 22 '22 01:09

Jason Malinowski


Okay I found out why I am always getting null. Post just in case someone may find it helpful in the future.

I found this post very helpful in identifying my problem. So it turns out I am not checking type on the correct "level", as I call it. I used the method in the post(In the syntax visualizer, right click a node -> view typeSymbol) to check for the type of my argument. I found that if I check at "Argument", then there is nothing, which explains why I got null. And if I check the node at the level under the "Argument", it gives you the right type.

So I changed my code to:

var typeInfo = model.GetTypeInfo(argument.ChildNodes().First());
Console.WriteLine(typeInfo);

And it works.

like image 34
Cyan.F Avatar answered Sep 21 '22 01:09

Cyan.F