LineCoverageStats::LineCoverageStats(
ArrayRef<const coverage::CoverageSegment *> LineSegments,
- const coverage::CoverageSegment *WrappedSegment) {
+ 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) {
!LineSegments.front()->HasCount &&
LineSegments.front()->IsRegionEntry;
- ExecutionCount = 0;
HasMultipleRegions = MinRegionCount > 1;
Mapped =
!StartOfSkippedRegion &&
ExecutionCount = WrappedSegment->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) {
// Compute the line coverage
size_t NumLines = 0, CoveredLines = 0;
CoverageData CD = CM.getCoverageForFunction(Function);
- auto NextSegment = CD.begin();
- auto EndSegment = CD.end();
- const coverage::CoverageSegment *WrappedSegment = nullptr;
- SmallVector<const coverage::CoverageSegment *, 4> LineSegments;
- unsigned Line = NextSegment->Line;
- while (NextSegment != EndSegment) {
- // Gather the segments on this line and the wrapped segment.
- if (LineSegments.size())
- WrappedSegment = LineSegments.back();
- LineSegments.clear();
- while (NextSegment != EndSegment && NextSegment->Line == Line)
- LineSegments.push_back(&*NextSegment++);
-
- LineCoverageStats LCS{LineSegments, WrappedSegment};
- if (LCS.isMapped()) {
- ++NumLines;
- if (LCS.ExecutionCount)
- ++CoveredLines;
- }
-
- ++Line;
+ for (const auto &LCS : getLineCoverageStats(CD)) {
+ if (!LCS.isMapped())
+ continue;
+ ++NumLines;
+ if (LCS.getExecutionCount())
+ ++CoveredLines;
}
return FunctionCoverageSummary(
#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"
};
/// \brief Coverage statistics for a single line.
-struct LineCoverageStats {
+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);
+ const coverage::CoverageSegment *WrappedSegment,
+ unsigned Line);
- bool isMapped() const { return Mapped; }
+ 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;
auto EndISV = InstantiationSubViews.end();
// Get the coverage information for the file.
- auto NextSegment = CoverageInfo.begin();
+ auto StartSegment = CoverageInfo.begin();
auto EndSegment = CoverageInfo.end();
+ LineCoverageIterator LCI{CoverageInfo, 1};
+ LineCoverageIterator LCIEnd = LCI.getEnd();
- unsigned FirstLine = NextSegment != EndSegment ? NextSegment->Line : 0;
- const coverage::CoverageSegment *WrappedSegment = nullptr;
- SmallVector<const coverage::CoverageSegment *, 8> LineSegments;
- for (line_iterator LI(File, /*SkipBlanks=*/false); !LI.is_at_eof(); ++LI) {
+ unsigned FirstLine = StartSegment != EndSegment ? StartSegment->Line : 0;
+ for (line_iterator LI(File, /*SkipBlanks=*/false); !LI.is_at_eof();
+ ++LI, ++LCI) {
// If we aren't rendering the whole file, we need to filter out the prologue
// and epilogue.
if (!WholeFile) {
- if (NextSegment == EndSegment)
+ if (LCI == LCIEnd)
break;
else if (LI.line_number() < FirstLine)
continue;
}
- // Collect the coverage information relevant to this line.
- if (LineSegments.size())
- WrappedSegment = LineSegments.back();
- LineSegments.clear();
- while (NextSegment != EndSegment && NextSegment->Line == LI.line_number())
- LineSegments.push_back(&*NextSegment++);
-
renderLinePrefix(OS, ViewDepth);
if (getOptions().ShowLineNumbers)
renderLineNumberColumn(OS, LI.line_number());
- LineCoverageStats LineCount{LineSegments, WrappedSegment};
if (getOptions().ShowLineStats)
- renderLineCoverageColumn(OS, LineCount);
+ renderLineCoverageColumn(OS, *LCI);
// If there are expansion subviews, we want to highlight the first one.
unsigned ExpansionColumn = 0;
ExpansionColumn = NextESV->getStartCol();
// Display the source code for the current line.
- renderLine(OS, {*LI, LI.line_number()}, WrappedSegment, LineSegments,
- ExpansionColumn, ViewDepth);
+ renderLine(OS, {*LI, LI.line_number()}, LCI->getWrappedSegment(),
+ LCI->getLineSegments(), ExpansionColumn, ViewDepth);
// Show the region markers.
- if (shouldRenderRegionMarkers(LineSegments))
- renderRegionMarkers(OS, LineSegments, ViewDepth);
+ if (shouldRenderRegionMarkers(LCI->getLineSegments()))
+ renderRegionMarkers(OS, LCI->getLineSegments(), ViewDepth);
// Show the expansions and instantiations for this line.
bool RenderedSubView = false;
// this subview.
if (RenderedSubView) {
ExpansionColumn = NextESV->getStartCol();
- renderExpansionSite(OS, {*LI, LI.line_number()}, WrappedSegment,
- LineSegments, ExpansionColumn, ViewDepth);
+ renderExpansionSite(OS, {*LI, LI.line_number()},
+ LCI->getWrappedSegment(), LCI->getLineSegments(),
+ ExpansionColumn, ViewDepth);
renderViewDivider(OS, ViewDepth + 1);
}
raw_ostream &OS, const LineCoverageStats &Line) {
std::string Count = "";
if (Line.isMapped())
- Count = tag("pre", formatCount(Line.ExecutionCount));
+ Count = tag("pre", formatCount(Line.getExecutionCount()));
std::string CoverageClass =
- (Line.ExecutionCount > 0) ? "covered-line" : "uncovered-line";
+ (Line.getExecutionCount() > 0) ? "covered-line" : "uncovered-line";
OS << tag("td", Count, CoverageClass);
}
OS.indent(LineCoverageColumnWidth) << '|';
return;
}
- std::string C = formatCount(Line.ExecutionCount);
+ std::string C = formatCount(Line.getExecutionCount());
OS.indent(LineCoverageColumnWidth - C.size());
colored_ostream(OS, raw_ostream::MAGENTA,
Line.hasMultipleRegions() && getOptions().Colors)