Hi Everyone,
I am creating a branch coverage report using the tool “genhtml” of code instrumented with clang. The branch coverage for template code is low, especially if many instances with different template parameters exist.
The report is generated using “clang” and “llvm-cov” with the following script:
#!/bin/bash
set -e
clang++ -O0 -fcoverage-mapping -fprofile-instr-generate -DWITH_USAGE $@ template_coverage.cpp
./a.out
llvm-profdata merge -output=default.profdata default.profraw
llvm-cov export ./a.out -instr-profile=default.profdata . -format lcov > "lcov.info"
genhtml --function-coverage --branch-coverage --show-details -o genhtml "lcov.info"
I have reduced the case into an example in file “template_coverage.cpp”:
#include <iostream>
#include <optional>
#include <string>
#include <vector>
template<typename T, typename F>
auto orElse(const std::optional<T>& opt, F elseFunc) {
if (opt.has_value()) {
return opt.value();
}
return elseFunc();
}
// Example of a test that runs all branches of function orElse
static std::string testCoverageWithString() {
std::optional<std::string> opt1;
std::optional<std::string> opt2 = "valid";
auto elseFunc = []() {
return std::string("alternative");
};
auto v1 = orElse(opt1, elseFunc);
auto v2 = orElse(opt2, elseFunc);
return v1 + "," + v2;
}
#ifdef WITH_USAGE
// Example of code that makes use of function orElse, where not all branches
// have to be tested again
static std::vector<int> usageWithVector() {
std::optional<std::vector<int>> opt1;
return orElse(opt1, []() {
return std::vector<int>();
});
}
#endif
int main() {
std::cout << testCoverageWithString() << std::endl;
#ifdef WITH_USAGE
usageWithVector();
#endif
return 0;
}
It seems that the coverage report handles every instantiation of template function “orElse” independently. This leads to an incomplete branch coverage for this function.
Here is an extract of the file “lcov.info”:
SF:/home/stma6092/Documents/LLVM/template_coverage.cpp
...
FN:7,template_coverage.cpp:_Z6orElseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEZL22testCoverageWithStringvE3$_0EDaRKSt8optionalIT_ET0_
...
FN:7,template_coverage.cpp:_Z6orElseISt6vectorIiSaIiEEZL15usageWithVectorvE3$_0EDaRKSt8optionalIT_ET0_
...
DA:7,3
DA:8,3
DA:9,1
DA:10,1
DA:11,2
DA:12,3
...
BRDA:8,0,0,1
BRDA:8,0,1,1
BRDA:8,1,2,0
BRDA:8,1,3,1
BRF:2
BRH:2
...
end_of_record
There are four BRDA entries for line 8 with two different block numbers. Is there any option in “llvm-cov” to reduce the number of considered blocks to a union of all instantiated templates?
If not, is there any way to identify the different template instances in the BRDA entries to apply some kind of post-processing after “llvm-cov export”?