I'm writing a program that needs to analyze C# code and figure out, for each method invocation, exactly what method of what class is being called. The appropriate tools for this job would seem to be Roslyn, CSharpSyntaxTree and SemanticModel, but they are not working reliably. When I run it on real code, it finds the correct symbol in a few cases, a list of candidates including the correct symbol in a few more, but in most cases, completely fails.
For a reproducible test case, here is a distilled version of the analysis code:
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
class Program {
static void Main(string[] _) {
var compilation = CSharpCompilation.Create("MyCompilation")
.WithOptions(new CSharpCompilationOptions(OutputKind.ConsoleApplication))
.AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Console).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Environment).Assembly.Location),
MetadataReference.CreateFromFile(Path.Combine(
Path.GetDirectoryName(typeof(object).Assembly.Location), "System.Runtime.dll")));
var file = "Class1.cs";
var tree = CSharpSyntaxTree.ParseText(File.ReadAllText(file), CSharpParseOptions.Default, file);
if (tree.GetDiagnostics().Any()) {
foreach (var diagnostic in tree.GetDiagnostics())
Console.Error.WriteLine(diagnostic);
Environment.Exit(1);
}
compilation = compilation.AddSyntaxTrees(tree);
var model = compilation.GetSemanticModel(tree);
var root = tree.GetCompilationUnitRoot();
new Walker(model).Visit(root);
}
}
class Walker: CSharpSyntaxWalker {
public Walker(SemanticModel model) {
this.model = model;
}
public override void VisitInvocationExpression(InvocationExpressionSyntax node) {
base.VisitInvocationExpression(node);
var symbolInfo = model.GetSymbolInfo(node);
Console.WriteLine(node);
Console.WriteLine(symbolInfo.Symbol);
Console.WriteLine(symbolInfo.CandidateSymbols.ToArray());
}
readonly SemanticModel model;
}
I run it on this code:
class Class1 {
void Method1() {
Environment.Exit(0);
}
}
And this is the output:
Environment.Exit(0)
Microsoft.CodeAnalysis.ISymbol[]
So for a static call to the standard library, that should be easy to resolve, it finds no candidate symbols.
What am I missing?
You are looking for InvocationExpressionSyntax. In your example there is no method invocation. I've used this example:
and my code is the following: