Roslyn SemanticModel 符号解析无法可靠工作

问题描述 投票:0回答:1

我正在编写一个程序,需要分析 C# 代码并弄清楚对于每个方法调用,到底调用的是哪个类的哪个方法。适合这项工作的工具似乎是 Roslyn、CSharpSyntaxTree 和 SemanticModel,但它们工作不可靠。当我在真实代码上运行它时,它在少数情况下找到正确的符号,在更多情况下找到包含正确符号的候选列表,但在大多数情况下,完全失败。

对于可重现的测试用例,这里是分析代码的精炼版本:

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

我在这段代码上运行它:

class Class1 {
    void Method1() {
        Environment.Exit(0);
    }
}

这是输出:

Environment.Exit(0)

Microsoft.CodeAnalysis.ISymbol[]

因此,对于对标准库的静态调用,这应该很容易解决,它找不到候选符号。

我错过了什么?

c# .net roslyn
1个回答
0
投票

您正在寻找 InspirationExpressionSyntax。在您的示例中没有方法调用。我用过这个例子:

    using System;
    using System.Text;

    namespace ConsoleApplication1
    {
        class MyClass
        {
            void Method(string input)
            {
                var x = new ArgumentNullException();
            }

            void MethodB(string input)
            {
                Method("TestMe");
            }

            void MethodC(string input)
            {
                MethodB("TestYou");
            }
        }
    }

我的代码如下:

    using Microsoft.CodeAnalysis.CSharp;
    using Microsoft.CodeAnalysis;
    using Microsoft.CodeAnalysis.CSharp.Syntax;

    class Program
    {
        static void Main(string[] _)
        {

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

            var mscorlib = MetadataReference.CreateFromFile(Path.Combine(
                                                     Path.GetDirectoryName(typeof(object).Assembly.Location), "System.Runtime.dll"));
            var compilation = CSharpCompilation.Create("MyCompilation", new[] { tree }, new[] { mscorlib });
            var semanticModel = compilation.GetSemanticModel(tree);

            var root = tree.GetRoot();
            var objectCreationExpression = root.DescendantNodes().OfType<InvocationExpressionSyntax>().ToList();        
            var lstNodes = objectCreationExpression;
            foreach (var item in lstNodes)
            {
                new Walker(semanticModel).Visit(item);
            }

        }
    }

    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;
    }
© www.soinside.com 2019 - 2024. All rights reserved.