如何处理c和c ++源代码以计算指标以进行静态代码分析?

时间:2019-03-21 13:01:55

标签: c++ parsing antlr4 metrics llvm-clang

Iam扩展了软件工具以计算软件项目的指标。 然后将这些度量用于进行静态代码分析。 我的任务是为c和c ++项目实现指标的计算。

在开发过程中,我遇到了一些问题,这些问题导致重置并使用其他工具或编程语言重新开始。 我将按时间顺序并尽可能地陈述我尝试解决的过程,问题和事情。

一些指标:

  • 代码行,用于类,结构,联合,函数/方法和源文件
  • 方法计数(用于类和结构)
  • 复杂性,用于类,结构和函数/方法
  • 类和结构之间的
  • 依赖项

由于c ++是一种难以解析的语言,并且我自己编写c ++解析器的规模过大,因此我倾向于使用现有的c ++解析器。 因此,我开始使用 LLVM项目中的库来收集有关源文件的语法和语义信息。

LLVM工具链接:https://clang.llvm.org/docs/Tooling.html


首先我从用c ++编写的LibTooling开始,因为它向我保证了对抽象语法树(AST)的“完全控制”。 我尝试了RecursiveASTVistorMatchfinder方法,但没有成功。

因此LibTooling被解雇了,因为我无法检索有关AST中节点周围的上下文信息。 当访问AST中的特定节点时,我只能对回调做出反应。但是我不知道我现在是什么情况。 例如。当我访问C ++ RecordDeclaration(类,结构,联合)时,我不知道它是否是嵌套记录。 但是,这些信息对于计算单个类的代码行是必需的。


第二方法是通过Python绑定使用LibClang接口。 使用LibClang接口,我能够递归地遍历AST节点并将所需的上下文信息存储在堆栈中。 在这里,我遇到了LibClang的一个普遍问题:

  

在为文件创建AST之前,将启动预处理器并解析所有预处理器指令。就像他应该做的一样。

  • 这很好,因为如果预处理器无法解析所有include指令,则输出AST将不完整。
  • 这非常糟糕,因为我将无法为任何c ++项目提供所有包含文件或目录。
  • 这很不好,因为无论是否定义了预处理器变量,被条件预处理器指令包围的代码都不是AST的一部分。使用已定义或未定义的预处理器变量的不同设置多次解析同一文件超出了范围。

使用Antlr生成的c ++解析器提供了c++14 grammar,这导致了第三以及当前尝试。

在解析器之前不执行任何预处理器。 这样很好,因为会解析完整的源代码,并且会忽略预处理程序指令。 不好的是,解析器似乎并不那么难。它在可编译的代码上失败,导致AST损坏。因此,这种解决方案还不够。


我的问题是:

  • 在使用libClang解析c / c ++源文件或头文件之前,是否可以选择停用预处理器? 因此,源代码保持不变,并且AST完整而详细。
  • 有没有一种方法可以解析c / c ++源代码文件而不提供所有必需的包含目录,但仍会生成详细的AST?
  • 由于iam用尽了所有选项。在分析/解析c / c ++源代码时,还有哪些其他方法可能值得研究?

如果您认为这不是问此类问题的合适地点,请随时将我重定向到另一个地方。

1 个答案:

答案 0 :(得分:0)

要回答您的最后一个问题,

由于iam用尽了所有选项。还有哪些其他方法可能值得 在考虑何时分析/解析c / c ++源代码?

另一种方法是将源代码解析为仅是文本。这避免了预处理源以及引入复杂的解析器的需要。请参阅本文的示例/简介:“类的概念凝聚力”,作者:Andrian Marcus,Denys Poshyvanyk。您仍然可以通过这种方法收集LOC和方法数量之类的信息,而无需完整的解析器。

这种方法有缺点(与其他任何方法一样):

  • 它要么1)与源代码一起解析注释,要么2)要求您从源代码中删除注释。但是后者是一个简单的步骤。之所以可行,是因为即使注释中也包含有关代码的信息,这可能有助于确定哪些模块更紧密地耦合等等。
  • 它将把局部变量,方法名称,参数名称等全部整合到您正在使用的“单词袋”中。