diff options
-rw-r--r-- | llvm/test/tools/llvm-cov/style.test | 22 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/SourceCoverageView.h | 4 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp | 127 |
3 files changed, 95 insertions, 58 deletions
diff --git a/llvm/test/tools/llvm-cov/style.test b/llvm/test/tools/llvm-cov/style.test new file mode 100644 index 00000000000..3cad21f4b66 --- /dev/null +++ b/llvm/test/tools/llvm-cov/style.test @@ -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'> diff --git a/llvm/tools/llvm-cov/SourceCoverageView.h b/llvm/tools/llvm-cov/SourceCoverageView.h index feef959f86b..6f2c4004c9b 100644 --- a/llvm/tools/llvm-cov/SourceCoverageView.h +++ b/llvm/tools/llvm-cov/SourceCoverageView.h @@ -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 diff --git a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp index fb4ad2d8dcd..ceab5566e62 100644 --- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp +++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp @@ -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 += "&"; + else if (C == '<') + Result += "<"; + else if (C == '>') + Result += ">"; + else if (C == '\"') + Result += """; + 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 += "&"; - else if (C == '<') - Result += "<"; - else if (C == '>') - Result += ">"; - else if (C == '\"') - Result += """; - 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(); } |