[llvm] r273767 - [llvm-cov] Separate presentation logic from formatting logic, NFC

Vedant Kumar via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 24 19:58:30 PDT 2016


Author: vedantk
Date: Fri Jun 24 21:58:30 2016
New Revision: 273767

URL: http://llvm.org/viewvc/llvm-project?rev=273767&view=rev
Log:
[llvm-cov] Separate presentation logic from formatting logic, NFC

This makes it easier to add renderers for new kinds of output formats.

- Define and document a pure-virtual coverage rendering interface.
- Move the text-based rendering logic into its a new file.
- Re-work the API to better reflect the presentation/formatting split.

Added:
    llvm/trunk/tools/llvm-cov/SourceCoverageViewText.cpp
    llvm/trunk/tools/llvm-cov/SourceCoverageViewText.h
Modified:
    llvm/trunk/tools/llvm-cov/CMakeLists.txt
    llvm/trunk/tools/llvm-cov/CodeCoverage.cpp
    llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp
    llvm/trunk/tools/llvm-cov/SourceCoverageView.h

Modified: llvm/trunk/tools/llvm-cov/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CMakeLists.txt?rev=273767&r1=273766&r2=273767&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/CMakeLists.txt (original)
+++ llvm/trunk/tools/llvm-cov/CMakeLists.txt Fri Jun 24 21:58:30 2016
@@ -8,5 +8,6 @@ add_llvm_tool(llvm-cov
   CoverageReport.cpp
   CoverageSummaryInfo.cpp
   SourceCoverageView.cpp
+  SourceCoverageViewText.cpp
   TestingSupport.cpp
   )

Modified: llvm/trunk/tools/llvm-cov/CodeCoverage.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CodeCoverage.cpp?rev=273767&r1=273766&r2=273767&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/CodeCoverage.cpp (original)
+++ llvm/trunk/tools/llvm-cov/CodeCoverage.cpp Fri Jun 24 21:58:30 2016
@@ -132,9 +132,9 @@ CodeCoverageTool::attachExpansionSubView
       continue;
 
     auto SubViewExpansions = ExpansionCoverage.getExpansions();
-    auto SubView = llvm::make_unique<SourceCoverageView>(
-        Expansion.Function.Name, SourceBuffer.get(), ViewOpts,
-        std::move(ExpansionCoverage));
+    auto SubView =
+        SourceCoverageView::create(Expansion.Function.Name, SourceBuffer.get(),
+                                   ViewOpts, std::move(ExpansionCoverage));
     attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
     View.addExpansion(Expansion.Region, std::move(SubView));
   }
