[llvm-cov] Use relative paths to the stylesheet (for html reports)
authorVedant Kumar <vsk@apple.com>
Thu, 21 Jul 2016 23:26:15 +0000 (23:26 +0000)
committerVedant Kumar <vsk@apple.com>
Thu, 21 Jul 2016 23:26:15 +0000 (23:26 +0000)
This makes it easy to swap out the default stylesheet for a custom one.
It also shaves ~6.62 MB out of the report directory for a full coverage
build of llvm+clang.

While we're at it, prune the CSS and add tests for it.

llvm-svn: 276359

llvm/test/tools/llvm-cov/style.test [new file with mode: 0644]
llvm/tools/llvm-cov/SourceCoverageView.h
llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp

diff --git a/llvm/test/tools/llvm-cov/style.test b/llvm/test/tools/llvm-cov/style.test
new file mode 100644 (file)
index 0000000..3cad21f
--- /dev/null
@@ -0,0 +1,22 @@
+RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -filename-equivalence %S/showTemplateInstantiations.cpp -format html -o %t.dir
+
+RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -filename-equivalence -name=_Z4funcIbEiT_ %S/showTemplateInstantiations.cpp -format html -o %t.dir
+
+RUN: FileCheck %s -input-file=%t.dir/style.css -check-prefix=STYLE
+RUN: FileCheck %s -input-file=%t.dir/functions.html -check-prefix=FUNCTIONS
+RUN: FileCheck %s -input-file=%t.dir/coverage/tmp/showTemplateInstantiations.cpp.html -check-prefix=FILEVIEW
+
+STYLE-DAG: .red
+STYLE-DAG: .cyan
+STYLE-DAG: .source-name-title
+STYLE-DAG: .centered
+STYLE-DAG: .expansion-view
+STYLE-DAG: .line-number
+STYLE-DAG: .covered-line
+STYLE-DAG: .uncovered-line
+STYLE-DAG: .tooltip
+STYLE-DAG: .tooltip span.tooltip-content
+
+FUNCTIONS: <link rel='stylesheet' type='text/css' href='style.css'>
+
+FILEVIEW: <link rel='stylesheet' type='text/css' href='..{{.*}}..{{.*}}style.css'>
index feef959..6f2c400 100644 (file)
@@ -99,8 +99,6 @@ struct LineCoverageStats {
 
 /// \brief A file manager that handles format-aware file creation.
 class CoveragePrinter {
-  const CoverageViewOptions &Opts;
-
 public:
   struct StreamDestructor {
     void operator()(raw_ostream *OS) const;
@@ -109,6 +107,8 @@ public:
   using OwnedStream = std::unique_ptr<raw_ostream, StreamDestructor>;
 
 protected:
+  const CoverageViewOptions &Opts;
+
   CoveragePrinter(const CoverageViewOptions &Opts) : Opts(Opts) {}
 
   /// \brief Return `OutputDir/ToplevelDir/Path.Extension`. If \p InToplevel is
index fb4ad2d..ceab556 100644 (file)
@@ -21,33 +21,51 @@ using namespace llvm;
 
 namespace {
 
+// Return a string with the special characters in \p Str escaped.
+std::string escape(StringRef Str) {
+  std::string Result;
+  for (char C : Str) {
+    if (C == '&')
+      Result += "&amp;";
+    else if (C == '<')
+      Result += "&lt;";
+    else if (C == '>')
+      Result += "&gt;";
+    else if (C == '\"')
+      Result += "&quot;";
+    else
+      Result += C;
+  }
+  return Result;
+}
+
+// Create a \p Name tag around \p Str, and optionally set its \p ClassName.
+std::string tag(const std::string &Name, const std::string &Str,
+                const std::string &ClassName = "") {
+  std::string Tag = "<" + Name;
+  if (ClassName != "")
+    Tag += " class='" + ClassName + "'";
+  return Tag + ">" + Str + "</" + Name + ">";
+}
+
+// Create an anchor to \p Link with the label \p Str.
+std::string a(const std::string &Link, const std::string &Str,
+              const std::string &TargetType = "href") {
+  return "<a " + TargetType + "='" + Link + "'>" + Str + "</a>";
+}
+
 const char *BeginHeader =
   "<head>"
     "<meta name='viewport' content='width=device-width,initial-scale=1'>"
     "<meta charset='UTF-8'>";
 
 const char *CSSForCoverage =
-  "<style>"
-R"(
-
-.red {
+    R"(.red {
   background-color: #FFD0D0;
 }
 .cyan {
   background-color: cyan;
 }
-.black {
-  background-color: black;
-  color: white;
-}
-.green {
-  background-color: #98FFA6;
-  color: white;
-}
-.magenta {
-  background-color: #F998FF;
-  color: white;
-}
 body {
   font-family: -apple-system, sans-serif;
 }
@@ -140,9 +158,7 @@ td:first-child {
 td:last-child {
   border-right: none;
 }
-
-)"
-  "</style>";
+)";
 
 const char *EndHeader = "</head>";
 
@@ -170,11 +186,28 @@ const char *BeginTable = "<table>";
 
 const char *EndTable = "</table>";
 
-void emitPrelude(raw_ostream &OS) {
+std::string getPathToStyle(StringRef ViewPath) {
+  std::string PathToStyle = "";
+  std::string PathSep = sys::path::get_separator();
+  unsigned NumSeps = ViewPath.count(PathSep);
+  for (unsigned I = 0, E = NumSeps; I < E; ++I)
+    PathToStyle += ".." + PathSep;
+  return PathToStyle + "style.css";
+}
+
+void emitPrelude(raw_ostream &OS, const std::string &PathToStyle = "") {
   OS << "<!doctype html>"
         "<html>"
-     << BeginHeader << CSSForCoverage << EndHeader << "<body>"
-     << BeginCenteredDiv;
+     << BeginHeader;
+
+  // Link to a stylesheet if one is available. Otherwise, use the default style.
+  if (PathToStyle.empty())
+    OS << "<style>" << CSSForCoverage << "</style>";
+  else
+    OS << "<link rel='stylesheet' type='text/css' href='" << escape(PathToStyle)
+       << "'>";
+
+  OS << EndHeader << "<body>" << BeginCenteredDiv;
 }
 
 void emitEpilog(raw_ostream &OS) {
@@ -182,39 +215,6 @@ void emitEpilog(raw_ostream &OS) {
                           "</html>";
 }
 
-// Return a string with the special characters in \p Str escaped.
-std::string escape(StringRef Str) {
-  std::string Result;
-  for (char C : Str) {
-    if (C == '&')
-      Result += "&amp;";
-    else if (C == '<')
-      Result += "&lt;";
-    else if (C == '>')
-      Result += "&gt;";
-    else if (C == '\"')
-      Result += "&quot;";
-    else
-      Result += C;
-  }
-  return Result;
-}
-
-// Create a \p Name tag around \p Str, and optionally set its \p ClassName.
-std::string tag(const std::string &Name, const std::string &Str,
-                const std::string &ClassName = "") {
-  std::string Tag = "<" + Name;
-  if (ClassName != "")
-    Tag += " class='" + ClassName + "'";
-  return Tag + ">" + Str + "</" + Name + ">";
-}
-
-// Create an anchor to \p Link with the label \p Str.
-std::string a(const std::string &Link, const std::string &Str,
-              const std::string &TargetType = "href") {
-  return "<a " + TargetType + "='" + Link + "'>" + Str + "</a>";
-}
-
 } // anonymous namespace
 
 Expected<CoveragePrinter::OwnedStream>
@@ -224,7 +224,14 @@ CoveragePrinterHTML::createViewFile(StringRef Path, bool InToplevel) {
     return OSOrErr;
 
   OwnedStream OS = std::move(OSOrErr.get());
-  emitPrelude(*OS.get());
+
+  if (!Opts.hasOutputDirectory()) {
+    emitPrelude(*OS.get());
+  } else {
+    std::string ViewPath = getOutputPath(Path, "html", InToplevel);
+    emitPrelude(*OS.get(), getPathToStyle(ViewPath));
+  }
+
   return std::move(OS);
 }
 
@@ -252,6 +259,14 @@ Error CoveragePrinterHTML::createIndexFile(ArrayRef<StringRef> SourceFiles) {
   OSRef << EndTable;
   emitEpilog(OSRef);
 
+  // Emit the default stylesheet.
+  auto CSSOrErr = createOutputStream("style", "css", /*InToplevel=*/true);
+  if (Error E = CSSOrErr.takeError())
+    return E;
+
+  OwnedStream CSS = std::move(CSSOrErr.get());
+  CSS->operator<<(CSSForCoverage);
+
   return Error::success();
 }