Отсутствует покрытие llvm-cov при вызове из утверждения - PullRequest
0 голосов
/ 01 февраля 2019

У меня есть следующие файлы заголовков:

power.hpp:

#pragma once

#include <type_traits>

template <typename T, typename R = decltype(std::declval<T>() * std::declval<T>())>
constexpr inline R square(const T& x_) noexcept;

power.inl:

#pragma once

#include "power.hpp"

template <typename T, typename R>
constexpr inline R square(const T& x_) noexcept
{
    return (x_ * x_);
}

power_unit_test.cpp:

#include <power.inl>

int main()
{
    static_assert(square(2) == 4);
    assert(square(2) == 4);
    square(2);

    return (0);
}

После компиляции с флагами -fprofile-instr-generate и -fcoverage-mapping при использовании clang ++.Запустив двоичный файл модульного теста, я получаю отчет о том, что каждая из трех строк в main была вызвана, но содержимое функции использовалось только один раз.Это использование происходит от автономного вызова на square(2), кажется, что утверждения не дают правильных отчетов о покрытии.

Если я удаляю автономный square(2), тогда покрытие не достигает 100%, так как утверждения не производятпокрытие по какой-то причине.

Отчет о покрытии читается как:

power.inl:

   22|       |        template <typename T, typename R>
   23|       |        constexpr inline R square(const T& x_) noexcept
   24|      0|        {
   25|      0|            return (x_ * x_);
   26|      0|        }

power_unit_test.cpp

   29|       |int main()
   30|      1|{
   31|      1|    static_assert(arc::math::sq(2) == 4);
   32|      1|    assert(arc::math::sq(2) == 4);
   33|      1|    // arc::math::sq(2);
   34|      1|
   35|      1|    return (0);
   36|      1|}

ПожалуйстаНе могли бы вы помочь мне понять, почему покрытие не сообщается, как я ожидал здесь?Это ошибка в llvm-cov или я не понимаю намерения покрытия?

Компиляция с использованием homebrew's clang 7.0.1 на MacOS.Использование CMake 3.13.2 для системы сборки.

1 Ответ

0 голосов
/ 05 февраля 2019

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

Ваша первая мысль может заключаться в том, чтобы удалить идентификатор inline, но это не сработает.Это связано с тем, что ваш компилятор, скорее всего, достаточно умен, чтобы признать, что функция square() может быть встроенной, и в любом случае работает и делает это.Конечным результатом является то, что внешний код не вызывается.

Так что вам нужен способ обойти встраивание функции square().Вы можете сделать это с помощью указателя на функцию.См. Следующую модификацию вашей функции main:

int main()
{
    int (*f_ptr)(const int&);       // Ptr to func that takes 'const int&' and returns 'int' 
    f_ptr = &square;

    static_assert(square(2) == 4);  // Cant use 'f_ptr' here
    assert(f_ptr(2) == 4);
    f_ptr(2);

    return (0);
}

В приведенном выше коде мы заменяем явные вызовы square(const int&) указателем на функцию f_ptr.В результате компилятор не будет автоматически вставлять функции в утверждения, и код будет успешно вызван дважды.Результат:

power.cpp:

    4|       |template <typename T, typename R>
    5|       |constexpr inline R square(const T& x_) noexcept
    6|      2|{
    7|      2|    return (x_ * x_);
    8|      2|}

power_unit_test.cpp:

    5|       |int main()
    6|      1|{
    7|      1|    int (*f_ptr)(const int&);
    8|      1|    f_ptr = &square;
    9|      1|
   10|      1|    static_assert(square(2) == 4);
   11|      1|    assert(f_ptr(2) == 4);
   12|      1|    f_ptr(2);
   13|      1|
   14|      1|    return (0);
   15|      1|}

Быстрая заметка .Поскольку static_assert по сути является утверждением времени компиляции, мы не можем заменить вызов square() указателем на нашу функцию, поскольку указатели на функции не являются константными выражениями .Но не волнуйтесь, ваш компилятор достаточно умен, чтобы жаловаться, если вы попытаетесь заменить square(2) указателем на функцию f_ptr(2) здесь.

...