C#通过Roslyn获取代码中的引用及签名

Roslyn可以对代码进行分析,查找代码并替换代码。参考文档如下:

https://roslynquoter.azurewebsites.net/
https://devblogs.microsoft.com/visualstudio/roslyn-syntax-visualizers/
https://jonskeet.uk/csharp/index.html
https://joshvarty.com/2014/07/06/learn-roslyn-now-part-2-analyzing-syntax-trees-with-linq/
https://joshvarty.com/learn-roslyn-now/

有这么一个需求:找到代码中所有的引用并打印出来。

如果是手动查找的话,容易出错且工作量比较大,因此通过Roslyn可以自动地将代码的信息提取出来。步骤如下:

1.DemoApp,一个简单的函数,有四个地方引用这个函数,现在需要做的是通过Roslyn查找四个引用

    class Program
    {
        /// <summary>
        /// 方法入口123
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {

            var c1 = Plus(1, 2);
            var c2 = Plus(3, 4);
            var c3 = Plus(5,55);
            var c4 = Plus(6, 666);




        }

        static int Plus(int a,int b)
        {
            return a + b;
        }
    }

 

2.初始化Roslyn

初始化包含: MSBuildLocator.RegisterDefaults(); MSBuildWorkspace.Create(); workspace.OpenSolutionAsync() 等方法。

 Init();
            
            var workspace = MSBuildWorkspace.Create();
            workspace.SkipUnrecognizedProjects = true;
            workspace.LoadMetadataForReferencedProjects = false;


            workspace.WorkspaceFailed += Workspace_WorkspaceFailed;
            var solution = workspace.OpenSolutionAsync(@"D:\测试代码\2022-06-27-DemoApp\2022-06-27-DemoApp.sln").Result;

  

3.找到引用:

  var machineMgrProj = solution.Projects.FirstOrDefault(x => x.Name == projectName);
            var sysLogDoc = machineMgrProj.Documents.FirstOrDefault(x => x.Name == csFileName);

            var semanticModel2 = sysLogDoc.GetSemanticModelAsync().Result;
            var rootNode2 = sysLogDoc.GetSyntaxRootAsync().Result;

            var nodeClass = rootNode2.DescendantNodes().OfType<ClassDeclarationSyntax>()
                .FirstOrDefault(x => x.Identifier.ToString() == className1);


            var nodeMethod = nodeClass.DescendantNodes()
                .OfType<MethodDeclarationSyntax>().FirstOrDefault(x => x.Identifier.ToString() == methodName && x.ParameterList.ToString() == methodParListString);
             
            var sampleMethodSymbol1 = semanticModel2.GetDeclaredSymbol(nodeMethod);


            var referencesToSampleMethod2 = SymbolFinder.FindReferencesAsync(sampleMethodSymbol1, solution).Result;

  

4.解析引用:

  //文件名
                    var fileName = location.Document.Name;


                    //syntex tree
                    var syntaxTree = location.Location.SourceTree;

                    var root = syntaxTree.GetRoot();

                    //class node
                    var cc1c = root.DescendantNodes().OfType<ClassDeclarationSyntax>().First();

                    //类名
                    var className = cc1c.Identifier.ValueText;

                    if (!fileName.Contains(".cs"))
                    {
                    }

                    //location node-inovation node
                    var nodeFind = syntaxTree.GetRoot().FindNode(location.Location.SourceSpan);

                    //method node
                    var parentMethod = GetParentMethod<MethodDeclarationSyntax>(nodeFind);

                    //方法名
                    var methodName1 = parentMethod.Identifier.ValueText;


                    //方法注释
                    //method token 
                    var t1 = parentMethod.DescendantTokens();


                    var t2 = t1
                        .Where(x => x.IsKind(SyntaxKind.PrivateKeyword) || x.IsKind(SyntaxKind.PublicKeyword) ||
                                    x.IsKind(SyntaxKind.ProtectedKeyword)||x.IsKind(SyntaxKind.StaticKeyword)).FirstOrDefault();


                    //token的细节信息
                    var trivia = t2.LeadingTrivia.Where(x =>
                            x.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia) ||
                            x.IsKind(SyntaxKind.MultiLineCommentTrivia))
                        .FirstOrDefault();
                    var comment = GetComment(trivia);


                    //参数

                    var invocation = GetParentMethod<InvocationExpressionSyntax>(nodeFind);


                    var parameter = invocation.DescendantNodes().OfType<ArgumentListSyntax>()
                        .Where(x => x.Span.Start >= nodeFind.Span.End).First();
                    var argumentss = parameter.DescendantNodes().OfType<ArgumentSyntax>().ToList();

 

最后,效果如下图,查找到了4个引用,及引用的参数值

 

 

  

 

 

 

源码下载:https://files.cnblogs.com/files/congqiandehoulai/%E6%B5%8B%E8%AF%95N%E6%96%B9%E6%B3%95%E6%AC%A1%E6%95%B0_2.rar

https://files.cnblogs.com/files/congqiandehoulai/2022-06-27-DemoApp.rar

 

posted @ 2022-06-27 20:28  灰主流  阅读(439)  评论(0编辑  收藏  举报