summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/ProfileData/Coverage/CoverageMapping.h83
-rw-r--r--lib/ProfileData/Coverage/CoverageMapping.cpp53
-rw-r--r--tools/llvm-cov/CoverageSummaryInfo.cpp53
-rw-r--r--tools/llvm-cov/CoverageSummaryInfo.h89
-rw-r--r--unittests/ProfileData/CoverageMappingTest.cpp57
5 files changed, 193 insertions, 142 deletions
diff --git a/include/llvm/ProfileData/Coverage/CoverageMapping.h b/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 22286f6d468..5a4098cf666 100644
--- a/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -594,6 +594,89 @@ public:
getInstantiationGroups(StringRef Filename) const;
};
+/// Coverage statistics for a single line.
+class LineCoverageStats {
+ uint64_t ExecutionCount;
+ bool HasMultipleRegions;
+ bool Mapped;
+ unsigned Line;
+ ArrayRef<const CoverageSegment *> LineSegments;
+ const CoverageSegment *WrappedSegment;
+
+ friend class LineCoverageIterator;
+ LineCoverageStats() = default;
+
+public:
+ LineCoverageStats(ArrayRef<const CoverageSegment *> LineSegments,
+ const CoverageSegment *WrappedSegment, unsigned Line);
+
+ uint64_t getExecutionCount() const { return ExecutionCount; }
+
+ bool hasMultipleRegions() const { return HasMultipleRegions; }
+
+ bool isMapped() const { return Mapped; }
+
+ unsigned getLine() const { return Line; }
+
+ ArrayRef<const CoverageSegment *> getLineSegments() const {
+ return LineSegments;
+ }
+
+ const CoverageSegment *getWrappedSegment() const { return WrappedSegment; }
+};
+
+/// An iterator over the \c LineCoverageStats objects for lines described by
+/// a \c CoverageData instance.
+class LineCoverageIterator
+ : public iterator_facade_base<
+ LineCoverageIterator, std::forward_iterator_tag, LineCoverageStats> {
+public:
+ LineCoverageIterator(const CoverageData &CD)
+ : LineCoverageIterator(CD, CD.begin()->Line) {}
+
+ LineCoverageIterator(const CoverageData &CD, unsigned Line)
+ : CD(CD), WrappedSegment(nullptr), Next(CD.begin()), Ended(false),
+ Line(Line), Segments(), Stats() {
+ this->operator++();
+ }
+
+ LineCoverageIterator &operator=(const LineCoverageIterator &R) = default;
+
+ bool operator==(const LineCoverageIterator &R) const {
+ return &CD == &R.CD && Next == R.Next && Ended == R.Ended;
+ }
+
+ const LineCoverageStats &operator*() const { return Stats; }
+
+ LineCoverageStats &operator*() { return Stats; }
+
+ LineCoverageIterator &operator++();
+
+ LineCoverageIterator getEnd() const {
+ auto EndIt = *this;
+ EndIt.Next = CD.end();
+ EndIt.Ended = true;
+ return EndIt;
+ }
+
+private:
+ const CoverageData &CD;
+ const CoverageSegment *WrappedSegment;
+ std::vector<CoverageSegment>::const_iterator Next;
+ bool Ended;
+ unsigned Line;
+ SmallVector<const CoverageSegment *, 4> Segments;
+ LineCoverageStats Stats;
+};
+
+/// Get a \c LineCoverageIterator range for the lines described by \p CD.
+static inline iterator_range<LineCoverageIterator>
+getLineCoverageStats(const coverage::CoverageData &CD) {
+ auto Begin = LineCoverageIterator(CD);
+ auto End = Begin.getEnd();
+ return make_range(Begin, End);
+}
+
// Profile coverage map has the following layout:
// [CoverageMapFileHeader]
// [ArrayStart]
diff --git a/lib/ProfileData/Coverage/CoverageMapping.cpp b/lib/ProfileData/Coverage/CoverageMapping.cpp
index 52f9447aa3e..bda61768e7b 100644
--- a/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -671,6 +671,59 @@ CoverageData CoverageMapping::getCoverageForExpansion(
return ExpansionCoverage;
}
+LineCoverageStats::LineCoverageStats(
+ ArrayRef<const coverage::CoverageSegment *> LineSegments,
+ const coverage::CoverageSegment *WrappedSegment, unsigned Line)
+ : ExecutionCount(0), HasMultipleRegions(false), Mapped(false), Line(Line),
+ LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
+ // Find the minimum number of regions which start in this line.
+ unsigned MinRegionCount = 0;
+ auto isStartOfRegion = [](const coverage::CoverageSegment *S) {
+ return !S->IsGapRegion && S->HasCount && S->IsRegionEntry;
+ };
+ for (unsigned I = 0; I < LineSegments.size() && MinRegionCount < 2; ++I)
+ if (isStartOfRegion(LineSegments[I]))
+ ++MinRegionCount;
+
+ bool StartOfSkippedRegion = !LineSegments.empty() &&
+ !LineSegments.front()->HasCount &&
+ LineSegments.front()->IsRegionEntry;
+
+ HasMultipleRegions = MinRegionCount > 1;
+ Mapped =
+ !StartOfSkippedRegion &&
+ ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0));
+
+ if (!Mapped)
+ return;
+
+ // Pick the max count from the non-gap, region entry segments. If there
+ // aren't any, use the wrapped count.
+ if (!MinRegionCount) {
+ ExecutionCount = WrappedSegment->Count;
+ return;
+ }
+ for (const auto *LS : LineSegments)
+ if (isStartOfRegion(LS))
+ ExecutionCount = std::max(ExecutionCount, LS->Count);
+}
+
+LineCoverageIterator &LineCoverageIterator::operator++() {
+ if (Next == CD.end()) {
+ Stats = LineCoverageStats();
+ Ended = true;
+ return *this;
+ }
+ if (Segments.size())
+ WrappedSegment = Segments.back();
+ Segments.clear();
+ while (Next != CD.end() && Next->Line == Line)
+ Segments.push_back(&*Next++);
+ Stats = LineCoverageStats(Segments, WrappedSegment, Line);
+ ++Line;
+ return *this;
+}
+
static std::string getCoverageMapErrString(coveragemap_error Err) {
switch (Err) {
case coveragemap_error::success:
diff --git a/tools/llvm-cov/CoverageSummaryInfo.cpp b/tools/llvm-cov/CoverageSummaryInfo.cpp
index d1fcef4299d..7847a2abf48 100644
--- a/tools/llvm-cov/CoverageSummaryInfo.cpp
+++ b/tools/llvm-cov/CoverageSummaryInfo.cpp
@@ -17,59 +17,6 @@
using namespace llvm;
using namespace coverage;
-LineCoverageStats::LineCoverageStats(
- ArrayRef<const coverage::CoverageSegment *> LineSegments,
- const coverage::CoverageSegment *WrappedSegment, unsigned Line)
- : ExecutionCount(0), HasMultipleRegions(false), Mapped(false), Line(Line),
- LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
- // Find the minimum number of regions which start in this line.
- unsigned MinRegionCount = 0;
- auto isStartOfRegion = [](const coverage::CoverageSegment *S) {
- return !S->IsGapRegion && S->HasCount && S->IsRegionEntry;
- };
- for (unsigned I = 0; I < LineSegments.size() && MinRegionCount < 2; ++I)
- if (isStartOfRegion(LineSegments[I]))
- ++MinRegionCount;
-
- bool StartOfSkippedRegion = !LineSegments.empty() &&
- !LineSegments.front()->HasCount &&
- LineSegments.front()->IsRegionEntry;
-
- HasMultipleRegions = MinRegionCount > 1;
- Mapped =
- !StartOfSkippedRegion &&
- ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0));
-
- if (!Mapped)
- return;
-
- // Pick the max count from the non-gap, region entry segments. If there
- // aren't any, use the wrapped count.
- if (!MinRegionCount) {
- ExecutionCount = WrappedSegment->Count;
- return;
- }
- for (const auto *LS : LineSegments)
- if (isStartOfRegion(LS))
- ExecutionCount = std::max(ExecutionCount, LS->Count);
-}
-
-LineCoverageIterator &LineCoverageIterator::operator++() {
- if (Next == CD.end()) {
- Stats = LineCoverageStats();
- Ended = true;
- return *this;
- }
- if (Segments.size())
- WrappedSegment = Segments.back();
- Segments.clear();
- while (Next != CD.end() && Next->Line == Line)
- Segments.push_back(&*Next++);
- Stats = LineCoverageStats(Segments, WrappedSegment, Line);
- ++Line;
- return *this;
-}
-
FunctionCoverageSummary
FunctionCoverageSummary::get(const CoverageMapping &CM,
const coverage::FunctionRecord &Function) {
diff --git a/tools/llvm-cov/CoverageSummaryInfo.h b/tools/llvm-cov/CoverageSummaryInfo.h
index d3f43d19104..8eae0b7fec9 100644
--- a/tools/llvm-cov/CoverageSummaryInfo.h
+++ b/tools/llvm-cov/CoverageSummaryInfo.h
@@ -15,8 +15,6 @@
#ifndef LLVM_COV_COVERAGESUMMARYINFO_H
#define LLVM_COV_COVERAGESUMMARYINFO_H
-#include "llvm/ADT/iterator.h"
-#include "llvm/ADT/iterator_range.h"
#include "llvm/ProfileData/Coverage/CoverageMapping.h"
#include "llvm/Support/raw_ostream.h"
@@ -138,93 +136,6 @@ public:
}
};
-/// \brief Coverage statistics for a single line.
-class LineCoverageStats {
- uint64_t ExecutionCount;
- bool HasMultipleRegions;
- bool Mapped;
- unsigned Line;
- ArrayRef<const coverage::CoverageSegment *> LineSegments;
- const coverage::CoverageSegment *WrappedSegment;
-
- friend class LineCoverageIterator;
- LineCoverageStats() = default;
-
-public:
- LineCoverageStats(ArrayRef<const coverage::CoverageSegment *> LineSegments,
- const coverage::CoverageSegment *WrappedSegment,
- unsigned Line);
-
- uint64_t getExecutionCount() const { return ExecutionCount; }
-
- bool hasMultipleRegions() const { return HasMultipleRegions; }
-
- bool isMapped() const { return Mapped; }
-
- unsigned getLine() const { return Line; }
-
- ArrayRef<const coverage::CoverageSegment *> getLineSegments() const {
- return LineSegments;
- }
-
- const coverage::CoverageSegment *getWrappedSegment() const {
- return WrappedSegment;
- }
-};
-
-/// Iterates over LineCoverageStats for each line described by a CoverageData
-/// object.
-class LineCoverageIterator
- : public iterator_facade_base<
- LineCoverageIterator, std::forward_iterator_tag, LineCoverageStats> {
-public:
- LineCoverageIterator(const coverage::CoverageData &CD)
- : LineCoverageIterator(CD, CD.begin()->Line) {}
-
- LineCoverageIterator(const coverage::CoverageData &CD, unsigned Line)
- : CD(CD), WrappedSegment(nullptr), Next(CD.begin()), Ended(false),
- Line(Line), Segments(), Stats() {
- this->operator++();
- }
-
- LineCoverageIterator &operator=(const LineCoverageIterator &R) = default;
-
- bool operator==(const LineCoverageIterator &R) const {
- return &CD == &R.CD && Next == R.Next && Ended == R.Ended;
- }
-
- const LineCoverageStats &operator*() const { return Stats; }
-
- LineCoverageStats &operator*() { return Stats; }
-
- LineCoverageIterator &operator++();
-
- LineCoverageIterator getEnd() const {
- auto EndIt = *this;
- EndIt.Next = CD.end();
- EndIt.Ended = true;
- return EndIt;
- }
-
-private:
- const coverage::CoverageData &CD;
- const coverage::CoverageSegment *WrappedSegment;
- std::vector<coverage::CoverageSegment>::const_iterator Next;
- bool Ended;
- unsigned Line;
- SmallVector<const coverage::CoverageSegment *, 4> Segments;
- LineCoverageStats Stats;
-};
-
-/// Get a range of LineCoverageStats for each line described by a CoverageData
-/// object.
-static inline iterator_range<LineCoverageIterator>
-getLineCoverageStats(const coverage::CoverageData &CD) {
- auto Begin = LineCoverageIterator(CD);
- auto End = Begin.getEnd();
- return make_range(Begin, End);
-}
-
/// \brief A summary of function's code coverage.
struct FunctionCoverageSummary {
std::string Name;
diff --git a/unittests/ProfileData/CoverageMappingTest.cpp b/unittests/ProfileData/CoverageMappingTest.cpp
index 8c9c8c48234..ad0a0cfb873 100644
--- a/unittests/ProfileData/CoverageMappingTest.cpp
+++ b/unittests/ProfileData/CoverageMappingTest.cpp
@@ -635,6 +635,63 @@ TEST_P(CoverageMappingTest, basic_coverage_iteration) {
ASSERT_EQ(CoverageSegment(11, 11, false), Segments[6]);
}
+TEST_P(CoverageMappingTest, test_line_coverage_iterator) {
+ ProfileWriter.addRecord({"func", 0x1234, {30, 20, 10, 0}}, Err);
+
+ startFunction("func", 0x1234);
+ addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);
+ addCMR(Counter::getCounter(1), "file1", 1, 1, 4, 7);
+ addCMR(Counter::getCounter(2), "file1", 5, 8, 9, 1);
+ addCMR(Counter::getCounter(3), "file1", 10, 10, 11, 11);
+ EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());
+
+ CoverageData Data = LoadedCoverage->getCoverageForFile("file1");
+
+ unsigned NumLineStats = 0;
+ for (const auto &LCS : getLineCoverageStats(Data)) {
+ ++NumLineStats;
+ (void)LCS;
+ }
+ ASSERT_EQ(11U, NumLineStats);
+
+ LineCoverageIterator LCI{Data};
+
+ ASSERT_EQ(1U, LCI->getLine());
+ ASSERT_EQ(20ULL, LCI->getExecutionCount());
+ ++LCI;
+ ASSERT_EQ(2U, LCI->getLine());
+ ASSERT_EQ(20ULL, LCI->getExecutionCount());
+ ++LCI;
+ ASSERT_EQ(3U, LCI->getLine());
+ ASSERT_EQ(20ULL, LCI->getExecutionCount());
+ ++LCI;
+ ASSERT_EQ(4U, LCI->getLine());
+ ASSERT_EQ(20ULL, LCI->getExecutionCount());
+ ++LCI;
+ ASSERT_EQ(5U, LCI->getLine());
+ ASSERT_EQ(10ULL, LCI->getExecutionCount());
+ ++LCI;
+ ASSERT_EQ(6U, LCI->getLine());
+ ASSERT_EQ(10ULL, LCI->getExecutionCount());
+ ++LCI;
+ ASSERT_EQ(7U, LCI->getLine());
+ ASSERT_EQ(10ULL, LCI->getExecutionCount());
+ ++LCI;
+ ASSERT_EQ(8U, LCI->getLine());
+ ASSERT_EQ(10ULL, LCI->getExecutionCount());
+ ++LCI;
+ ASSERT_EQ(9U, LCI->getLine());
+ ASSERT_EQ(10ULL, LCI->getExecutionCount());
+ ++LCI;
+ ASSERT_EQ(10U, LCI->getLine());
+ ASSERT_EQ(0ULL, LCI->getExecutionCount());
+ ++LCI;
+ ASSERT_EQ(11U, LCI->getLine());
+ ASSERT_EQ(0ULL, LCI->getExecutionCount());
+ ++LCI;
+ ASSERT_EQ(LCI, LCI.getEnd());
+}
+
TEST_P(CoverageMappingTest, uncovered_function) {
startFunction("func", 0x1234);
addCMR(Counter::getZero(), "file1", 1, 2, 3, 4);