[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.

llvm-svn: 273767
diff --git a/llvm/tools/llvm-cov/SourceCoverageView.h b/llvm/tools/llvm-cov/SourceCoverageView.h
index 2e98151..ef237d8 100644
--- a/llvm/tools/llvm-cov/SourceCoverageView.h
+++ b/llvm/tools/llvm-cov/SourceCoverageView.h
@@ -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 @@
 /// \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 @@
   /// on display.
   std::vector<InstantiationView> InstantiationSubViews;
 
+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
+  /// @{
+
+  /// \brief Render the source name for the view.
+  virtual void renderSourceName(raw_ostream &OS) = 0;
+
+  /// \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.
-  void renderLine(raw_ostream &OS, StringRef Line, int64_t LineNumber,
-                  const coverage::CoverageSegment *WrappedSegment,
-                  ArrayRef<const coverage::CoverageSegment *> Segments,
-                  unsigned ExpansionCol);
-
-  void renderIndent(raw_ostream &OS, unsigned Level);
-
-  void renderViewDivider(unsigned Offset, unsigned Length, raw_ostream &OS);
+  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);
+  virtual void renderRegionMarkers(raw_ostream &OS,
+                                   CoverageSegmentArray Segments,
+                                   unsigned ViewDepth) = 0;
 
-  static const unsigned LineCoverageColumnWidth = 7;
-  static const unsigned LineNumberColumnWidth = 5;
+  /// \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;
 
-public:
+  /// \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);
+
   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));
-  }
+                        std::unique_ptr<SourceCoverageView> 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);
-
-  /// \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