aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp')
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp126
1 files changed, 105 insertions, 21 deletions
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
index 17353b5..1c078ee9 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
@@ -11,11 +11,13 @@
///
//===----------------------------------------------------------------------===//
+#include "CoverageReport.h"
#include "SourceCoverageViewHTML.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/Path.h"
using namespace llvm;
@@ -73,7 +75,7 @@ const char *BeginHeader =
const char *CSSForCoverage =
R"(.red {
- background-color: #FFD0D0;
+ background-color: #ffd0d0;
}
.cyan {
background-color: cyan;
@@ -110,6 +112,25 @@ pre {
table {
border-collapse: collapse;
}
+.light-row {
+ background: #ffffff;
+ border: 1px solid #dbdbdb;
+}
+.column-entry {
+ text-align: right;
+}
+.column-entry-yellow {
+ text-align: right;
+ background-color: #ffffd0;
+}
+.column-entry-red {
+ text-align: right;
+ background-color: #ffd0d0;
+}
+.column-entry-green {
+ text-align: right;
+ background-color: #d0ffd0;
+}
.line-number {
text-align: right;
color: #aaa;
@@ -284,16 +305,88 @@ void CoveragePrinterHTML::closeViewFile(OwnedStream OS) {
emitEpilog(*OS.get());
}
-Error CoveragePrinterHTML::createIndexFile(ArrayRef<StringRef> SourceFiles) {
+/// Emit column labels for the table in the index.
+static void emitColumnLabelsForIndex(raw_ostream &OS) {
+ SmallVector<std::string, 4> Columns;
+ for (const char *Label :
+ {"Filename", "Region Coverage", "Function Coverage", "Line Coverage"})
+ Columns.emplace_back(tag("td", Label, "column-entry"));
+ OS << tag("tr", join(Columns.begin(), Columns.end(), ""));
+}
+
+/// Render a file coverage summary (\p FCS) in a table row. If \p IsTotals is
+/// false, link the summary to \p SF.
+void CoveragePrinterHTML::emitFileSummary(raw_ostream &OS, StringRef SF,
+ const FileCoverageSummary &FCS,
+ bool IsTotals) const {
+ SmallVector<std::string, 4> Columns;
+
+ // Format a coverage triple and add the result to the list of columns.
+ auto AddCoverageTripleToColumn = [&Columns](unsigned Hit, unsigned Total,
+ float Pctg) {
+ std::string S;
+ {
+ raw_string_ostream RSO{S};
+ RSO << format("%*.2f", 7, Pctg) << "% (" << Hit << '/' << Total << ')';
+ }
+ const char *CellClass = "column-entry-yellow";
+ if (Pctg < 80.0)
+ CellClass = "column-entry-red";
+ else if (Hit == Total)
+ CellClass = "column-entry-green";
+ Columns.emplace_back(tag("td", tag("pre", S, "code"), CellClass));
+ };
+
+ // Simplify the display file path, and wrap it in a link if requested.
+ std::string Filename;
+ SmallString<128> LinkTextStr(sys::path::relative_path(FCS.Name));
+ sys::path::remove_dots(LinkTextStr, /*remove_dot_dots=*/true);
+ sys::path::native(LinkTextStr);
+ std::string LinkText = escape(LinkTextStr, Opts);
+ if (IsTotals) {
+ Filename = LinkText;
+ } else {
+ std::string LinkTarget =
+ escape(getOutputPath(SF, "html", /*InToplevel=*/false), Opts);
+ Filename = a(LinkTarget, LinkText);
+ }
+
+ Columns.emplace_back(tag("td", tag("pre", Filename, "code")));
+ AddCoverageTripleToColumn(
+ FCS.RegionCoverage.NumRegions - FCS.RegionCoverage.NotCovered,
+ FCS.RegionCoverage.NumRegions, FCS.RegionCoverage.getPercentCovered());
+ AddCoverageTripleToColumn(FCS.FunctionCoverage.Executed,
+ FCS.FunctionCoverage.NumFunctions,
+ FCS.FunctionCoverage.getPercentCovered());
+ AddCoverageTripleToColumn(
+ FCS.LineCoverage.NumLines - FCS.LineCoverage.NotCovered,
+ FCS.LineCoverage.NumLines, FCS.LineCoverage.getPercentCovered());
+
+ OS << tag("tr", join(Columns.begin(), Columns.end(), ""), "light-row");
+}
+
+Error CoveragePrinterHTML::createIndexFile(
+ ArrayRef<StringRef> SourceFiles,
+ const coverage::CoverageMapping &Coverage) {
+ // 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);
+
+ // Emit a file index along with some coverage statistics.
auto OSOrErr = createOutputStream("index", "html", /*InToplevel=*/true);
if (Error E = OSOrErr.takeError())
return E;
auto OS = std::move(OSOrErr.get());
raw_ostream &OSRef = *OS.get();
- // Emit a table containing links to reports for each file in the covmapping.
assert(Opts.hasOutputDirectory() && "No output directory for index file");
emitPrelude(OSRef, Opts, getPathToStyle(""));
+
+ // Emit some basic information about the coverage report.
if (Opts.hasProjectTitle())
OSRef << BeginProjectTitleDiv
<< tag("span", escape(Opts.ProjectTitle, Opts)) << EndProjectTitleDiv;
@@ -305,28 +398,19 @@ Error CoveragePrinterHTML::createIndexFile(ArrayRef<StringRef> SourceFiles) {
<< tag("span", escape(Opts.CreatedTimeStr, Opts))
<< EndCreatedTimeDiv;
OSRef << LineBreak;
+
+ // Emit a table containing links to reports for each file in the covmapping.
+ CoverageReport Report(Opts, Coverage);
OSRef << BeginCenteredDiv << BeginTable;
- OSRef << BeginSourceNameDiv << "Index" << EndSourceNameDiv;
- for (StringRef SF : SourceFiles) {
- SmallString<128> LinkTextStr(sys::path::relative_path(SF));
- sys::path::remove_dots(LinkTextStr, /*remove_dot_dots=*/true);
- sys::path::native(LinkTextStr);
- std::string LinkText = escape(sys::path::relative_path(LinkTextStr), Opts);
- std::string LinkTarget =
- escape(getOutputPath(SF, "html", /*InToplevel=*/false), Opts);
- OSRef << tag("tr", tag("td", tag("pre", a(LinkTarget, LinkText), "code")));
- }
+ emitColumnLabelsForIndex(OSRef);
+ FileCoverageSummary Totals("TOTALS");
+ auto FileReports = Report.prepareFileReports(Totals, SourceFiles);
+ for (unsigned I = 0, E = FileReports.size(); I < E; ++I)
+ emitFileSummary(OSRef, SourceFiles[I], FileReports[I]);
+ emitFileSummary(OSRef, "Totals", Totals, /*IsTotals=*/true);
OSRef << EndTable << EndCenteredDiv;
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();
}