天天看点

我怎么知道代码中的哪些部分从未使用过?

本文翻译自:How can I know which parts in the code are never used?

I have legacy C++ code that I'm supposed to remove unused code from.

我有遗留的C ++代码,我应该从中删除未使用的代码。

The problem is that the code base is large.

问题是代码库很大。

How can I find out which code is never called/never used?

如何找出从未调用/从未使用过的代码?

#1楼

参考:https://stackoom.com/question/KCKJ/我怎么知道代码中的哪些部分从未使用过

#2楼

CppDepend is a commercial tool which can detect unused types, methods and fields, and do much more.

CppDepend是一个商业工具,可以检测未使用的类型,方法和字段,并做更多。

It is available for Windows and Linux (but currently has no 64-bit support), and comes with a 2-week trial.

它适用于Windows和Linux(但目前没有64位支持),并提供为期2周的试用版。

Disclaimer: I don't work there, but I own a license for this tool (as well as NDepend , which is a more powerful alternative for .NET code).

免责声明:我不在那里工作,但我拥有此工具的许可证(以及NDepend ,这是.NET代码的更强大的替代品)。

For those who are curious, here is an example built-in (customizable) rule for detecting dead methods, written in CQLinq :

对于那些好奇的人,这里有一个用于检测死方法的示例内置(可自定义)规则,用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] }
           

#3楼

I had a friend ask me this very question today, and I looked around at some promising Clang developments, eg ASTMatcher s and the Static Analyzer that might have sufficient visibility in the goings-on during compiling to determine the dead code sections, but then I found this:

我今天有一个朋友问我这个问题,我环顾了一些有希望的Clang开发项目,例如ASTMatcher和静态分析器 ,它们在编译过程中可能具有足够的可见性以确定死代码部分,但后来我发现了这个:

https://blog.flameeyes.eu/2008/01/today-how-to-identify-unused-exported-functions-and-variables

https://blog.flameeyes.eu/2008/01/today-how-to-identify-unused-exported-functions-and-variables

It's pretty much a complete description of how to use a few GCC flags that are seemingly designed for the purpose of identifying unreferenced symbols!

它几乎是一个完整的描述,说明如何使用一些看似为识别未引用符号而设计的GCC标志!

#4楼

The general problem of if some function will be called is NP-Complete.

如果将调用某个函数的一般问题是NP-Complete。

You cannot know in advance in a general way if some function will be called as you won't know if a Turing machine will ever stop.

如果某些功能被调用,您无法事先知道,因为您不知道图灵机是否会停止。

You can get if there's some path (statically) that goes from main() to the function you have written, but that doesn't warrant you it will ever be called.

如果有一些路径(静态地)从main()到你编写的函数,你可以得到,但这并不能保证你将被调用。

#5楼

One way is use a debugger and the compiler feature of eliminating unused machine code during compilation.

一种方法是使用调试器和编译器功能,在编译期间消除未使用的机器代码。

Once some machine code is eliminated the debugger won't let you put a breakpojnt on corresponding line of source code.

一旦消除了一些机器代码,调试器就不会让你在相应的源代码行上放置一个breakpojnt。

So you put breakpoints everywhere and start the program and inspect the breakpoints - those which are in "no code loaded for this source" state correspond to eliminated code - either that code is never called or it has been inlined and you have to perform some minimum analysis to find which of those two happened.

所以你在任何地方放置断点并启动程序并检查断点 - 那些“没有为此源加载的代码”状态对应于被删除的代码 - 要么代码从未被调用,要么已被内联,你必须执行一些最小值分析找出这两者中的哪一个发生了。

At least that's how it works in Visual Studio and I guess other toolsets also can do that.

至少它是如何在Visual Studio中工作的,我猜其他工具集也可以做到这一点。

That's lots of work, but I guess faster than manually analyzing all code.

这是很多工作,但我想比手动分析所有代码更快。

#6楼

It depends of the platform you use to create your application.

这取决于您用于创建应用程序的平台。

For example, if you use Visual Studio, you could use a tool like .NET ANTS Profiler which is able to parse and profile your code.

例如,如果您使用Visual Studio,则可以使用.NET ANTS Profiler之类的工具来解析和分析您的代码。

This way, you should quickly know which part of your code is actually used.

这样,您应该快速了解代码的哪个部分实际使用。

Eclipse also have equivalent plugins.

Eclipse也有相同的插件。

Otherwise, if you need to know what function of your application is actually used by your end user, and if you can release your application easily, you can use a log file for an audit.

否则,如果您需要了解最终用户实际使用的应用程序的功能,并且您可以轻松地发布应用程序,则可以使用日志文件进行审核。

For each main function, you can trace its usage, and after a few days/week just get that log file, and have a look at it.

对于每个主要功能,您可以跟踪其使用情况,并在几天/周后获取该日志文件,并查看它。

继续阅读