[llvm-cov] Use relative paths to the stylesheet (for html reports)

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
This commit is contained in:
Vedant Kumar 2016-07-21 23:26:15 +00:00
parent 31fd506623
commit c076c49076
3 changed files with 95 additions and 58 deletions

View File

@ -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'>

View 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

View 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();
}