Поиск неинстанцированных шаблонов в коде C++

Каков наилучший способ найти необоснованные шаблоны в коде C++?

У меня есть кодовая база, которая интенсивно использует шаблоны. Конечно, мы хотим убедиться, что тестовое покрытие является высоким. Для всего используемого кода это работает очень хорошо, используя gcov,

Тем не менее, неиспользуемые шаблоны сообщаются как неисполняемые gcov,

После некоторого поиска в Google, кажется, что нет никакого способа заставить g++ испускать код для этих шаблонов (что логично, как компилятор должен угадывать какие-либо типы?) Также представляется, что нет способа заставить gcov распознавать необоснованный код шаблона как исполняемый код.

Есть ли что-нибудь "из коробки", что позволяет мне увеличивать файлы, сгенерированные GCC -ftest-coverage -fprofile-arcs измерительные приборы? С помощью документации по опциям gcov в GCC, вероятно, будет достаточно отметить все тело функции шаблона как один блок, так как выполнение никогда не закончится там.

РЕДАКТИРОВАТЬ (справочная информация): я работаю над библиотекой шаблонов только для заголовка. Моя цель здесь - найти неиспользуемые / непроверенные функции.

Я знаю, что покрытие кода имеет недостатки, но поиск неосуществленного кода является очень важным шагом на пути к лучшему тестированию кода. В настоящее время мы помещаем макросы контрольных точек в начале каждой функции. В режиме тестирования они расширяются до кода, который вставляет пару (file, line) в глобальный набор пройденных контрольных точек. После запуска тестов мы вручную читаем все файлы и сравниваем достигнутые контрольные точки с набором всех доступных контрольных точек.

Поиск неосуществленного кода важен, например, из-за неинтуитивного поведения приоритета шаблона C++, где-то может быть мертвый код, который читатель или даже автор ожидают использовать.

3 ответа

Я думаю, что наш C++ Test Coverage (не на основе GCC) делает это правильно с вашей точки зрения.

Он обрабатывает исходный код до того, как его увидит компилятор; код внутри шаблонов получает "пробники покрытия" независимо от того, используется шаблон или нет. Часть отображения тестового покрытия инструмента знает, где находятся все зонды; если код шаблона не создан, он явно не может быть выполнен, о чем будет сообщено. Вам не нужно делать какую-либо "пользовательскую" вставку макроса или что-то еще, например, BS.

Недостатком является то, что если у вас есть шаблон, параметризованный несколькими различными типами, и метод шаблона m1 и m2 выполняются для различных экземпляров типов, ваше покрытие для m1 и m2 будет 100% (в конце концов, вы выполнили инструментальный шаблон). Не ясно, что это плохо; просто это то, как это интерпретируется.

У меня возникла такая же проблема, поэтому я написал программу, которая модифицирует отчеты о покрытии кода, чтобы показывать необоснованные шаблоны. Это не самый элегантный, но работает.

Есть две фазы:

  • Перед компиляцией вы используете программу на C++, написанную с помощью Libtooling Clang, чтобы найти все шаблоны в вашем коде и вставить комментарии до и после них.
  • После того, как вы сгенерировали отчет о тестовом покрытии, вы запускаете скрипт python, который просматривает отчет и модифицирует строки, заключенные в комментарии из шага 1.

Таким образом, в основном используется тот факт, что, хотя большая часть вашего кода не включена в двоичный код, в конечном итоге все это заканчивается в окончательном отчете о покрытии. Макросы, описанные в этом вопросе, послужили источником вдохновения для этого подхода (в основном это их автоматическая версия, которая не загромождает исходный код).

Пока я использовал его только в своем собственном коде, но он должен обобщать. Вопросы и запросы на получение приветствуются!

Хорошо, так как я не очень разбираюсь в GCC, вот утомительное и очень трудоемкое решение, но, по крайней мере, оно работает!:)
Этот тест основан на том факте, что некоторые ошибки в коде шаблона не обнаруживаются до фактического создания экземпляра, то есть когда зависимые имена на самом деле не существуют в параметре шаблона:

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

Добавьте такой typedef к каждому имеющемуся шаблону, затем скомпилируйте. Удалите его из каждой структуры / класса / функции, для которой отображается компилятор, и для каждого шаблона, который все еще содержит такую ​​typedef, когда код, наконец, компилируется, никогда не создается. Или вам не повезло, и некоторые типы определяют такой _123344_non_existent_typeхотя я бы линчевала сотрудника, который за это отвечает.;)

Другие вопросы по тегам