[llvm] r217975 - llvm-cov: Rework the API for getting the coverage of a file (NFC)

Justin Bogner mail at justinbogner.com
Wed Sep 17 11:23:47 PDT 2014


Author: bogner
Date: Wed Sep 17 13:23:47 2014
New Revision: 217975

URL: http://llvm.org/viewvc/llvm-project?rev=217975&view=rev
Log:
llvm-cov: Rework the API for getting the coverage of a file (NFC)

This encapsulates how we handle the coverage regions of a file or
function. In the old model, the user had to deal with nested regions,
so they needed to maintain their own auxiliary data structures to get
any useful information out of this. The new API provides a sequence of
non-overlapping coverage segments, which makes it possible to render
coverage information in a single pass and avoids a fair amount of
extra work.

Modified:
    llvm/trunk/tools/llvm-cov/CodeCoverage.cpp
    llvm/trunk/tools/llvm-cov/RenderingSupport.h
    llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.cpp
    llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.h
    llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp
    llvm/trunk/tools/llvm-cov/SourceCoverageView.h

Modified: llvm/trunk/tools/llvm-cov/CodeCoverage.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CodeCoverage.cpp?rev=217975&r1=217974&r2=217975&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/CodeCoverage.cpp (original)
+++ llvm/trunk/tools/llvm-cov/CodeCoverage.cpp Wed Sep 17 13:23:47 2014
@@ -284,12 +284,12 @@ void CodeCoverageTool::createExpansionSu
     return;
   auto SubView = llvm::make_unique<SourceCoverageView>(SourceBuffer.get(),
                                                        Parent.getOptions());
-  SourceCoverageDataManager RegionManager;
+  auto RegionManager = llvm::make_unique<SourceCoverageDataManager>();
   for (const auto &CR : Function.CountedRegions) {
     if (CR.FileID == ExpandedRegion.ExpandedFileID)
-      RegionManager.insert(CR);
+      RegionManager->insert(CR);
   }
-  SubView->load(RegionManager);
+  SubView->load(std::move(RegionManager));
   createExpansionSubViews(*SubView, ExpandedRegion.ExpandedFileID, Function);
   Parent.addExpansion(ExpandedRegion, std::move(SubView));
 }
@@ -311,16 +311,16 @@ void CodeCoverageTool::createExpansionSu
 void CodeCoverageTool::createInstantiationSubView(
     StringRef SourceFile, const FunctionCoverageMapping &Function,
     SourceCoverageView &View) {
-  SourceCoverageDataManager RegionManager;
+  auto RegionManager = llvm::make_unique<SourceCoverageDataManager>();
   SmallSet<unsigned, 8> InterestingFileIDs;
   if (!gatherInterestingFileIDs(SourceFile, Function, InterestingFileIDs))
     return;
   // Get the interesting regions
   for (const auto &CR : Function.CountedRegions) {
     if (InterestingFileIDs.count(CR.FileID))
-      RegionManager.insert(CR);
+      RegionManager->insert(CR);
   }
-  View.load(RegionManager);
+  View.load(std::move(RegionManager));
   unsigned MainFileID;
   if (findMainViewFileID(SourceFile, Function, MainFileID))
     return;
@@ -331,7 +331,7 @@ bool CodeCoverageTool::createSourceFileV
     StringRef SourceFile, SourceCoverageView &View,
     ArrayRef<FunctionCoverageMapping> FunctionMappingRecords,
     bool UseOnlyRegionsInMainFile) {
-  SourceCoverageDataManager RegionManager;
+  auto RegionManager = llvm::make_unique<SourceCoverageDataManager>();
   FunctionInstantiationSetCollector InstantiationSetCollector;
 
   for (const auto &Function : FunctionMappingRecords) {
@@ -347,14 +347,14 @@ bool CodeCoverageTool::createSourceFileV
     // Get the interesting regions
     for (const auto &CR : Function.CountedRegions) {
       if (InterestingFileIDs.count(CR.FileID))
-        RegionManager.insert(CR);
+        RegionManager->insert(CR);
     }
     InstantiationSetCollector.insert(Function, MainFileID);
     createExpansionSubViews(View, MainFileID, Function);
   }
-  if (RegionManager.getSourceRegions().empty())
+  if (RegionManager->getCoverageSegments().empty())
     return true;
-  View.load(RegionManager);
+  View.load(std::move(RegionManager));
   // Show instantiations
   if (!ViewOpts.ShowFunctionInstantiations)
     return false;
@@ -626,7 +626,7 @@ int CodeCoverageTool::show(int argc, con
       ViewOpts.colored_ostream(outs(), raw_ostream::CYAN)
           << Function.Name << " from " << SourceFile << ":";
       outs() << "\n";
-      mainView.render(outs());
+      mainView.render(outs(), /*WholeFile=*/false);
       if (FunctionMappingRecords.size() > 1)
         outs() << "\n";
     }
@@ -663,7 +663,7 @@ int CodeCoverageTool::show(int argc, con
       ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << SourceFile << ":";
       outs() << "\n";
     }
-    mainView.render(outs());
+    mainView.render(outs(), /*Wholefile=*/true);
     if (SourceFiles.size() > 1)
       outs() << "\n";
   }

