--- /dev/null
+RUN: llvm-cov report -instr-profile %S/Inputs/multiple_objects/merged.profdata \
+RUN: %S/Inputs/multiple_objects/use_2.covmapping \
+RUN: -object %S/Inputs/multiple_objects/use_1.covmapping | FileCheck -check-prefix=REPORT %s
+
+REPORT: Filename{{ +}}Regions{{ +}}Missed Regions{{ +}}Cover
+REPORT-NEXT: ---
+REPORT-NEXT: header.h{{ +}}25{{ +}}14{{ +}}44.00%
+
+Instructions for regenerating the test:
+
+clang -std=c++11 -mllvm -enable-name-compression=false -fprofile-instr-generate -fcoverage-mapping use_1.cc -o use_1
+clang -std=c++11 -mllvm -enable-name-compression=false -fprofile-instr-generate -fcoverage-mapping use_2.cc -o use_2
+LLVM_PROFILE_FILE="use_1.raw" ./use_1
+LLVM_PROFILE_FILE="use_2.raw" ./use_2
+llvm-profdata merge use_{1,2}.raw -o merged.profdata
+llvm-cov convert-for-testing ./use_1 -o ./use_1.covmapping
+llvm-cov convert-for-testing ./use_2 -o ./use_2.covmapping
++CoveredRegions;
}
+ // TODO: This logic is incorrect and needs to be removed (PR34615). We need
+ // to use the segment builder to get accurate line execution counts.
+ //
// Compute the line coverage
size_t NumLines = 0, CoveredLines = 0;
for (unsigned FileID = 0, E = Function.Filenames.size(); FileID < E;
LineStart = std::min(LineStart, CR.LineStart);
LineEnd = std::max(LineEnd, CR.LineEnd);
}
+ assert(LineStart <= LineEnd && "Function contains spurious file");
unsigned LineCount = LineEnd - LineStart + 1;
// Get counters
llvm::SmallVector<uint64_t, 16> ExecutionCounts;
ExecutionCounts.resize(LineCount, 0);
+ unsigned LinesNotSkipped = LineCount;
for (auto &CR : Function.CountedRegions) {
if (CR.FileID != FileID)
continue;
// Ignore the lines that were skipped by the preprocessor.
auto ExecutionCount = CR.ExecutionCount;
if (CR.Kind == CounterMappingRegion::SkippedRegion) {
- LineCount -= CR.LineEnd - CR.LineStart + 1;
+ unsigned SkippedLines = CR.LineEnd - CR.LineStart + 1;
+ assert((SkippedLines <= LinesNotSkipped) &&
+ "Skipped region larger than file containing it");
+ LinesNotSkipped -= SkippedLines;
ExecutionCount = 1;
}
for (unsigned I = CR.LineStart; I <= CR.LineEnd; ++I)
ExecutionCounts[I - LineStart] = ExecutionCount;
}
- CoveredLines += LineCount - std::count(ExecutionCounts.begin(),
- ExecutionCounts.end(), 0);
- NumLines += LineCount;
+ unsigned UncoveredLines =
+ std::min(std::count(ExecutionCounts.begin(), ExecutionCounts.end(), 0),
+ (long)LinesNotSkipped);
+ CoveredLines += LinesNotSkipped - UncoveredLines;
+ NumLines += LinesNotSkipped;
}
return FunctionCoverageSummary(
Function.Name, Function.ExecutionCount,
RegionCoverageInfo() : Covered(0), NumRegions(0) {}
RegionCoverageInfo(size_t Covered, size_t NumRegions)
- : Covered(Covered), NumRegions(NumRegions) {}
+ : Covered(Covered), NumRegions(NumRegions) {
+ assert(Covered <= NumRegions && "Covered regions over-counted");
+ }
RegionCoverageInfo &operator+=(const RegionCoverageInfo &RHS) {
Covered += RHS.Covered;
void merge(const RegionCoverageInfo &RHS) {
Covered = std::max(Covered, RHS.Covered);
+ NumRegions = std::max(NumRegions, RHS.NumRegions);
}
size_t getCovered() const { return Covered; }
bool isFullyCovered() const { return Covered == NumRegions; }
double getPercentCovered() const {
+ assert(Covered <= NumRegions && "Covered regions over-counted");
if (NumRegions == 0)
return 0.0;
return double(Covered) / double(NumRegions) * 100.0;
LineCoverageInfo() : Covered(0), NumLines(0) {}
LineCoverageInfo(size_t Covered, size_t NumLines)
- : Covered(Covered), NumLines(NumLines) {}
+ : Covered(Covered), NumLines(NumLines) {
+ assert(Covered <= NumLines && "Covered lines over-counted");
+ }
LineCoverageInfo &operator+=(const LineCoverageInfo &RHS) {
Covered += RHS.Covered;
void merge(const LineCoverageInfo &RHS) {
Covered = std::max(Covered, RHS.Covered);
+ NumLines = std::max(NumLines, RHS.NumLines);
}
size_t getCovered() const { return Covered; }
bool isFullyCovered() const { return Covered == NumLines; }
double getPercentCovered() const {
+ assert(Covered <= NumLines && "Covered lines over-counted");
if (NumLines == 0)
return 0.0;
return double(Covered) / double(NumLines) * 100.0;
bool isFullyCovered() const { return Executed == NumFunctions; }
double getPercentCovered() const {
+ assert(Executed <= NumFunctions && "Covered functions over-counted");
if (NumFunctions == 0)
return 0.0;
return double(Executed) / double(NumFunctions) * 100.0;
LineCoverageInfo LineCoverage;
FunctionCoverageSummary(const std::string &Name)
- : Name(Name), ExecutionCount(0) {}
+ : Name(Name), ExecutionCount(0), RegionCoverage(), LineCoverage() {}
FunctionCoverageSummary(const std::string &Name, uint64_t ExecutionCount,
const RegionCoverageInfo &RegionCoverage,
FunctionCoverageInfo FunctionCoverage;
FunctionCoverageInfo InstantiationCoverage;
- FileCoverageSummary(StringRef Name) : Name(Name) {}
+ FileCoverageSummary(StringRef Name)
+ : Name(Name), RegionCoverage(), LineCoverage(), FunctionCoverage(),
+ InstantiationCoverage() {}
void addFunction(const FunctionCoverageSummary &Function) {
RegionCoverage += Function.RegionCoverage;