@@ -151,8 +151,8 @@ CodeCoverageTool::createFunctionView(con
     return nullptr;
 
   auto Expansions = FunctionCoverage.getExpansions();
-  auto View = llvm::make_unique<SourceCoverageView>(
-      Function.Name, SourceBuffer.get(), ViewOpts, std::move(FunctionCoverage));
+  auto View = SourceCoverageView::create(Function.Name, SourceBuffer.get(),
+                                         ViewOpts, std::move(FunctionCoverage));
   attachExpansionSubViews(*View, Expansions, Coverage);
 
   return View;
@@ -169,16 +169,16 @@ CodeCoverageTool::createSourceFileView(S
     return nullptr;
 
   auto Expansions = FileCoverage.getExpansions();
-  auto View = llvm::make_unique<SourceCoverageView>(
-      SourceFile, SourceBuffer.get(), ViewOpts, std::move(FileCoverage));
+  auto View = SourceCoverageView::create(SourceFile, SourceBuffer.get(),
+                                         ViewOpts, std::move(FileCoverage));
   attachExpansionSubViews(*View, Expansions, Coverage);
 
   for (auto Function : Coverage.getInstantiations(SourceFile)) {
     auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
     auto SubViewExpansions = SubViewCoverage.getExpansions();
-    auto SubView = llvm::make_unique<SourceCoverageView>(
-        Function->Name, SourceBuffer.get(), ViewOpts,
-        std::move(SubViewCoverage));
+    auto SubView =
+        SourceCoverageView::create(Function->Name, SourceBuffer.get(), ViewOpts,
+                                   std::move(SubViewCoverage));
     attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
 
     if (SubView) {
@@ -428,8 +428,7 @@ int CodeCoverageTool::show(int argc, con
             << "\n";
         continue;
       }
-      mainView->renderSourceName(outs());
-      mainView->render(outs(), /*WholeFile=*/false);
+      mainView->print(outs(), /*WholeFile=*/false, /*ShowSourceName=*/true);
       outs() << "\n";
     }
     return 0;
@@ -452,10 +451,7 @@ int CodeCoverageTool::show(int argc, con
       continue;
     }
 
-    if (ShowFilenames)
-      mainView->renderSourceName(outs());
-
-    mainView->render(outs(), /*Wholefile=*/true);
+    mainView->print(outs(), /*Wholefile=*/true, /*ShowSourceName=*/ShowFilenames);
     if (SourceFiles.size() > 1)
       outs() << "\n";
   }

Modified: llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp?rev=273767&r1=273766&r2=273767&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp (original)
+++ llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp Fri Jun 24 21:58:30 2016
@@ -12,75 +12,14 @@
 //===----------------------------------------------------------------------===//
 
 #include "SourceCoverageView.h"
-#include "llvm/ADT/Optional.h"
+#include "SourceCoverageViewText.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/LineIterator.h"
 
 using namespace llvm;
 
-void SourceCoverageView::renderLine(
-    raw_ostream &OS, StringRef Line, int64_t LineNumber,
-    const coverage::CoverageSegment *WrappedSegment,
-    ArrayRef<const coverage::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,
-                    getOptions().Colors && Highlight, /*Bold=*/false,
-                    /*BG=*/true)
-        << Line.substr(Col - 1, End - Col);
-    if (getOptions().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
-  colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR,
-                  getOptions().Colors && Highlight, /*Bold=*/false, /*BG=*/true)
-      << Line.substr(Col - 1, Line.size() - Col + 1);
-  OS << "\n";
-
-  if (getOptions().Debug) {
-    for (const auto &Range : HighlightedRanges)
-      errs() << "Highlighted line " << LineNumber << ", " << Range.first
-             << " -> " << Range.second << "\n";
-    if (Highlight)
-      errs() << "Highlighted line " << LineNumber << ", " << Col << " -> ?\n";
-  }
-}
-
-void SourceCoverageView::renderIndent(raw_ostream &OS, unsigned Level) {
-  for (unsigned I = 0; I < Level; ++I)
-    OS << "  |";
-}
-
-void SourceCoverageView::renderViewDivider(unsigned Level, unsigned Length,
-                                           raw_ostream &OS) {
-  assert(Level != 0 && "Cannot render divider at top level");
-  renderIndent(OS, Level - 1);
-  OS.indent(2);
-  for (unsigned I = 0; I < Length; ++I)
-    OS << "-";
-}
-
-/// Format a count using engineering notation with 3 significant digits.
-static std::string formatCount(uint64_t N) {
+std::string SourceCoverageView::formatCount(uint64_t N) {
   std::string Number = utostr(N);
   int Len = Number.size();
   if (Len <= 3)
@@ -95,63 +34,30 @@ static std::string formatCount(uint64_t
   return Result;
 }
 
-void
-SourceCoverageView::renderLineCoverageColumn(raw_ostream &OS,
-                                             const LineCoverageStats &Line) {
-  if (!Line.isMapped()) {
-    OS.indent(LineCoverageColumnWidth) << '|';
-    return;
-  }
-  std::string C = formatCount(Line.ExecutionCount);
-  OS.indent(LineCoverageColumnWidth - C.size());
-  colored_ostream(OS, raw_ostream::MAGENTA,
-                  Line.hasMultipleRegions() && getOptions().Colors)
-      << C;
-  OS << '|';
-}
-
-void SourceCoverageView::renderLineNumberColumn(raw_ostream &OS,
-                                                unsigned LineNo) {
-  SmallString<32> Buffer;
-  raw_svector_ostream BufferOS(Buffer);
-  BufferOS << LineNo;
-  auto Str = BufferOS.str();
-  // Trim and align to the right
-  Str = Str.substr(0, std::min(Str.size(), (size_t)LineNumberColumnWidth));
-  OS.indent(LineNumberColumnWidth - Str.size()) << Str << '|';
-}
-
-void SourceCoverageView::renderRegionMarkers(
-    raw_ostream &OS, ArrayRef<const coverage::CoverageSegment *> Segments) {
-  unsigned PrevColumn = 1;
-  for (const auto *S : Segments) {
-    if (!S->IsRegionEntry)
-      continue;
-    // Skip to the new region
-    if (S->Col > PrevColumn)
-      OS.indent(S->Col - PrevColumn);
-    PrevColumn = S->Col + 1;
-    std::string C = formatCount(S->Count);
-    PrevColumn += C.size();
-    OS << '^' << C;
-  }
-  OS << "\n";
-
-  if (getOptions().Debug)
-    for (const auto *S : Segments)
-      errs() << "Marker at " << S->Line << ":" << S->Col << " = "
-             << formatCount(S->Count) << (S->IsRegionEntry ? "\n" : " (pop)\n");
-}
-
-void SourceCoverageView::render(raw_ostream &OS, bool WholeFile,
-                                unsigned IndentLevel) {
-  // The width of the leading columns
-  unsigned CombinedColumnWidth =
-      (getOptions().ShowLineStats ? LineCoverageColumnWidth + 1 : 0) +
-      (getOptions().ShowLineNumbers ? LineNumberColumnWidth + 1 : 0);
-  // The width of the line that is used to divide between the view and the
-  // subviews.
-  unsigned DividerWidth = CombinedColumnWidth + 4;
+void SourceCoverageView::addExpansion(
+    const coverage::CounterMappingRegion &Region,
+    std::unique_ptr<SourceCoverageView> View) {
+  ExpansionSubViews.emplace_back(Region, std::move(View));
+}
+
+void SourceCoverageView::addInstantiation(
+    StringRef FunctionName, unsigned Line,
+    std::unique_ptr<SourceCoverageView> View) {
+  InstantiationSubViews.emplace_back(FunctionName, Line, std::move(View));
+}
+
+std::unique_ptr<SourceCoverageView>
+SourceCoverageView::create(StringRef SourceName, const MemoryBuffer &File,
+                           const CoverageViewOptions &Options,
+                           coverage::CoverageData &&CoverageInfo) {
+  return llvm::make_unique<SourceCoverageViewText>(SourceName, File, Options,
+                                                   std::move(CoverageInfo));
+}
+
+void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
+                               bool ShowSourceName, unsigned ViewDepth) {
+  if (ShowSourceName)
+    renderSourceName(OS);
 
   // We need the expansions and instantiations sorted so we can go through them
   // while we iterate lines.
@@ -192,10 +98,9 @@ void SourceCoverageView::render(raw_ostr
       LineCount.addRegionCount(WrappedSegment->Count);
     for (const auto *S : LineSegments)
       if (S->HasCount && S->IsRegionEntry)
-          LineCount.addRegionStartCount(S->Count);
+        LineCount.addRegionStartCount(S->Count);
 
-    // Render the line prefix.
-    renderIndent(OS, IndentLevel);
+    renderLinePrefix(OS, ViewDepth);
     if (getOptions().ShowLineStats)
       renderLineCoverageColumn(OS, LineCount);
     if (getOptions().ShowLineNumbers)
@@ -208,62 +113,34 @@ void SourceCoverageView::render(raw_ostr
       ExpansionColumn = NextESV->getStartCol();
 
     // Display the source code for the current line.
-    renderLine(OS, *LI, LI.line_number(), WrappedSegment, LineSegments,
-               ExpansionColumn);
+    renderLine(OS, {*LI, LI.line_number()}, WrappedSegment, LineSegments,
+               ExpansionColumn, ViewDepth);
 
     // Show the region markers.
     if (getOptions().ShowRegionMarkers &&
         (!getOptions().ShowLineStatsOrRegionMarkers ||
          LineCount.hasMultipleRegions()) &&
         !LineSegments.empty()) {
-      renderIndent(OS, IndentLevel);
-      OS.indent(CombinedColumnWidth);
-      renderRegionMarkers(OS, LineSegments);
+      renderRegionMarkers(OS, LineSegments, ViewDepth);
     }
 
     // Show the expansions and instantiations for this line.
-    unsigned NestedIndent = IndentLevel + 1;
     bool RenderedSubView = false;
     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.
-        ExpansionColumn = NextESV->getStartCol();
-        renderIndent(OS, IndentLevel);
-        OS.indent(CombinedColumnWidth + (IndentLevel == 0 ? 0 : 1));
-        renderLine(OS, *LI, LI.line_number(), WrappedSegment, LineSegments,
-                   ExpansionColumn);
-        renderViewDivider(NestedIndent, DividerWidth, OS);
-        OS << "\n";
-      }
-      // Render the child subview
-      if (getOptions().Debug)
-        errs() << "Expansion at line " << NextESV->getLine() << ", "
-               << NextESV->getStartCol() << " -> " << NextESV->getEndCol()
-               << "\n";
-      NextESV->View->render(OS, false, NestedIndent);
+      renderViewDivider(OS, ViewDepth + 1);
+      ExpansionColumn = renderExpansionView(
+          OS, *NextESV,
+          RenderedSubView ? Optional<LineRef>({*LI, LI.line_number()})
+                          : Optional<LineRef>(),
+          ExpansionColumn, WrappedSegment, LineSegments, ViewDepth);
       RenderedSubView = true;
     }
     for (; NextISV != EndISV && NextISV->Line == LI.line_number(); ++NextISV) {
-      renderViewDivider(NestedIndent, DividerWidth, OS);
-      OS << "\n";
-      renderIndent(OS, NestedIndent);
-      OS << ' ';
-      NextISV->View->renderSourceName(OS);
-      NextISV->View->render(OS, false, NestedIndent);
+      renderInstantiationView(OS, *NextISV, ViewDepth + 1);
       RenderedSubView = true;
     }
-    if (RenderedSubView) {
-      renderViewDivider(NestedIndent, DividerWidth, OS);
-      OS << "\n";
-    }
+    if (RenderedSubView)
+      renderViewDivider(OS, ViewDepth + 1);
   }
 }
-
-void SourceCoverageView::renderSourceName(raw_ostream &OS) {
-  getOptions().colored_ostream(OS, raw_ostream::CYAN) << getSourceName()
-                                                      << ":\n";
-}

Modified: llvm/trunk/tools/llvm-cov/SourceCoverageView.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/SourceCoverageView.h?rev=273767&r1=273766&r2=273767&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/SourceCoverageView.h (original)
+++ llvm/trunk/tools/llvm-cov/SourceCoverageView.h Fri Jun 24 21:58:30 2016
@@ -16,6 +16,7 @@
 
 #include "CoverageViewOptions.h"
 #include "llvm/ProfileData/Coverage/CoverageMapping.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include <vector>
 
@@ -100,7 +101,6 @@ struct LineCoverageStats {
 /// \brief A code coverage view of a specific source file.
 /// It can have embedded coverage views.
 class SourceCoverageView {
-private:
   /// A function or file name.
   StringRef SourceName;
 
@@ -120,59 +120,93 @@ private:
   /// on display.
   std::vector<InstantiationView> InstantiationSubViews;
 
-  /// \brief Render a source line with highlighting.
-  void renderLine(raw_ostream &OS, StringRef Line, int64_t LineNumber,
-                  const coverage::CoverageSegment *WrappedSegment,
-                  ArrayRef<const coverage::CoverageSegment *> Segments,
-                  unsigned ExpansionCol);
+protected:
+  struct LineRef {
+    StringRef Line;
+    int64_t LineNo;
+
+    LineRef(StringRef Line, int64_t LineNo) : Line(Line), LineNo(LineNo) {}
+  };
+
+  using CoverageSegmentArray = ArrayRef<const coverage::CoverageSegment *>;
+
+  /// @name Rendering Interface
+  /// @{
 
-  void renderIndent(raw_ostream &OS, unsigned Level);
+  /// \brief Render the source name for the view.
+  virtual void renderSourceName(raw_ostream &OS) = 0;
 
-  void renderViewDivider(unsigned Offset, unsigned Length, raw_ostream &OS);
+  /// \brief Render the line prefix at the given \p ViewDepth.
+  virtual void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) = 0;
+
+  /// \brief Render a view divider at the given \p ViewDepth.
+  virtual void renderViewDivider(raw_ostream &OS, unsigned ViewDepth) = 0;
+
+  /// \brief Render a source line with highlighting.
+  virtual void renderLine(raw_ostream &OS, LineRef L,
+                          const coverage::CoverageSegment *WrappedSegment,
+                          CoverageSegmentArray Segments, unsigned ExpansionCol,
+                          unsigned ViewDepth) = 0;
 
   /// \brief Render the line's execution count column.
-  void renderLineCoverageColumn(raw_ostream &OS, const LineCoverageStats &Line);
+  virtual void renderLineCoverageColumn(raw_ostream &OS,
+                                        const LineCoverageStats &Line) = 0;
 
   /// \brief Render the line number column.
-  void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo);
+  virtual void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) = 0;
 
   /// \brief Render all the region's execution counts on a line.
-  void
-  renderRegionMarkers(raw_ostream &OS,
-                      ArrayRef<const coverage::CoverageSegment *> Segments);
-
-  static const unsigned LineCoverageColumnWidth = 7;
-  static const unsigned LineNumberColumnWidth = 5;
+  virtual void renderRegionMarkers(raw_ostream &OS,
+                                   CoverageSegmentArray Segments,
+                                   unsigned ViewDepth) = 0;
+
+  /// \brief Render an expansion view. If \p FirstLine is provided, it points
+  /// to the expansion site, which must be re-rendered for clarity.
+  virtual unsigned renderExpansionView(
+      raw_ostream &OS, ExpansionView &ESV, Optional<LineRef> FirstLine,
+      unsigned ExpansionCol, const coverage::CoverageSegment *WrappedSegment,
+      CoverageSegmentArray LineSegments, unsigned ViewDepth) = 0;
+
+  /// \brief Render an instantiation view.
+  virtual void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV,
+                                       unsigned ViewDepth) = 0;
+
+  /// @}
+
+  /// \brief Format a count using engineering notation with 3 significant
+  /// digits.
+  static std::string formatCount(uint64_t N);
 
