Amin
Amin

Reputation: 129

Access Invocations reference using Roslyn

I want to create a Visual Studio Extension(VSIX) using Roslyn. This extension should find all invocations, then looks for their definitions to analyse attributes defined on them. The definition of the method can be any where in the solution.

My first class is like this:

namespace MainProject
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(BusinessProject.Calc.AddNumbers(5, 8));
        }
    }
}

My second class is something like the following:

namespace BusinessProject
{
    public class Calc
    {
        [CustomAttr("Do something")]
        public static long AddNumbers(int a, int b)
        {
            return a + b;
        }
    }
}

In above sample, in class Program, I have an invocation of AddNumbers method. I want to 1) analyse the code, 2) find this invocation, 3) get all attributes of the reference method in class Calc, 4) process attributes parameters, 5) and then make a warning/error if needed. I can analyse current class to find all invocations by RegisterCodeBlockAction, But what I can't do is accessing the entire solution to find definition of the invocation and after that, accessing attributes of the reference.

How can I access the entire solution in RegiserCodeBlockAction?

Upvotes: 1

Views: 620

Answers (2)

Amin
Amin

Reputation: 129

As @SLaks mentioned in his comment, by using SemanticModel.Compilation.SyntaxTrees we can access all of the source codes in solution. I found the method and its parameters. But this has a problem which you can't get the TypeInfo of objects using SemanticModel.GetTypeInfo. You have to create a new Semantic Model like as follows:

foreach (var tree in context.SemanticModel.Compilation.SyntaxTrees)
{
    var compilation = CSharpCompilation.Create("MyCompilation",
                    syntaxTrees: new[] { tree }, references: new List<MetadataReference>());
    var syntaxRoot = tree.GetRoot();
    var model = compilation.GetSemanticModel(tree);
    var targetMethod = syntaxRoot.DescendantNodes().OfType<MethodDeclarationSyntax>().FirstOrDefault(f => f.Identifier.ToString() == "Class name to find");
    if (targetMethod == null)
        continue;

    var typeInfo = model.GetTypeInfo(targetMethod.First().ParameterList.Parameters[i].ChildNodes().First());
    // Do any thing with typeInfo
}

Upvotes: 1

SLaks
SLaks

Reputation: 888077

You're calling the wrong method.

You actually want your analyzer to run on every method invocation, not every code block.
Therefore, you should call RegisterSyntaxNodeAction, and pass SyntaxKind.InvocationExpression.

It will then call you with an InvocationExpressionSyntax which has all the information you need (mostly in the Semantic Model).

Upvotes: 2

Related Questions