在 C++ 中查找非实例化模板代码

发布于 2024-11-03 10:26:38 字数 823 浏览 1 评论 0原文

在 C++ 代码中查找未实例化模板的最佳方法是什么?

我有一个大量使用模板的代码库。 当然,我们希望确保测试覆盖率很高。 对于所有使用的代码,使用 gcov 效果非常好。

但是,未使用的模板会被 gcov 报告为不可执行。

经过一番谷歌搜索后,似乎没有办法强制 g++ 为这些模板发出代码(这只是逻辑上的,编译器应该如何猜测任何类型?) 似乎也没有办法让 gcov 将未实例化的模板代码识别为可运行代码。

是否有任何“开箱即用”的东西可以让我增强 GCC -ftest-coverage -fprofile-arcs 工具生成的文件?通过 GCC 的 gcov 选项文档 ,将整个模板函数体标记为一个块可能就足够了,因为执行永远不会在那里结束。

编辑(背景信息):我正在开发一个仅包含标题的模板库。 我的目标是找到未使用/未经测试的功能。

我知道代码覆盖率是有缺陷的,但找到未实例化的代码是迈向更好地测试代码的非常重要的一步。 目前,我们将检查点宏放在每个函数的开头。 在测试模式下,它们扩展为将一对(文件,行)插入到一组已通过的检查点的全局中的代码。 运行测试后,我们手动读取所有文件并将到达的检查点与所有可用检查点集进行比较。

查找未实例化的代码很重要,例如,由于不直观的 C​​++ 模板优先行为,读者甚至作者希望使用的某个地方可能存在死代码。

What is the best way to find uninstantiated templates in C++ Code?

I have a code base that heavily uses templates.
Of course, we want to make sure that the test coverage is high.
For all used code, this works very well using gcov.

However, unused templates are reported as non-executable by gcov.

After some googling, it appears that there is no way to force g++ to emit code for these templates (which is only logical, how should the compiler guess any types?)
It also appears that there is no way to make gcov recognize the uninstantiated template code as runnable code.

Is there anything "out of the box" that allows me to augment the files generated by the GCC -ftest-coverage -fprofile-arcs instrumentation? By the gcov option documentation of GCC, it would probably be enough to mark the whole template function body as one block since execution will never end up there.

EDIT (background information): I'm working on a header-only template library.
My aim here is to find unused/untested functions.

I know that code coverage is flawed but finding uninstantiated code is a very important step towards better tested code.
Currently, we are putting checkpoint macros at the beginning of each function.
In testing mode, they expand to code that inserts a pair of (file, line) into a global set of passed checkpoints.
After running the tests, we manually read all files and compare the reached checkpoints with the set of all available checkpoints.

Finding uninstantiated code is important, for example, because of unintuitive C++ template precedence behaviour, there might be dead code somewhere that the reader or even the author would expect to be used.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

挥剑断情 2024-11-10 10:26:38

我认为我们的 C++ 测试覆盖率 工具(不是基于 GCC 的)可以正确执行此操作你的观点。

它在编译器看到源代码之前对源代码进行检测;无论模板是否被使用,模板内的代码都会获得“覆盖探测”。该工具的测试覆盖率显示部分知道所有探针的位置;如果模板代码未实例化,则显然无法执行,这就是报告的内容。您不必执行任何“自定义”宏插入或其他,呃,废话。

缺点是,如果您有一个由多种不同类型参数化的模板,并且针对不同的实例化类型执行模板方法 m1 和 m2,则您对 m1 和 m2 的覆盖率将是 100%(毕竟,您执行了插装模板)。目前还不清楚这是否不好;只是这就是如何解释的。

I think our C++ Test Coverage tool (not GCC-based) does this correctly from your point of view.

It instruments the source code before the compiler sees it; code inside templates get "coverage probes" regardless of whether the template gets used or not. The test coverage display portion of the tool knows where all the probes are; if the template code isn't instantiated, it clearly can't be executed that's what will get reported. You don't have to do any "custom" macro insertion or other, er, BS.

The downside is that if you have a template parameterized by several different types, and template method m1 and m2 are executed for different instantiated types, your coverage for m1 and m2 will be 100% (after all, you executed the instrumented template). It isn't clear this is bad; just that it is how this is interpreted.

一世旳自豪 2024-11-10 10:26:38

好吧,因为我不太熟悉 GCC,所以这是一个乏味且非常耗时的解决方案,但至少它有效! :)
该测试依赖于这样一个事实,即在实际实例化之前,即当模板参数中实际不存在依赖名称时,不会检测到模板代码中的某些错误:

template<class T>
struct Example{
  typedef typename T::_123344_non_existent_type instantiation_test;
};

将这样的 typedef 添加到您拥有的每个模板中,然后进行编译。从编译器显示错误的每个结构/类/函数中删除它,并且当代码最终编译时仍然包含此类 typedef 的每个模板永远不会被实例化。或者你很不幸,某些类型确实定义了这样的 _123344_non_existent_type,尽管我会私刑处死对此负责的同事。 ;)

Okay, since I'm not very versed with GCC, here's a tedious and very time-taking solution, but atleast it works! :)
This test relies on the fact, that some errors in template code aren't detected until actual instantiation, i.e. when dependant names don't actually exist in the template parameter:

template<class T>
struct Example{
  typedef typename T::_123344_non_existent_type instantiation_test;
};

Add such a typedef to every template you have, then compile. Remove it from every struct/class/function the compiler displays an error for and every template that still contains such a typedef when the code finally compiles never gets instantiated. Or you're unlucky and some types do define such a _123344_non_existent_type, though I'd lynch the coworker that is responsible for that. ;)

伴我老 2024-11-10 10:26:38

我遇到了同样的问题,所以我编写了一个修改代码覆盖率报告以显示未实例化模板的程序。它不是最优雅的,但它确实有效。

有两个阶段:

  • 在编译之前,您使用使用 Clang 的 Libtooling 编写的 C++ 程序来查找代码中的所有模板,并在它们之前和之后插入注释。
  • 生成测试覆盖率报告后,您运行一个 python 脚本,该脚本会遍历该报告并修改步骤 1 中的注释所包含的行。

因此,基本上它利用了这样一个事实:即使留下了很多代码从二进制文件中,几乎所有内容都最终出现在最终的覆盖率报告中。这个问题中描述的宏是这种方法的灵感(它基本上是它们的自动化版本,不会使源代码混乱)。

到目前为止,我只在我自己的代码中使用过它,但它应该具有普遍性。欢迎提出问题和请求!

I was having this same problem, so I wrote a program that modifies code coverage reports to show uninstantiated templates. It's not the most elegant, but it works.

There are two phases:

  • Before compilation, you use a C++ program written using Clang's Libtooling to find all of the templates in your code and insert comments before and after them.
  • After you've generated a test coverage report, you run a python script which goes through the report and modifies the lines enclosed by the comments from step 1.

So basically it takes advantage of the fact that even though a lot of your code is left out of the binary it pretty much all ends up in the final coverage report. The macros described in this question were the inspiration for this approach (it's basically an automated version of them that doesn't clutter the source code).

I've only used it on my own code so far, but it should generalize. Issues and pull requests welcome!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文