我有遗留的c++代码,我应该删除不使用的代码。问题是代码库很大。
我如何才能知道哪些代码从未被调用/从未被使用?
我有遗留的c++代码,我应该删除不使用的代码。问题是代码库很大。
我如何才能知道哪些代码从未被调用/从未被使用?
当前回答
CppDepend是一个商业工具,它可以检测未使用的类型、方法和字段,以及做更多的事情。它适用于Windows和Linux(但目前不支持64位),并有两周的试用期。
免责声明:我不在那里工作,但我拥有这个工具的许可证(以及NDepend,它是。net代码的一个更强大的替代方案)。
对于那些好奇的人来说,这里有一个内置的(可定制的)检测死方法的规则示例,用CQLinq编写:
// <Name>Potentially dead Methods</Name>
warnif count > 0
// Filter procedure for methods that should'nt be considered as dead
let canMethodBeConsideredAsDeadProc = new Func<IMethod, bool>(
m => !m.IsPublic && // Public methods might be used by client applications of your Projects.
!m.IsEntryPoint && // Main() method is not used by-design.
!m.IsClassConstructor &&
!m.IsVirtual && // Only check for non virtual method that are not seen as used in IL.
!(m.IsConstructor && // Don't take account of protected ctor that might be call by a derived ctors.
m.IsProtected) &&
!m.IsGeneratedByCompiler
)
// Get methods unused
let methodsUnused =
from m in JustMyCode.Methods where
m.NbMethodsCallingMe == 0 &&
canMethodBeConsideredAsDeadProc(m)
select m
// Dead methods = methods used only by unused methods (recursive)
let deadMethodsMetric = methodsUnused.FillIterative(
methods => // Unique loop, just to let a chance to build the hashset.
from o in new[] { new object() }
// Use a hashet to make Intersect calls much faster!
let hashset = methods.ToHashSet()
from m in codeBase.Application.Methods.UsedByAny(methods).Except(methods)
where canMethodBeConsideredAsDeadProc(m) &&
// Select methods called only by methods already considered as dead
hashset.Intersect(m.MethodsCallingMe).Count() == m.NbMethodsCallingMe
select m)
from m in JustMyCode.Methods.Intersect(deadMethodsMetric.DefinitionDomain)
select new { m, m.MethodsCallingMe, depth = deadMethodsMetric[m] }
其他回答
这取决于创建应用程序时使用的平台。
例如,如果你使用Visual Studio,你可以使用像. net ANTS Profiler这样的工具来解析和分析你的代码。通过这种方式,您应该很快知道实际使用了代码的哪一部分。Eclipse也有等效的插件。
否则,如果您需要知道最终用户实际使用了应用程序的哪些功能,并且您可以轻松地发布应用程序,则可以使用日志文件进行审计。
对于每个主要函数,您可以跟踪它的使用情况,并在几天/一周后获取日志文件,并查看它。
Mark as much public functions and variables as private or protected without causing compilation error, while doing this, try to also refactor the code. By making functions private and to some extent protected, you reduced your search area since private functions can only be called from the same class (unless there are stupid macro or other tricks to circumvent access restriction, and if that's the case I'd recommend you find a new job). It is much easier to determine that you don't need a private function since only the class you're currently working on can call this function. This method is easier if your code base have small classes and is loosely coupled. If your code base does not have small classes or have very tight coupling, I suggest cleaning those up first.
接下来将标记所有剩余的公共函数,并制作一个调用图,以找出类之间的关系。从这棵树上,试着找出树枝的哪一部分看起来可以修剪。
这种方法的优点是你可以在每个模块的基础上进行测试,所以当你的代码库损坏时,你很容易通过单元测试,而不会有很长一段时间。
我认为您正在寻找一个代码覆盖工具。代码覆盖工具将在代码运行时分析它,它将让您知道哪些代码行被执行了,执行了多少次,以及哪些代码没有执行。
您可以尝试使用这个开源代码覆盖工具:TestCocoon—用于C/ c++和c#的代码覆盖工具。
你可以尝试使用Gimple Software的PC-lint/FlexeLint。它声称
找到未使用的宏,typedef, 类、成员、声明等。 贯穿整个项目
我曾用它进行静态分析,并发现它非常好,但我必须承认,我没有专门用它来查找死代码。
有两种未使用的代码:
局部路径,即在某些函数中,某些路径或变量未使用(或使用但没有任何意义,如写入但从未读取) 全局的:永远不会调用的函数,永远不会访问的全局对象
对于第一种类型,一个好的编译器可以帮助:
-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++语言规则,并且您将能够集中精力处理手头的问题。
然而,这种技术不能识别未使用的虚拟覆盖,因为它们可能由您无法推理的第三方代码调用。