[llvm-cov] Create an index of reports in -output-dir mode

This index lists the reports available in the 'coverage' sub-directory.
This will help navigate coverage output from large projects.

This commit factors the file creation code out of SourceCoverageView and
into CoveragePrinter.

llvm-svn: 274029
diff --git a/llvm/tools/llvm-cov/SourceCoverageView.h b/llvm/tools/llvm-cov/SourceCoverageView.h
index def5c6a..3244dc8 100644
--- a/llvm/tools/llvm-cov/SourceCoverageView.h
+++ b/llvm/tools/llvm-cov/SourceCoverageView.h
@@ -97,11 +97,59 @@
   }
 };
 
+/// \brief A file manager that handles format-aware file creation.
+class CoveragePrinter {
+  const CoverageViewOptions &Opts;
+
+public:
+  struct StreamDestructor {
+    void operator()(raw_ostream *OS) const;
+  };
+
+  using OwnedStream = std::unique_ptr<raw_ostream, StreamDestructor>;
+
+protected:
+  CoveragePrinter(const CoverageViewOptions &Opts) : Opts(Opts) {}
+
+  /// \brief Return `OutputDir/ToplevelDir/Path.Extension`.
+  std::string getOutputPath(StringRef Path, StringRef Extension,
+                            bool InToplevel);
+
+  /// \brief If directory output is enabled, create a file in that directory
+  /// at the path given by getOutputPath(). Otherwise, return stdout.
+  Expected<OwnedStream> createOutputStream(StringRef Path, StringRef Extension,
+                                           bool InToplevel);
+
+  /// \brief Return the sub-directory name for file coverage reports.
+  static StringRef getCoverageDir() { return "coverage"; }
+
+public:
+  static std::unique_ptr<CoveragePrinter>
+  create(const CoverageViewOptions &Opts);
+
+  virtual ~CoveragePrinter() {}
+
+  /// @name File Creation Interface
+  /// @{
+
+  /// \brief Create a file to print a coverage view into.
+  virtual Expected<OwnedStream> createViewFile(StringRef Path,
+                                               bool InToplevel) = 0;
+
+  /// \brief Close a file which has been used to print a coverage view.
+  virtual void closeViewFile(OwnedStream OS) = 0;
+
+  /// \brief Create an index which lists reports for the given source files.
+  virtual Error createIndexFile(ArrayRef<StringRef> SourceFiles) = 0;
+
+  /// @}
+};
+
 /// \brief A code coverage view of a source file or function.
 ///
 /// A source coverage view and its nested sub-views form a file-oriented
 /// representation of code coverage data. This view can be printed out by a
-/// renderer which implements both the File Creation and Rendering interfaces.
+/// renderer which implements the Rendering Interface.
 class SourceCoverageView {
   /// A function or file name.
   StringRef SourceName;
@@ -122,25 +170,6 @@
   /// on display.
   std::vector<InstantiationView> InstantiationSubViews;
 
-public:
-  struct StreamDestructor {
-    void operator()(raw_ostream *OS) const;
-  };
-
-  using OwnedStream = std::unique_ptr<raw_ostream, StreamDestructor>;
-
-  /// @name File Creation Interface
-  /// @{
-
-  /// \brief Create a file to print a coverage view into.
-  virtual Expected<OwnedStream> createOutputFile(StringRef Path,
-                                                 bool InToplevel) = 0;
-
-  /// \brief Close a file which has been used to print a coverage view.
-  virtual void closeOutputFile(OwnedStream OS) = 0;
-
-  /// @}
-
 protected:
   struct LineRef {
     StringRef Line;
@@ -202,12 +231,6 @@
   /// digits.
   static std::string formatCount(uint64_t N);
 
-  /// \brief If directory output is enabled, create a file with \p Path as the
-  /// suffix. Otherwise, return stdout.
-  static Expected<OwnedStream>
-  createOutputStream(const CoverageViewOptions &Opts, StringRef Path,
-                     StringRef Extension, bool InToplevel);
-
   SourceCoverageView(StringRef SourceName, const MemoryBuffer &File,
                      const CoverageViewOptions &Options,
                      coverage::CoverageData &&CoverageInfo)