Modified: llvm/trunk/tools/llvm-cov/RenderingSupport.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/RenderingSupport.h?rev=217975&r1=217974&r2=217975&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/RenderingSupport.h (original)
+++ llvm/trunk/tools/llvm-cov/RenderingSupport.h Wed Sep 17 13:23:47 2014
@@ -49,9 +49,10 @@ inline raw_ostream &operator<<(const Col
 /// is true. Returns an object that resets the color when destroyed.
 inline ColoredRawOstream colored_ostream(raw_ostream &OS,
                                          raw_ostream::Colors Color,
-                                         bool IsColorUsed = true) {
+                                         bool IsColorUsed = true,
+                                         bool Bold = false, bool BG = false) {
   if (IsColorUsed)
-    OS.changeColor(Color);
+    OS.changeColor(Color, Bold, BG);
   return ColoredRawOstream(OS, IsColorUsed);
 }
 }

Modified: llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.cpp?rev=217975&r1=217974&r2=217975&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.cpp (original)
+++ llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.cpp Wed Sep 17 13:23:47 2014
@@ -19,32 +19,86 @@ using namespace coverage;
 
 void SourceCoverageDataManager::insert(const CountedRegion &CR) {
   Regions.push_back(CR);
-  Uniqued = false;
+  Segments.clear();
 }
 