-public:
   SourceCoverageView(StringRef SourceName, const MemoryBuffer &File,
                      const CoverageViewOptions &Options,
                      coverage::CoverageData &&CoverageInfo)
       : SourceName(SourceName), File(File), Options(Options),
         CoverageInfo(std::move(CoverageInfo)) {}
 
+public:
+  static std::unique_ptr<SourceCoverageView>
+  create(StringRef SourceName, const MemoryBuffer &File,
+         const CoverageViewOptions &Options,
+         coverage::CoverageData &&CoverageInfo);
+
+  virtual ~SourceCoverageView() {}
+
   StringRef getSourceName() const { return SourceName; }
 
   const CoverageViewOptions &getOptions() const { return Options; }
 
   /// \brief Add an expansion subview to this view.
   void addExpansion(const coverage::CounterMappingRegion &Region,
-                    std::unique_ptr<SourceCoverageView> View) {
-    ExpansionSubViews.emplace_back(Region, std::move(View));
-  }
+                    std::unique_ptr<SourceCoverageView> View);
 
   /// \brief Add a function instantiation subview to this view.
   void addInstantiation(StringRef FunctionName, unsigned Line,
-                        std::unique_ptr<SourceCoverageView> View) {
-    InstantiationSubViews.emplace_back(FunctionName, Line, std::move(View));
-  }
-
-  /// \brief Print the code coverage information for a specific
-  /// portion of a source file to the output stream.
-  void render(raw_ostream &OS, bool WholeFile, unsigned IndentLevel = 0);
+                        std::unique_ptr<SourceCoverageView> View);
 
