mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
[llvm-cov] Factor out logic to iterate over line coverage stats (NFC)
There were two copies of the logic needed to construct a line stats object for each line in a range: this patch brings it down to one. In the future, this will make it easier for IDE clients to display coverage in-line in source editors. To do that, we just need to move the new LineCoverageIterator class to libCoverage. llvm-svn: 315789
This commit is contained in:
parent
7f4765cd80
commit
e010115612
@ -19,7 +19,9 @@ using namespace coverage;
|
||||
|
||||
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) {
|
||||
@ -33,7 +35,6 @@ LineCoverageStats::LineCoverageStats(
|
||||
!LineSegments.front()->HasCount &&
|
||||
LineSegments.front()->IsRegionEntry;
|
||||
|
||||
ExecutionCount = 0;
|
||||
HasMultipleRegions = MinRegionCount > 1;
|
||||
Mapped =
|
||||
!StartOfSkippedRegion &&
|
||||
@ -61,6 +62,22 @@ LineCoverageStats::LineCoverageStats(
|
||||
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) {
|
||||
@ -77,27 +94,12 @@ FunctionCoverageSummary::get(const CoverageMapping &CM,
|
||||
// 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(
|
||||
|
@ -15,6 +15,8 @@
|
||||
#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"
|
||||
|
||||
@ -137,19 +139,92 @@ public:
|
||||
};
|
||||
|
||||
/// \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);
|
||||
|
||||
uint64_t getExecutionCount() const { return ExecutionCount; }
|
||||
|
||||
bool hasMultipleRegions() const { return HasMultipleRegions; }
|
||||
|
||||
bool isMapped() const { return Mapped; }
|
||||
|
||||
bool hasMultipleRegions() const { return HasMultipleRegions; }
|
||||
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;
|
||||
|
@ -187,36 +187,29 @@ void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
|
||||
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;
|
||||
@ -225,12 +218,12 @@ void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
|
||||
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;
|
||||
@ -242,8 +235,9 @@ void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -589,9 +589,9 @@ void SourceCoverageViewHTML::renderLineCoverageColumn(
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -148,7 +148,7 @@ void SourceCoverageViewText::renderLineCoverageColumn(
|
||||
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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user