[llvm-cov] Create directory structure when filtering using -name*= options

Before this change using any of the -name*= command line options with an output
directory would result in a single file (functions.txt/functions.html)
containing the coverage for those specific functions. Now you get the same
directory structure as when not using any -name*= options.

Differential Revision: https://reviews.llvm.org/D38280

llvm-svn: 314396
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index 1ea54a8..1b9f232 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -35,7 +35,9 @@
 #include "llvm/Support/Threading.h"
 #include "llvm/Support/ThreadPool.h"
 #include "llvm/Support/ToolOutputFile.h"
+
 #include <functional>
+#include <map>
 #include <system_error>
 
 using namespace llvm;
@@ -526,7 +528,8 @@
   auto OS = std::move(OSOrErr.get());
 
   View->print(*OS.get(), /*Wholefile=*/true,
-              /*ShowSourceName=*/ShowFilenames);
+              /*ShowSourceName=*/ShowFilenames,
+              /*ShowTitle=*/ViewOpts.hasOutputDirectory());
   Printer->closeViewFile(std::move(OS));
 }
 
@@ -845,37 +848,6 @@
 
   auto Printer = CoveragePrinter::create(ViewOpts);
 
-  if (!Filters.empty()) {
-    auto OSOrErr = Printer->createViewFile("functions", /*InToplevel=*/true);
-    if (Error E = OSOrErr.takeError()) {
-      error("Could not create view file!", toString(std::move(E)));
-      return 1;
-    }
-    auto OS = std::move(OSOrErr.get());
-
-    // Show functions.
-    for (const auto &Function : Coverage->getCoveredFunctions()) {
-      if (!Filters.matches(*Coverage.get(), Function))
-        continue;
-
-      auto mainView = createFunctionView(Function, *Coverage);
-      if (!mainView) {
-        warning("Could not read coverage for '" + Function.Name + "'.");
-        continue;
-      }
-
-      mainView->print(*OS.get(), /*WholeFile=*/false, /*ShowSourceName=*/true);
-    }
-
-    Printer->closeViewFile(std::move(OS));
-    return 0;
-  }
-
-  // Show files
-  bool ShowFilenames =
-      (SourceFiles.size() != 1) || ViewOpts.hasOutputDirectory() ||
-      (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML);
-
   if (SourceFiles.empty())
     // Get the source files from the function coverage mapping.
     for (StringRef Filename : Coverage->getUniqueSourceFiles())
@@ -883,12 +855,55 @@
 
   // Create an index out of the source files.
   if (ViewOpts.hasOutputDirectory()) {
-    if (Error E = Printer->createIndexFile(SourceFiles, *Coverage)) {
+    if (Error E = Printer->createIndexFile(SourceFiles, *Coverage, Filters)) {
       error("Could not create index file!", toString(std::move(E)));
       return 1;
     }
   }
 
+  if (!Filters.empty()) {
+    // Build the map of filenames to functions.
+    std::map<llvm::StringRef, std::vector<const FunctionRecord *>>
+        FilenameFunctionMap;
+    for (const auto &SourceFile : SourceFiles)
+      for (const auto &Function : Coverage->getCoveredFunctions(SourceFile))
+        if (Filters.matches(*Coverage.get(), Function))
+          FilenameFunctionMap[SourceFile].push_back(&Function);
+
+    // Only print filter matching functions for each file.
+    for (const auto &FileFunc : FilenameFunctionMap) {
+      StringRef File = FileFunc.first;
+      const auto &Functions = FileFunc.second;
+
+      auto OSOrErr = Printer->createViewFile(File, /*InToplevel=*/false);
+      if (Error E = OSOrErr.takeError()) {
+        error("Could not create view file!", toString(std::move(E)));
+        return 1;
+      }
+      auto OS = std::move(OSOrErr.get());
+
+      bool ShowTitle = true;
+      for (const auto *Function : Functions) {
+        auto FunctionView = createFunctionView(*Function, *Coverage);
+        if (!FunctionView) {
+          warning("Could not read coverage for '" + Function->Name + "'.");
+          continue;
+        }
+        FunctionView->print(*OS.get(), /*WholeFile=*/false,
+                            /*ShowSourceName=*/true, ShowTitle);
+        ShowTitle = false;
+      }
+
+      Printer->closeViewFile(std::move(OS));
+    }
+    return 0;
+  }
+
+  // Show files
+  bool ShowFilenames =
+      (SourceFiles.size() != 1) || ViewOpts.hasOutputDirectory() ||
+      (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML);
+
   // If NumThreads is not specified, auto-detect a good default.
   if (NumThreads == 0)
     NumThreads =