用反复分析C#源代码

时间:2011-09-28 04:45:21

标签: c# parsing irony

这是我和我的团队选择为我们的学校项目做的事情。好吧,实际上我们还没有决定如何解析C#源文件。

我们的目标是,对C#源文件执行完整分析,并生成报告。 其中报告将包含代码中发生的内容。

报告只需包含:

  • 字符串文字
  • 方法名称
  • 变量名称
  • 字段名称

我负责调查这个反讽图书馆。说实话,我不知道将数据排序成清晰可读报告的最佳方法。我使用的是带有zip的C#语法类。

是否有任何步骤我可以正确识别每个节点的孩子? (例如:using指令,名称空间声明,类声明等,方法体)

非常感谢任何帮助或建议。感谢。

编辑:抱歉,我忘了说我们也需要分析方法调用。

2 个答案:

答案 0 :(得分:1)

我不确定这是否是您需要的,但您可以使用CodeDom和CodeDom.Compiler命名空间来编译C#代码,然后使用Reflection分析结果,如:

        // Create assamblly in Memory
        CodeSnippetCompileUnit code = new CodeSnippetCompileUnit(classCode);
        CSharpCodeProvider provider = new CSharpCodeProvider();
        CompilerResults results = provider.CompileAssemblyFromDom(compileParams, code);
        foreach(var type in results.CompiledAssembly)
        {
              // Your analysis go here
        }

更新:在VS2015中,您可以使用新的C#编译器(AKA Roslyn)为example:

执行相同操作
var root = (CompilationUnitSyntax)tree.GetRoot();
var compilation = CSharpCompilation.Create("HelloTDN")
            .AddReferences(references: new[] { MetadataReference.CreateFromAssembly(typeof(object).Assembly) })
            .AddSyntaxTrees(tree);
var model = compilation.GetSemanticModel(tree);
var nameInfo = model.GetSymbolInfo(root.Usings[0].Name);
var systemSymbol = (INamespaceSymbol)nameInfo.Symbol;
foreach (var ns in systemSymbol.GetNamespaceMembers())
{
   Console.WriteLine(ns.Name);
}

答案 1 :(得分:1)

您的主要目标是掌握正式语言的基础知识。可能会找到一个好的初创公司here。本文介绍了在简单数字计算器的语法示例中使用Irony的方法。

假设您要解析包含C#代码的某个文件,您知道的路径为:

private void ParseForLongMethods(string path)
    {
        _parser = new Parser(new CSharpGrammar());
        if (_parser == null || !_parser.Language.CanParse()) return;
        _parseTree = null;
        GC.Collect(); //to avoid disruption of perf times with occasional collections
        _parser.Context.SetOption(ParseOptions.TraceParser, true);
        try
        {
            string contents = File.ReadAllText(path);
            _parser.Parse(contents);//, "<source>");
        }
        catch (Exception ex)
        {
        }
        finally
        {
            _parseTree = _parser.Context.CurrentParseTree;
            TraverseParseTree();
        }
    }

这是遍历方法本身,在节点中计算一些信息。实际上,此代码计算类的每个方法中的语句数。如果您有任何疑问,欢迎您随时来问我

 private void TraverseParseTree()
        {
            if (_parseTree == null) return;
            ParseNodeRec(_parseTree.Root);
        }
        private void ParseNodeRec(ParseTreeNode node)
        {
            if (node == null) return;
            string functionName = "";
            if (node.ToString().CompareTo("class_declaration") == 0)
            {
                ParseTreeNode tmpNode = node.ChildNodes[2];
                currentClass = tmpNode.AstNode.ToString();
            }
            if (node.ToString().CompareTo("method_declaration") == 0)
            {
                foreach (var child in node.ChildNodes)
                {
                    if (child.ToString().CompareTo("qual_name_with_targs") == 0)
                    {
                        ParseTreeNode tmpNode = child.ChildNodes[0];
                        while (tmpNode.ChildNodes.Count != 0)
                        { tmpNode = tmpNode.ChildNodes[0]; }
                        functionName = tmpNode.AstNode.ToString();
                    }
                    if (child.ToString().CompareTo("method_body") == 0)  //method_declaration
                    {
                        int statementsCount = FindStatements(child);
                        //Register bad smell
                        if (statementsCount>(((LongMethodsOptions)this.Options).MaxMethodLength))
                        {
                            //function.StartPoint.Line
                            int functionLine = GetLine(functionName);
                            foundSmells.Add(new BadSmellRegistry(name, functionLine,currentFile,currentProject,currentSolution,false));
                        }
                    }
                }
            }
            foreach (var child in node.ChildNodes)
            { ParseNodeRec(child); }
        }