这是我和我的团队选择为我们的学校项目做的事情。好吧,实际上我们还没有决定如何解析C#源文件。
我们的目标是,对C#源文件执行完整分析,并生成报告。 其中报告将包含代码中发生的内容。
报告只需包含:
我负责调查这个反讽图书馆。说实话,我不知道将数据排序成清晰可读报告的最佳方法。我使用的是带有zip的C#语法类。
是否有任何步骤我可以正确识别每个节点的孩子? (例如:using指令,名称空间声明,类声明等,方法体)
非常感谢任何帮助或建议。感谢。
编辑:抱歉,我忘了说我们也需要分析方法调用。
答案 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); }
}