-ArrayRef<CountedRegion> SourceCoverageDataManager::getSourceRegions() {
-  if (Uniqued || Regions.size() <= 1)
-    return Regions;
-
-  // Sort the regions given that they're all in the same file at this point.
-  std::sort(Regions.begin(), Regions.end(),
-            [](const CountedRegion &LHS, const CountedRegion &RHS) {
-    return LHS.startLoc() < RHS.startLoc();
-  });
-
-  // Merge duplicate source ranges and sum their execution counts.
-  auto Prev = Regions.begin();
-  for (auto I = Prev + 1, E = Regions.end(); I != E; ++I) {
-    if (I->startLoc() == Prev->startLoc() && I->endLoc() == Prev->endLoc()) {
-      Prev->ExecutionCount += I->ExecutionCount;
-      continue;
+namespace {
+class SegmentBuilder {
+  std::vector<CoverageSegment> Segments;
+  SmallVector<const CountedRegion *, 8> ActiveRegions;
+
+  /// Start a segment with no count specified.
+  void startSegment(unsigned Line, unsigned Col, bool IsRegionEntry) {
+    Segments.emplace_back(Line, Col, IsRegionEntry);
+  }
+
+  /// Start a segment with the given Region's count.
+  void startSegment(unsigned Line, unsigned Col, bool IsRegionEntry,
+                    const CountedRegion &Region) {
+    if (Segments.empty())
+      Segments.emplace_back(Line, Col, IsRegionEntry);
+    CoverageSegment S = Segments.back();
+    // Avoid creating empty regions.
+    if (S.Line != Line || S.Col != Col) {
+      Segments.emplace_back(Line, Col, IsRegionEntry);
+      S = Segments.back();
+    }
+    // Set this region's count.
+    if (Region.Kind != coverage::CounterMappingRegion::SkippedRegion)
+      Segments.back().setCount(Region.ExecutionCount);
+  }
+
+  /// Start a segment for the given region.
+  void startSegment(const CountedRegion &Region) {
+    startSegment(Region.LineStart, Region.ColumnStart, true, Region);
+  }
+
+  /// Pop the top region off of the active stack, starting a new segment with
+  /// the containing Region's count.
+  void popRegion() {
+    const CountedRegion *Active = ActiveRegions.back();
+    unsigned Line = Active->LineEnd, Col = Active->ColumnEnd;
+    ActiveRegions.pop_back();
+    if (ActiveRegions.empty())
+      startSegment(Line, Col, /*IsRegionEntry=*/false);
+    else
+      startSegment(Line, Col, /*IsRegionEntry=*/false, *ActiveRegions.back());
+  }
+
+public:
+  /// Build a list of CoverageSegments from a sorted list of Regions.
+  std::vector<CoverageSegment>
+  buildSegments(ArrayRef<CountedRegion> Regions) {
+    for (const auto &Region : Regions) {
+      // Pop any regions that end before this one starts.
+      while (!ActiveRegions.empty() &&
+             ActiveRegions.back()->endLoc() <= Region.startLoc())
+        popRegion();
+      // Add this region to the stack.
+      ActiveRegions.push_back(&Region);
+      startSegment(Region);
     }
-    ++Prev;
-    *Prev = *I;
+    // Pop any regions that are left in the stack.
+    while (!ActiveRegions.empty())
+      popRegion();
+    return Segments;
+  }
+};
+}
+
+ArrayRef<CoverageSegment> SourceCoverageDataManager::getCoverageSegments() {
+  if (Segments.empty()) {
+    // Sort the regions given that they're all in the same file at this point.
+    std::sort(Regions.begin(), Regions.end(),
+              [](const CountedRegion &LHS, const CountedRegion &RHS) {
+      if (LHS.startLoc() == RHS.startLoc())
+        // When LHS completely contains RHS, we sort LHS first.
+        return RHS.endLoc() < LHS.endLoc();
+      return LHS.startLoc() < RHS.startLoc();
+    });
+
+    Segments = SegmentBuilder().buildSegments(Regions);
   }
-  ++Prev;
-  Regions.erase(Prev, Regions.end());
 
-  Uniqued = true;
-  return Regions;
+  return Segments;
 }

Modified: llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.h?rev=217975&r1=217974&r2=217975&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.h (original)
+++ llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.h Wed Sep 17 13:23:47 2014
@@ -19,19 +19,33 @@
 
 namespace llvm {
 
+struct CoverageSegment {
+  unsigned Line;
+  unsigned Col;
+  bool IsRegionEntry;
+  uint64_t Count;
+  bool HasCount;
+
+  CoverageSegment(unsigned Line, unsigned Col, bool IsRegionEntry)
+      : Line(Line), Col(Col), IsRegionEntry(IsRegionEntry),
+        Count(0), HasCount(false) {}
+  void setCount(uint64_t NewCount) {
+    Count = NewCount;
+    HasCount = true;
+  }
+};
+
 /// \brief Partions mapping regions by their kind and sums
 /// the execution counts of the regions that start at the same location.
 class SourceCoverageDataManager {
   std::vector<coverage::CountedRegion> Regions;
-  bool Uniqued;
+  std::vector<CoverageSegment> Segments;
 
 public:
-  SourceCoverageDataManager() : Uniqued(false) {}
-
   void insert(const coverage::CountedRegion &CR);
 
-  /// \brief Return the source regions in order of first to last occurring.
-  ArrayRef<coverage::CountedRegion> getSourceRegions();
+  /// \brief Return a sequence of non-overlapping coverage segments.
+  ArrayRef<CoverageSegment> getCoverageSegments();
 };
 
 } // namespace llvm

Modified: llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp?rev=217975&r1=217974&r2=217975&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp (original)
+++ llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp Wed Sep 17 13:23:47 2014
@@ -12,54 +12,54 @@
 //===----------------------------------------------------------------------===//
 
 #include "SourceCoverageView.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/LineIterator.h"
 
 using namespace llvm;
 
 void SourceCoverageView::renderLine(raw_ostream &OS, StringRef Line,
-                                    ArrayRef<HighlightRange> Ranges) {
-  if (Ranges.empty()) {
-    OS << Line << "\n";
-    return;
-  }
-  if (Line.empty())
-    Line = " ";
-
-  unsigned PrevColumnStart = 0;
-  unsigned Start = 1;
-  for (const auto &Range : Ranges) {
-    if (PrevColumnStart == Range.ColumnStart)
-      continue;
-
-    // Show the unhighlighted part
-    unsigned ColumnStart = PrevColumnStart = Range.ColumnStart;
-    OS << Line.substr(Start - 1, ColumnStart - Start);
-
-    // Show the highlighted part
-    auto Color = Range.Kind == HighlightRange::NotCovered ? raw_ostream::RED
-                                                          : raw_ostream::CYAN;
-    OS.changeColor(Color, false, true);
-    unsigned ColumnEnd = std::min(Range.ColumnEnd, (unsigned)Line.size() + 1);
-    OS << Line.substr(ColumnStart - 1, ColumnEnd - ColumnStart);
-    Start = ColumnEnd;
-    OS.resetColor();
+                                    int64_t LineNumber,
+                                    const CoverageSegment *WrappedSegment,
+                                    ArrayRef<const CoverageSegment *> Segments,
+                                    unsigned ExpansionCol) {
+  Optional<raw_ostream::Colors> Highlight;
+  SmallVector<std::pair<unsigned, unsigned>, 2> HighlightedRanges;
+
+  // The first segment overlaps from a previous line, so we treat it specially.
+  if (WrappedSegment && WrappedSegment->HasCount && WrappedSegment->Count == 0)
+    Highlight = raw_ostream::RED;
+
+  // Output each segment of the line, possibly highlighted.
+  unsigned Col = 1;
+  for (const auto *S : Segments) {
+    unsigned End = std::min(S->Col, static_cast<unsigned>(Line.size()) + 1);
+    colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR,
+                    Options.Colors && Highlight, /*Bold=*/false, /*BG=*/true)
+        << Line.substr(Col - 1, End - Col);
+    if (Options.Debug && Highlight)
+      HighlightedRanges.push_back(std::make_pair(Col, End));
+    Col = End;
+    if (Col == ExpansionCol)
+      Highlight = raw_ostream::CYAN;
+    else if (S->HasCount && S->Count == 0)
+      Highlight = raw_ostream::RED;
+    else
+      Highlight = None;
   }
 
   // Show the rest of the line
-  OS << Line.substr(Start - 1, Line.size() - Start + 1);
+  colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR,
+                  Options.Colors && Highlight, /*Bold=*/false, /*BG=*/true)
+      << Line.substr(Col - 1, Line.size() - Col + 1);
   OS << "\n";
 
   if (Options.Debug) {
-    for (const auto &Range : Ranges) {
-      errs() << "Highlighted line " << Range.Line << ", " << Range.ColumnStart
-             << " -> ";
-      if (Range.ColumnEnd == std::numeric_limits<unsigned>::max()) {
-        errs() << "?\n";
-      } else {
-        errs() << Range.ColumnEnd << "\n";
-      }
-    }
+    for (const auto &Range : HighlightedRanges)
+      errs() << "Highlighted line " << LineNumber << ", " << Range.first
+             << " -> " << Range.second << "\n";
+    if (Highlight)
+      errs() << "Highlighted line " << LineNumber << ", " << Col << " -> ?\n";
   }
 }
 
@@ -109,18 +109,20 @@ void SourceCoverageView::renderLineNumbe
   OS.indent(LineNumberColumnWidth - Str.size()) << Str << '|';
 }
 
-void SourceCoverageView::renderRegionMarkers(raw_ostream &OS,
-                                             ArrayRef<RegionMarker> Regions) {
+void SourceCoverageView::renderRegionMarkers(
+    raw_ostream &OS, ArrayRef<const CoverageSegment *> Segments) {
   SmallString<32> Buffer;
   raw_svector_ostream BufferOS(Buffer);
 
   unsigned PrevColumn = 1;
-  for (const auto &Region : Regions) {
+  for (const auto *S : Segments) {
+    if (!S->IsRegionEntry)
+      continue;
     // Skip to the new region
-    if (Region.Column > PrevColumn)
-      OS.indent(Region.Column - PrevColumn);
-    PrevColumn = Region.Column + 1;
-    BufferOS << Region.ExecutionCount;
+    if (S->Col > PrevColumn)
+      OS.indent(S->Col - PrevColumn);
+    PrevColumn = S->Col + 1;
+    BufferOS << S->Count;
     StringRef Str = BufferOS.str();
     // Trim the execution count
     Str = Str.substr(0, std::min(Str.size(), (size_t)7));
@@ -130,87 +132,14 @@ void SourceCoverageView::renderRegionMar
   }
   OS << "\n";
 
-  if (Options.Debug) {
-    for (const auto &Region : Regions) {
-      errs() << "Marker at " << Region.Line << ":" << Region.Column << " = "
-             << Region.ExecutionCount << "\n";
-    }
-  }
+  if (Options.Debug)
+    for (const auto *S : Segments)
+      errs() << "Marker at " << S->Line << ":" << S->Col << " = " << S->Count
+             << (S->IsRegionEntry ? "\n" : " (pop)\n");
 }
 
-/// \brief Insert a new highlighting range into the line's highlighting ranges
-/// Return line's new highlighting ranges in result.
-static void insertExpansionHighlightRange(
-    ArrayRef<SourceCoverageView::HighlightRange> Ranges,
-    unsigned Line, unsigned StartCol, unsigned EndCol,
-    SmallVectorImpl<SourceCoverageView::HighlightRange> &Result) {
-  auto RangeToInsert = SourceCoverageView::HighlightRange(
-      Line, StartCol, EndCol, SourceCoverageView::HighlightRange::Expanded);
-  Result.clear();
-  size_t I = 0;
-  auto E = Ranges.size();
-  for (; I < E; ++I) {
-    if (RangeToInsert.ColumnStart < Ranges[I].ColumnEnd) {
-      const auto &Range = Ranges[I];
-      bool NextRangeContainsInserted = false;
-      // If the next range starts before the inserted range, move the end of the
-      // next range to the start of the inserted range.
-      if (Range.ColumnStart < RangeToInsert.ColumnStart) {
-        if (RangeToInsert.ColumnStart != Range.ColumnStart)
-          Result.push_back(SourceCoverageView::HighlightRange(
-              Range.Line, Range.ColumnStart, RangeToInsert.ColumnStart,
-              Range.Kind));
-        // If the next range also ends after the inserted range, keep this range
-        // and create a new range that starts at the inserted range and ends
-        // at the next range later.
-        if (Range.ColumnEnd > RangeToInsert.ColumnEnd)
-          NextRangeContainsInserted = true;
-      }
-      if (!NextRangeContainsInserted) {
-        ++I;
-        // Ignore ranges that are contained in inserted range
-        while (I < E && RangeToInsert.contains(Ranges[I]))
-          ++I;
-      }
-      break;
-    }
-    Result.push_back(Ranges[I]);
-  }
-  Result.push_back(RangeToInsert);
-  // If the next range starts before the inserted range end, move the start
-  // of the next range to the end of the inserted range.
-  if (I < E && Ranges[I].ColumnStart < RangeToInsert.ColumnEnd) {
-    const auto &Range = Ranges[I];
-    if (RangeToInsert.ColumnEnd != Range.ColumnEnd)
-      Result.push_back(SourceCoverageView::HighlightRange(
-          Range.Line, RangeToInsert.ColumnEnd, Range.ColumnEnd, Range.Kind));
-    ++I;
-  }
-  // Add the remaining ranges that are located after the inserted range
-  for (; I < E; ++I)
-    Result.push_back(Ranges[I]);
-}
-
-template <typename T>
-ArrayRef<T> gatherLineItems(size_t &CurrentIdx, const std::vector<T> &Items,
-                            unsigned LineNo) {
-  auto PrevIdx = CurrentIdx;
-  auto E = Items.size();
-  while (CurrentIdx < E && Items[CurrentIdx].Line == LineNo)
-    ++CurrentIdx;
-  return ArrayRef<T>(Items.data() + PrevIdx, CurrentIdx - PrevIdx);
-}
-
-void SourceCoverageView::render(raw_ostream &OS, unsigned IndentLevel) {
-  SmallVector<HighlightRange, 8> AdjustedLineHighlightRanges;
-  size_t CurrentHighlightRange = 0;
-  size_t CurrentRegionMarker = 0;
-
-  line_iterator Lines(File, /*SkipBlanks=*/false);
-  // Advance the line iterator to the first line.
-  while (Lines.line_number() < LineOffset)
-    ++Lines;
-
+void SourceCoverageView::render(raw_ostream &OS, bool WholeFile,
+                                unsigned IndentLevel) {
   // The width of the leading columns
   unsigned CombinedColumnWidth =
       (Options.ShowLineStats ? LineCoverageColumnWidth + 1 : 0) +
@@ -228,66 +157,88 @@ void SourceCoverageView::render(raw_ostr
   auto NextISV = InstantiationSubViews.begin();
   auto EndISV = InstantiationSubViews.end();
 
-  for (size_t I = 0, E = LineStats.size(); I < E && !Lines.is_at_eof();
-       ++I, ++Lines) {
-    unsigned LineNo = Lines.line_number();
+  // Get the coverage information for the file.
+  auto CoverageSegments = RegionManager->getCoverageSegments();
+  assert(CoverageSegments.size() && "View with no coverage?");
+  auto NextSegment = CoverageSegments.begin();
+  auto EndSegment = CoverageSegments.end();
+
+  const CoverageSegment *WrappedSegment = nullptr;
+  SmallVector<const CoverageSegment *, 8> LineSegments;
+  for (line_iterator LI(File, /*SkipBlanks=*/false); !LI.is_at_eof(); ++LI) {
+    // If we aren't rendering the whole file, we need to filter out the prologue
+    // and epilogue.
+    if (!WholeFile) {
+      if (NextSegment == EndSegment)
+        break;
+      else if (LI.line_number() < NextSegment->Line)
+        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++);
+
+    // Calculate a count to be for the line as a whole.
+    LineCoverageInfo LineCount;
+    if (WrappedSegment && WrappedSegment->HasCount)
+      LineCount.addRegionCount(WrappedSegment->Count);
+    for (const auto *S : LineSegments)
+      if (S->HasCount && S->IsRegionEntry)
+          LineCount.addRegionStartCount(S->Count);
 
+    // Render the line prefix.
     renderIndent(OS, IndentLevel);
     if (Options.ShowLineStats)
-      renderLineCoverageColumn(OS, LineStats[I]);
+      renderLineCoverageColumn(OS, LineCount);
     if (Options.ShowLineNumbers)
-      renderLineNumberColumn(OS, LineNo);
+      renderLineNumberColumn(OS, LI.line_number());
 
-    // Gather highlighting ranges.
-    auto LineHighlightRanges =
-        gatherLineItems(CurrentHighlightRange, HighlightRanges, LineNo);
-    auto LineRanges = LineHighlightRanges;
-    // Highlight the expansion range if there is an expansion subview on this
-    // line.
-    if (NextESV != EndESV && NextESV->getLine() == LineNo && Options.Colors) {
-      insertExpansionHighlightRange(
-          LineHighlightRanges, NextESV->getLine(), NextESV->getStartCol(),
-          NextESV->getEndCol(), AdjustedLineHighlightRanges);
-      LineRanges = AdjustedLineHighlightRanges;
-    }
+    // If there are expansion subviews, we want to highlight the first one.
+    unsigned ExpansionColumn = 0;
+    if (NextESV != EndESV && NextESV->getLine() == LI.line_number() &&
+        Options.Colors)
+      ExpansionColumn = NextESV->getStartCol();
 
     // Display the source code for the current line.
-    StringRef Line = *Lines;
-    renderLine(OS, Line, LineRanges);
+    renderLine(OS, *LI, LI.line_number(), WrappedSegment, LineSegments,
+               ExpansionColumn);
 
     // Show the region markers.
-    bool ShowMarkers = !Options.ShowLineStatsOrRegionMarkers ||
-                       LineStats[I].hasMultipleRegions();
-    auto LineMarkers = gatherLineItems(CurrentRegionMarker, Markers, LineNo);
-    if (ShowMarkers && !LineMarkers.empty()) {
+    if (Options.ShowRegionMarkers && (!Options.ShowLineStatsOrRegionMarkers ||
+                                      LineCount.hasMultipleRegions()) &&
+        !LineSegments.empty()) {
       renderIndent(OS, IndentLevel);
       OS.indent(CombinedColumnWidth);
-      renderRegionMarkers(OS, LineMarkers);
+      renderRegionMarkers(OS, LineSegments);
     }
 
     // Show the expansions and instantiations for this line.
     unsigned NestedIndent = IndentLevel + 1;
     bool RenderedSubView = false;
-    for (; NextESV != EndESV && NextESV->getLine() == LineNo; ++NextESV) {
+    for (; NextESV != EndESV && NextESV->getLine() == LI.line_number();
+         ++NextESV) {
       renderViewDivider(NestedIndent, DividerWidth, OS);
       OS << "\n";
       if (RenderedSubView) {
         // Re-render the current line and highlight the expansion range for
         // this subview.
-        insertExpansionHighlightRange(
-            LineHighlightRanges, NextESV->getLine(), NextESV->getStartCol(),
-            NextESV->getEndCol(), AdjustedLineHighlightRanges);
+        ExpansionColumn = NextESV->getStartCol();
         renderIndent(OS, IndentLevel);
         OS.indent(CombinedColumnWidth + (IndentLevel == 0 ? 0 : 1));
-        renderLine(OS, Line, AdjustedLineHighlightRanges);
+        renderLine(OS, *LI, LI.line_number(), WrappedSegment, LineSegments,
+                   ExpansionColumn);
         renderViewDivider(NestedIndent, DividerWidth, OS);
         OS << "\n";
       }
       // Render the child subview
-      NextESV->View->render(OS, NestedIndent);
+      NextESV->View->render(OS, false, NestedIndent);
       RenderedSubView = true;
     }
-    for (; NextISV != EndISV && NextISV->Line == LineNo; ++NextISV) {
+    for (; NextISV != EndISV && NextISV->Line == LI.line_number(); ++NextISV) {
       renderViewDivider(NestedIndent, DividerWidth, OS);
       OS << "\n";
       renderIndent(OS, NestedIndent);
@@ -295,7 +246,7 @@ void SourceCoverageView::render(raw_ostr
       Options.colored_ostream(OS, raw_ostream::CYAN) << NextISV->FunctionName
                                                      << ":";
       OS << "\n";
-      NextISV->View->render(OS, NestedIndent);
+      NextISV->View->render(OS, false, NestedIndent);
       RenderedSubView = true;
     }
     if (RenderedSubView) {
@@ -304,89 +255,3 @@ void SourceCoverageView::render(raw_ostr
     }
   }
 }
-
-void SourceCoverageView::setUpVisibleRange(SourceCoverageDataManager &Data) {
-  auto CountedRegions = Data.getSourceRegions();
-  if (!CountedRegions.size())
-    return;
-
-  unsigned Start = CountedRegions.front().LineStart, End = 0;
-  for (const auto &CR : CountedRegions) {
-    Start = std::min(Start, CR.LineStart);
-    End = std::max(End, CR.LineEnd);
-  }
-  LineOffset = Start;
-  LineStats.resize(End - Start + 1);
-}
-
-void
-SourceCoverageView::createLineCoverageInfo(SourceCoverageDataManager &Data) {
-  auto CountedRegions = Data.getSourceRegions();
-  for (const auto &CR : CountedRegions) {
-    if (CR.Kind == coverage::CounterMappingRegion::SkippedRegion) {
-      // Reset the line stats for skipped regions.
-      for (unsigned Line = CR.LineStart; Line <= CR.LineEnd;
-           ++Line)
-        LineStats[Line - LineOffset] = LineCoverageInfo();
-      continue;
-    }
-    LineStats[CR.LineStart - LineOffset].addRegionStartCount(CR.ExecutionCount);
-    for (unsigned Line = CR.LineStart + 1; Line <= CR.LineEnd; ++Line)
-      LineStats[Line - LineOffset].addRegionCount(CR.ExecutionCount);
-  }
-}
-
-void
-SourceCoverageView::createHighlightRanges(SourceCoverageDataManager &Data) {
-  auto CountedRegions = Data.getSourceRegions();
-  std::vector<bool> AlreadyHighlighted;
-  AlreadyHighlighted.resize(CountedRegions.size(), false);
-
-  for (size_t I = 0, S = CountedRegions.size(); I < S; ++I) {
-    const auto &CR = CountedRegions[I];
-    if (CR.Kind == coverage::CounterMappingRegion::SkippedRegion ||
-        CR.ExecutionCount != 0)
-      continue;
-    if (AlreadyHighlighted[I])
-      continue;
-    for (size_t J = 0; J < S; ++J) {
-      if (CR.contains(CountedRegions[J])) {
-        AlreadyHighlighted[J] = true;
-      }
-    }
-    if (CR.LineStart == CR.LineEnd) {
-      HighlightRanges.push_back(HighlightRange(
-          CR.LineStart, CR.ColumnStart, CR.ColumnEnd));
-      continue;
-    }
-    HighlightRanges.push_back(
-        HighlightRange(CR.LineStart, CR.ColumnStart,
-                       std::numeric_limits<unsigned>::max()));
-    HighlightRanges.push_back(
-        HighlightRange(CR.LineEnd, 1, CR.ColumnEnd));
-    for (unsigned Line = CR.LineStart + 1; Line < CR.LineEnd;
-         ++Line) {
-      HighlightRanges.push_back(
-          HighlightRange(Line, 1, std::numeric_limits<unsigned>::max()));
-    }
-  }
-
-  std::sort(HighlightRanges.begin(), HighlightRanges.end());
-}
-
-void SourceCoverageView::createRegionMarkers(SourceCoverageDataManager &Data) {
-  for (const auto &CR : Data.getSourceRegions())
-    if (CR.Kind != coverage::CounterMappingRegion::SkippedRegion)
-      Markers.push_back(
-          RegionMarker(CR.LineStart, CR.ColumnStart, CR.ExecutionCount));
-}
-
-void SourceCoverageView::load(SourceCoverageDataManager &Data) {
-  setUpVisibleRange(Data);
-  if (Options.ShowLineStats)
-    createLineCoverageInfo(Data);
-  if (Options.Colors)
-    createHighlightRanges(Data);
-  if (Options.ShowRegionMarkers)
-    createRegionMarkers(Data);
-}

Modified: llvm/trunk/tools/llvm-cov/SourceCoverageView.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/SourceCoverageView.h?rev=217975&r1=217974&r2=217975&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/SourceCoverageView.h (original)
+++ llvm/trunk/tools/llvm-cov/SourceCoverageView.h Wed Sep 17 13:23:47 2014
@@ -77,7 +77,7 @@ struct InstantiationView {
 /// \brief A code coverage view of a specific source file.
 /// It can have embedded coverage views.
 class SourceCoverageView {
-public:
+private:
   /// \brief Coverage information for a single line.
   struct LineCoverageInfo {
     uint64_t ExecutionCount;
@@ -98,90 +98,22 @@ public:
 
     void addRegionCount(uint64_t Count) {
       Mapped = true;
-      ExecutionCount = Count;
-    }
-  };
-
-  /// \brief A marker that points at the start
-  /// of a specific mapping region.
-  struct RegionMarker {
-    unsigned Line, Column;
-    uint64_t ExecutionCount;
-
-    RegionMarker(unsigned Line, unsigned Column, uint64_t Value)
-        : Line(Line), Column(Column), ExecutionCount(Value) {}
-  };
-
-  /// \brief A single line source range used to
-  /// render highlighted text.
-  struct HighlightRange {
-    enum HighlightKind {
-      /// The code that wasn't executed.
-      NotCovered,
-
-      /// The region of code that was expanded.
-      Expanded
-    };
-    HighlightKind Kind;
-    unsigned Line;
-    unsigned ColumnStart;
-    unsigned ColumnEnd;
-
-    HighlightRange(unsigned Line, unsigned ColumnStart, unsigned ColumnEnd,
-                   HighlightKind Kind = NotCovered)
-        : Kind(Kind), Line(Line), ColumnStart(ColumnStart),
-          ColumnEnd(ColumnEnd) {}
-
-    bool operator<(const HighlightRange &Other) const {
-      if (Line == Other.Line)
-        return ColumnStart < Other.ColumnStart;
-      return Line < Other.Line;
-    }
-
-    bool columnStartOverlaps(const HighlightRange &Other) const {
-      return ColumnStart <= Other.ColumnStart && ColumnEnd > Other.ColumnStart;
-    }
-    bool columnEndOverlaps(const HighlightRange &Other) const {
-      return ColumnEnd >= Other.ColumnEnd && ColumnStart < Other.ColumnEnd;
-    }
-    bool contains(const HighlightRange &Other) const {
-      if (Line != Other.Line)
-        return false;
-      return ColumnStart <= Other.ColumnStart && ColumnEnd >= Other.ColumnEnd;
-    }
-
-    bool overlaps(const HighlightRange &Other) const {
-      if (Line != Other.Line)
-        return false;
-      return columnStartOverlaps(Other) || columnEndOverlaps(Other);
+      if (!RegionCount)
+        ExecutionCount = Count;
     }
   };
 
-private:
   const MemoryBuffer &File;
   const CoverageViewOptions &Options;
-  unsigned LineOffset;
+  std::unique_ptr<SourceCoverageDataManager> RegionManager;
   std::vector<ExpansionView> ExpansionSubViews;
   std::vector<InstantiationView> InstantiationSubViews;
-  std::vector<LineCoverageInfo> LineStats;
-  std::vector<HighlightRange> HighlightRanges;
-  std::vector<RegionMarker> Markers;
-
-  /// \brief Initialize the visible source range for this view.
-  void setUpVisibleRange(SourceCoverageDataManager &Data);
-
-  /// \brief Create the line coverage information using the coverage data.
-  void createLineCoverageInfo(SourceCoverageDataManager &Data);
-
-  /// \brief Create the line highlighting ranges using the coverage data.
-  void createHighlightRanges(SourceCoverageDataManager &Data);
-
-  /// \brief Create the region markers using the coverage data.
-  void createRegionMarkers(SourceCoverageDataManager &Data);
 
   /// \brief Render a source line with highlighting.
-  void renderLine(raw_ostream &OS, StringRef Line,
-                  ArrayRef<HighlightRange> Ranges);
+  void renderLine(raw_ostream &OS, StringRef Line, int64_t LineNumber,
+                  const CoverageSegment *WrappedSegment,
+                  ArrayRef<const CoverageSegment *> Segments,
+                  unsigned ExpansionCol);
 
   void renderIndent(raw_ostream &OS, unsigned Level);
 
@@ -194,7 +126,8 @@ private:
   void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo);
 
   /// \brief Render all the region's execution counts on a line.
-  void renderRegionMarkers(raw_ostream &OS, ArrayRef<RegionMarker> Regions);
+  void renderRegionMarkers(raw_ostream &OS,
+                           ArrayRef<const CoverageSegment *> Segments);
 
   static const unsigned LineCoverageColumnWidth = 7;
   static const unsigned LineNumberColumnWidth = 5;
@@ -202,7 +135,7 @@ private:
 public:
   SourceCoverageView(const MemoryBuffer &File,
                      const CoverageViewOptions &Options)
-      : File(File), Options(Options), LineOffset(0) {}
+      : File(File), Options(Options) {}
 
   const CoverageViewOptions &getOptions() const { return Options; }
 
@@ -220,11 +153,13 @@ public:
 
   /// \brief Print the code coverage information for a specific
   /// portion of a source file to the output stream.
-  void render(raw_ostream &OS, unsigned IndentLevel = 0);
+  void render(raw_ostream &OS, bool WholeFile, unsigned IndentLevel = 0);
 
   /// \brief Load the coverage information required for rendering
   /// from the mapping regions in the data manager.
-  void load(SourceCoverageDataManager &Data);
+  void load(std::unique_ptr<SourceCoverageDataManager> Data) {
+    RegionManager = std::move(Data);
+  }
 };
 
 } // namespace llvm





More information about the llvm-commits mailing list