我有遗留的c++代码,我应该删除不使用的代码。问题是代码库很大。
我如何才能知道哪些代码从未被调用/从未被使用?
我有遗留的c++代码,我应该删除不使用的代码。问题是代码库很大。
我如何才能知道哪些代码从未被调用/从未被使用?
当前回答
我不认为它可以自动完成。
即使使用代码覆盖工具,也需要提供足够的输入数据来运行。
可能是非常复杂和昂贵的静态分析工具,如Coverity的或LLVM编译器可能会有所帮助。
但我不确定,我更喜欢手动代码审查。
更新
嗯. .不过,仅删除未使用的变量和未使用的函数并不难。
更新
看了其他人的回答和评论后,我更加坚定地认为这是不可能的。
您必须了解代码以获得有意义的代码覆盖率度量,如果您知道大量的手动编辑将比准备/运行/检查覆盖率结果更快。
其他回答
我自己没有使用过cppcheck,但它声称可以找到未使用的函数。这也许不能完全解决问题,但可能是个开始。
GNU链接器有一个——cref选项,用于生成交叉引用信息。你可以通过-Wl,——cref从gcc命令行传递它。
例如,假设foo。O定义了一个符号foo_sym,也在bar.o中使用。然后在输出中你会看到:
foo_sym foo.o
bar.o
如果foo_sym限制为foo。O,那么你不会看到任何额外的目标文件;后面会跟着另一个符号:
foo_sym foo.o
force_flag options.o
现在,从这里我们不知道是否使用了foo_sym。它只是一个候选:我们知道它是在一个文件中定义的,而没有在其他任何文件中使用。Foo_sym可以在foo中定义。O和用于那里。
那么,你该怎么处理这些信息呢
执行一些文本修改,以识别限制在一个目标文件中的这些符号,生成候选列表。 进入源代码,给每个候选对象提供带有静态的内部链接,就像它应该有的那样。 重新编译源代码。 现在,对于那些真正未使用的符号,编译器将能够警告,为你精确定位它们;你可以删除它们。
当然,我忽略了其中一些符号是故意不使用的可能性,因为它们是为动态链接而导出的(即使在链接可执行文件时也可能出现这种情况);这是一种更微妙的情况,你必须了解并明智地处理。
有两种未使用的代码:
局部路径,即在某些函数中,某些路径或变量未使用(或使用但没有任何意义,如写入但从未读取) 全局的:永远不会调用的函数,永远不会访问的全局对象
对于第一种类型,一个好的编译器可以帮助:
-Wunused (GCC, Clang)应该警告未使用的变量,Clang未使用的分析器甚至已经增加到警告从未读取的变量(即使使用)。 -Wunreachable-code(旧的GCC,在2010年被移除)应该警告从未被访问的局部块(它发生在早期返回或条件总是计算为true时) 据我所知,没有选项可以警告未使用的catch块,因为编译器通常不能证明没有异常将被抛出。
对于第二种,要困难得多。静态地,它需要整个程序的分析,即使链接时间优化实际上可以删除死代码,在实践中,程序在执行时已经进行了如此多的转换,以至于几乎不可能向用户传递有意义的信息。
因此有两种方法:
The theoretic one is to use a static analyzer. A piece of software that will examine the whole code at once in great detail and find all the flow paths. In practice I don't know any that would work here. The pragmatic one is to use an heuristic: use a code coverage tool (in the GNU chain it's gcov. Note that specific flags should be passed during compilation for it to work properly). You run the code coverage tool with a good set of varied inputs (your unit-tests or non-regression tests), the dead code is necessarily within the unreached code... and so you can start from here.
如果您对这个主题非常感兴趣,并且有时间和意愿自己开发一个工具,我建议您使用Clang库来构建这样一个工具。
使用Clang库获取AST(抽象语法树) 从入口点开始执行标记-清除分析
因为Clang将为您解析代码,并执行重载解析,所以您不必处理c++语言规则,并且您将能够集中精力处理手头的问题。
然而,这种技术不能识别未使用的虚拟覆盖,因为它们可能由您无法推理的第三方代码调用。
你可以尝试使用Gimple Software的PC-lint/FlexeLint。它声称
找到未使用的宏,typedef, 类、成员、声明等。 贯穿整个项目
我曾用它进行静态分析,并发现它非常好,但我必须承认,我没有专门用它来查找死代码。
If you are on Linux, you may want to look into callgrind, a C/C++ program analysis tool that is part of the valgrind suite, which also contains tools that check for memory leaks and other memory errors (which you should be using as well). It analyzes a running instance of your program, and produces data about its call graph, and about the performance costs of nodes on the call graph. It is usually used for performance analysis, but it also produces a call graph for your applications, so you can see what functions are called, as well as their callers.
这显然是对页面其他地方提到的静态方法的补充,它只会有助于消除完全不使用的类、方法和函数——它不会帮助找到实际调用的方法内部的死代码。