From 5371945eb169bef20d5636934d4305aabfc3917a Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Sat, 14 Oct 2017 02:27:29 +0000 Subject: [PATCH] [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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@315789 91177308-0d34-0410-b5e6-96231b3b80d8 --- tools/llvm-cov/CoverageSummaryInfo.cpp | 48 +++++++------- tools/llvm-cov/CoverageSummaryInfo.h | 81 ++++++++++++++++++++++- tools/llvm-cov/SourceCoverageView.cpp | 36 +++++----- tools/llvm-cov/SourceCoverageViewHTML.cpp | 4 +- tools/llvm-cov/SourceCoverageViewText.cpp | 2 +- 5 files changed, 121 insertions(+), 50 deletions(-) diff --git a/tools/llvm-cov/CoverageSummaryInfo.cpp b/tools/llvm-cov/CoverageSummaryInfo.cpp index 6a4cbd0c185..89948720504 100644 --- a/tools/llvm-cov/CoverageSummaryInfo.cpp +++ b/tools/llvm-cov/CoverageSummaryInfo.cpp @@ -19,7 +19,9 @@ using namespace coverage; LineCoverageStats::LineCoverageStats( ArrayRef 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 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( diff --git a/tools/llvm-cov/CoverageSummaryInfo.h b/tools/llvm-cov/CoverageSummaryInfo.h index 0548f491545..d3f43d19104 100644 --- a/tools/llvm-cov/CoverageSummaryInfo.h +++ b/tools/llvm-cov/CoverageSummaryInfo.h @@ -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 LineSegments; + const coverage::CoverageSegment *WrappedSegment; + friend class LineCoverageIterator; + LineCoverageStats() = default; + +public: LineCoverageStats(ArrayRef 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 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::const_iterator Next; + bool Ended; + unsigned Line; + SmallVector Segments; + LineCoverageStats Stats; +}; + +/// Get a range of LineCoverageStats for each line described by a CoverageData +/// object. +static inline iterator_range +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/tools/llvm-cov/SourceCoverageView.cpp b/tools/llvm-cov/SourceCoverageView.cpp index f944dc62b9e..337beb821bf 100644 --- a/tools/llvm-cov/SourceCoverageView.cpp +++ b/tools/llvm-cov/SourceCoverageView.cpp @@ -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 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); } diff --git a/tools/llvm-cov/SourceCoverageViewHTML.cpp b/tools/llvm-cov/SourceCoverageViewHTML.cpp index b8fdf4483a7..40e194cf2d9 100644 --- a/tools/llvm-cov/SourceCoverageViewHTML.cpp +++ b/tools/llvm-cov/SourceCoverageViewHTML.cpp @@ -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); } diff --git a/tools/llvm-cov/SourceCoverageViewText.cpp b/tools/llvm-cov/SourceCoverageViewText.cpp index 261f08d7022..e4ac1fd5bfd 100644 --- a/tools/llvm-cov/SourceCoverageViewText.cpp +++ b/tools/llvm-cov/SourceCoverageViewText.cpp @@ -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) -- 2.40.0