-  /// \brief Print the source name corresponding to this view.
-  void renderSourceName(raw_ostream &OS);
+  /// \brief Print the code coverage information for a specific portion of a
+  /// source file to the output stream.
+  void print(raw_ostream &OS, bool WholeFile, bool ShowSourceName,
+             unsigned ViewDepth = 0);
 };
 
 } // namespace llvm

Added: llvm/trunk/tools/llvm-cov/SourceCoverageViewText.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/SourceCoverageViewText.cpp?rev=273767&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/SourceCoverageViewText.cpp (added)
+++ llvm/trunk/tools/llvm-cov/SourceCoverageViewText.cpp Fri Jun 24 21:58:30 2016
@@ -0,0 +1,193 @@
+//===- SourceCoverageViewText.cpp - A text-based code coverage view -------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the text-based coverage renderer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SourceCoverageViewText.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+
+using namespace llvm;
+
+namespace {
+
+constexpr unsigned LineCoverageColumnWidth = 7;
+constexpr unsigned LineNumberColumnWidth = 5;
+
+/// \brief Get the width of the leading columns.
+unsigned getCombinedColumnWidth(const CoverageViewOptions &Opts) {
+  return (Opts.ShowLineStats ? LineCoverageColumnWidth + 1 : 0) +
+         (Opts.ShowLineNumbers ? LineNumberColumnWidth + 1 : 0);
+}
+
+/// \brief The width of the line that is used to divide between the view and
+/// the subviews.
+unsigned getDividerWidth(const CoverageViewOptions &Opts) {
+  return getCombinedColumnWidth(Opts) + 4;
+}
+
+} // anonymous namespace
+
+void SourceCoverageViewText::renderSourceName(raw_ostream &OS) {
+  getOptions().colored_ostream(OS, raw_ostream::CYAN) << getSourceName()
+                                                      << ":\n";
+}
+
+void SourceCoverageViewText::renderLinePrefix(raw_ostream &OS,
+                                              unsigned ViewDepth) {
+  for (unsigned I = 0; I < ViewDepth; ++I)
+    OS << "  |";
+}
+
+void SourceCoverageViewText::renderViewDivider(raw_ostream &OS,
+                                               unsigned ViewDepth) {
+  assert(ViewDepth != 0 && "Cannot render divider at top level");
+  renderLinePrefix(OS, ViewDepth - 1);
+  OS.indent(2);
+  unsigned Length = getDividerWidth(getOptions());
+  for (unsigned I = 0; I < Length; ++I)
+    OS << '-';
+  OS << '\n';
+}
+
+void SourceCoverageViewText::renderLine(
+    raw_ostream &OS, LineRef L,
+    const coverage::CoverageSegment *WrappedSegment,
+    CoverageSegmentArray Segments, unsigned ExpansionCol, unsigned ViewDepth) {
+  StringRef Line = L.Line;
+  unsigned LineNumber = L.LineNo;
+
+  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,
+                    getOptions().Colors && Highlight, /*Bold=*/false,
+                    /*BG=*/true)
+        << Line.substr(Col - 1, End - Col);
+    if (getOptions().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.
+  colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR,
+                  getOptions().Colors && Highlight, /*Bold=*/false, /*BG=*/true)
+      << Line.substr(Col - 1, Line.size() - Col + 1);
+  OS << '\n';
+
+  if (getOptions().Debug) {
+    for (const auto &Range : HighlightedRanges)
+      errs() << "Highlighted line " << LineNumber << ", " << Range.first
+             << " -> " << Range.second << '\n';
+    if (Highlight)
+      errs() << "Highlighted line " << LineNumber << ", " << Col << " -> ?\n";
+  }
+}
+
+void SourceCoverageViewText::renderLineCoverageColumn(
+    raw_ostream &OS, const LineCoverageStats &Line) {
+  if (!Line.isMapped()) {
+    OS.indent(LineCoverageColumnWidth) << '|';
+    return;
+  }
+  std::string C = formatCount(Line.ExecutionCount);
+  OS.indent(LineCoverageColumnWidth - C.size());
+  colored_ostream(OS, raw_ostream::MAGENTA,
+                  Line.hasMultipleRegions() && getOptions().Colors)
+      << C;
+  OS << '|';
+}
+
+void SourceCoverageViewText::renderLineNumberColumn(raw_ostream &OS,
+                                                    unsigned LineNo) {
+  SmallString<32> Buffer;
+  raw_svector_ostream BufferOS(Buffer);
+  BufferOS << LineNo;
+  auto Str = BufferOS.str();
+  // Trim and align to the right.
+  Str = Str.substr(0, std::min(Str.size(), (size_t)LineNumberColumnWidth));
+  OS.indent(LineNumberColumnWidth - Str.size()) << Str << '|';
+}
+
+void SourceCoverageViewText::renderRegionMarkers(
+    raw_ostream &OS, CoverageSegmentArray Segments, unsigned ViewDepth) {
+  renderLinePrefix(OS, ViewDepth);
+  OS.indent(getCombinedColumnWidth(getOptions()));
+
+  unsigned PrevColumn = 1;
+  for (const auto *S : Segments) {
+    if (!S->IsRegionEntry)
+      continue;
+    // Skip to the new region.
+    if (S->Col > PrevColumn)
+      OS.indent(S->Col - PrevColumn);
+    PrevColumn = S->Col + 1;
+    std::string C = formatCount(S->Count);
+    PrevColumn += C.size();
+    OS << '^' << C;
+  }
+  OS << '\n';
+
+  if (getOptions().Debug)
+    for (const auto *S : Segments)
+      errs() << "Marker at " << S->Line << ":" << S->Col << " = "
+             << formatCount(S->Count) << (S->IsRegionEntry ? "\n" : " (pop)\n");
+}
+
+unsigned SourceCoverageViewText::renderExpansionView(
+    raw_ostream &OS, ExpansionView &ESV, Optional<LineRef> FirstLine,
+    unsigned ExpansionCol, const coverage::CoverageSegment *WrappedSegment,
+    CoverageSegmentArray LineSegments, unsigned ViewDepth) {
+  unsigned NextExpansionCol = ExpansionCol;
+
+  if (FirstLine.hasValue()) {
+    // Re-render the current line and highlight the expansion range for
+    // this subview.
+    NextExpansionCol = ESV.getStartCol();
+    renderLinePrefix(OS, ViewDepth);
+    OS.indent(getCombinedColumnWidth(getOptions()) + (ViewDepth == 0 ? 0 : 1));
+    renderLine(OS, *FirstLine, WrappedSegment, LineSegments, ExpansionCol,
+               ViewDepth);
+    renderViewDivider(OS, ViewDepth + 1);
+  }
+
+  // Render the child subview.
+  if (getOptions().Debug)
+    errs() << "Expansion at line " << ESV.getLine() << ", " << ESV.getStartCol()
+           << " -> " << ESV.getEndCol() << '\n';
+  ESV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/false,
+                  ViewDepth + 1);
+
+  return NextExpansionCol;
+}
+
+void SourceCoverageViewText::renderInstantiationView(raw_ostream &OS,
+                                                     InstantiationView &ISV,
+                                                     unsigned ViewDepth) {
+  renderViewDivider(OS, ViewDepth);
+  renderLinePrefix(OS, ViewDepth);
+  OS << ' ';
+  ISV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/true, ViewDepth);
+}

