如何处理c和c++源代码来计算静态代码分析的指标?

Tar*_*exx 5 c++ parsing metrics llvm-clang antlr4

我正在扩展一个软件工具来计算软件项目的指标。然后使用这些指标进行静态代码分析。我的任务是为 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 之前,预处理器已启动并解析所有预处理器指令。正如他应该做的那样。

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

这导致了第三次也是当前尝试使用由Antlr生成的 c++ 解析器提供的c++14 语法

在解析器之前不执行任何预处理器。这很好,因为解析了完整的源代码并且忽略了预处理器指令。不好的是解析器似乎没有那么难。它在可以编译的代码上失败,导致 AST 损坏。所以这个解决方案也是不够的。


我的问题是:

  • 在使用 libClang 解析 ac/c++ 源文件或头文件之前,是否可以选择停用预处理器?所以源代码是原封不动的,AST 是完整和详细的。
  • 有没有办法在不提供所有必要的包含目录的情况下解析 ac/c++ 源代码文件,但仍然产生详细的 AST?
  • 由于我没有选择。在分析/解析 c/c++ 源代码时,还有哪些其他方法值得考虑?

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

小智 0

为了回答你的最后一个问题,

因为我已经没有选择了。在分析/解析 c/c++ 源代码时,还有哪些其他方法值得关注?

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

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

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