1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-18 18:42:46 +02: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:
Vedant Kumar 2017-10-14 02:27:29 +00:00
parent 7f4765cd80
commit e010115612
5 changed files with 121 additions and 50 deletions

View File

@ -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(

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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)