Added: llvm/trunk/tools/llvm-cov/SourceCoverageViewText.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/SourceCoverageViewText.h?rev=273767&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/SourceCoverageViewText.h (added)
+++ llvm/trunk/tools/llvm-cov/SourceCoverageViewText.h Fri Jun 24 21:58:30 2016
@@ -0,0 +1,61 @@
+//===- SourceCoverageViewText.h - A text-based code coverage view ---------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the interface to the text-based coverage renderer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_COV_SOURCECOVERAGEVIEWTEXT_H
+#define LLVM_COV_SOURCECOVERAGEVIEWTEXT_H
+
+#include "SourceCoverageView.h"
+
+namespace llvm {
+
+class SourceCoverageViewText : public SourceCoverageView {
+  void renderSourceName(raw_ostream &OS) override;
+
+  void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) override;
+
+  void renderViewDivider(raw_ostream &OS, unsigned ViewDepth) override;
+
+  void renderLine(raw_ostream &OS, LineRef L,
+                  const coverage::CoverageSegment *WrappedSegment,
+                  CoverageSegmentArray Segments, unsigned ExpansionCol,
+                  unsigned ViewDepth) override;
+
+  unsigned renderExpansionView(raw_ostream &OS, ExpansionView &ESV,
+                               Optional<LineRef> FirstLine,
+                               unsigned ExpansionCol,
+                               const coverage::CoverageSegment *WrappedSegment,
+                               CoverageSegmentArray LineSegments,
+                               unsigned ViewDepth) override;
+
+  void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV,
+                               unsigned ViewDepth) override;
+
+  void renderLineCoverageColumn(raw_ostream &OS,
+                                const LineCoverageStats &Line) override;
+
+  void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) override;
+
+  void renderRegionMarkers(raw_ostream &OS, CoverageSegmentArray Segments,
+                           unsigned ViewDepth) override;
+
+public:
+  SourceCoverageViewText(StringRef SourceName, const MemoryBuffer &File,
+                         const CoverageViewOptions &Options,
+                         coverage::CoverageData &&CoverageInfo)
+      : SourceCoverageView(SourceName, File, Options, std::move(CoverageInfo)) {
+  }
+};
+
+} // namespace llvm
+
+#endif // LLVM_COV_SOURCECOVERAGEVIEWTEXT_H




More information about the llvm-commits mailing list