summaryrefslogtreecommitdiff
path: root/tools/llvm-cov/SourceCoverageViewHTML.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-12-18 20:10:56 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-12-18 20:10:56 +0000
commit044eb2f6afba375a914ac9d8024f8f5142bb912e (patch)
tree1475247dc9f9fe5be155ebd4c9069c75aadf8c20 /tools/llvm-cov/SourceCoverageViewHTML.cpp
parenteb70dddbd77e120e5d490bd8fbe7ff3f8fa81c6b (diff)
Notes
Diffstat (limited to 'tools/llvm-cov/SourceCoverageViewHTML.cpp')
-rw-r--r--tools/llvm-cov/SourceCoverageViewHTML.cpp158
1 files changed, 97 insertions, 61 deletions
diff --git a/tools/llvm-cov/SourceCoverageViewHTML.cpp b/tools/llvm-cov/SourceCoverageViewHTML.cpp
index 64b888e89d79..e45c6f4cb473 100644
--- a/tools/llvm-cov/SourceCoverageViewHTML.cpp
+++ b/tools/llvm-cov/SourceCoverageViewHTML.cpp
@@ -16,7 +16,6 @@
#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"
@@ -285,15 +284,31 @@ void CoveragePrinterHTML::closeViewFile(OwnedStream OS) {
}
/// Emit column labels for the table in the index.
-static void emitColumnLabelsForIndex(raw_ostream &OS) {
+static void emitColumnLabelsForIndex(raw_ostream &OS,
+ const CoverageViewOptions &Opts) {
SmallVector<std::string, 4> Columns;
Columns.emplace_back(tag("td", "Filename", "column-entry-left"));
- for (const char *Label : {"Function Coverage", "Instantiation Coverage",
- "Line Coverage", "Region Coverage"})
- Columns.emplace_back(tag("td", Label, "column-entry"));
+ Columns.emplace_back(tag("td", "Function Coverage", "column-entry"));
+ if (Opts.ShowInstantiationSummary)
+ Columns.emplace_back(tag("td", "Instantiation Coverage", "column-entry"));
+ Columns.emplace_back(tag("td", "Line Coverage", "column-entry"));
+ if (Opts.ShowRegionSummary)
+ Columns.emplace_back(tag("td", "Region Coverage", "column-entry"));
OS << tag("tr", join(Columns.begin(), Columns.end(), ""));
}
+std::string
+CoveragePrinterHTML::buildLinkToFile(StringRef SF,
+ const FileCoverageSummary &FCS) const {
+ 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);
+ std::string LinkTarget =
+ escape(getOutputPath(SF, "html", /*InToplevel=*/false), Opts);
+ return a(LinkTarget, LinkText);
+}
+
/// 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,
@@ -326,34 +341,31 @@ void CoveragePrinterHTML::emitFileSummary(raw_ostream &OS, StringRef SF,
if (IsTotals) {
Filename = "TOTALS";
} else {
- 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);
- std::string LinkTarget =
- escape(getOutputPath(SF, "html", /*InToplevel=*/false), Opts);
- Filename = a(LinkTarget, LinkText);
+ Filename = buildLinkToFile(SF, FCS);
}
Columns.emplace_back(tag("td", tag("pre", Filename)));
- AddCoverageTripleToColumn(FCS.FunctionCoverage.Executed,
- FCS.FunctionCoverage.NumFunctions,
+ AddCoverageTripleToColumn(FCS.FunctionCoverage.getExecuted(),
+ FCS.FunctionCoverage.getNumFunctions(),
FCS.FunctionCoverage.getPercentCovered());
- AddCoverageTripleToColumn(FCS.InstantiationCoverage.Executed,
- FCS.InstantiationCoverage.NumFunctions,
- FCS.InstantiationCoverage.getPercentCovered());
- AddCoverageTripleToColumn(FCS.LineCoverage.Covered, FCS.LineCoverage.NumLines,
+ if (Opts.ShowInstantiationSummary)
+ AddCoverageTripleToColumn(FCS.InstantiationCoverage.getExecuted(),
+ FCS.InstantiationCoverage.getNumFunctions(),
+ FCS.InstantiationCoverage.getPercentCovered());
+ AddCoverageTripleToColumn(FCS.LineCoverage.getCovered(),
+ FCS.LineCoverage.getNumLines(),
FCS.LineCoverage.getPercentCovered());
- AddCoverageTripleToColumn(FCS.RegionCoverage.Covered,
- FCS.RegionCoverage.NumRegions,
- FCS.RegionCoverage.getPercentCovered());
+ if (Opts.ShowRegionSummary)
+ AddCoverageTripleToColumn(FCS.RegionCoverage.getCovered(),
+ FCS.RegionCoverage.getNumRegions(),
+ FCS.RegionCoverage.getPercentCovered());
OS << tag("tr", join(Columns.begin(), Columns.end(), ""), "light-row");
}
Error CoveragePrinterHTML::createIndexFile(
- ArrayRef<std::string> SourceFiles,
- const coverage::CoverageMapping &Coverage) {
+ ArrayRef<std::string> SourceFiles, const CoverageMapping &Coverage,
+ const CoverageFiltersMatchAll &Filters) {
// Emit the default stylesheet.
auto CSSOrErr = createOutputStream("style", "css", /*InToplevel=*/true);
if (Error E = CSSOrErr.takeError())
@@ -387,16 +399,39 @@ Error CoveragePrinterHTML::createIndexFile(
" for information about interpreting this report.");
// Emit a table containing links to reports for each file in the covmapping.
+ // Exclude files which don't contain any regions.
OSRef << BeginCenteredDiv << BeginTable;
- emitColumnLabelsForIndex(OSRef);
+ emitColumnLabelsForIndex(OSRef, Opts);
FileCoverageSummary Totals("TOTALS");
- auto FileReports =
- CoverageReport::prepareFileReports(Coverage, Totals, SourceFiles);
- for (unsigned I = 0, E = FileReports.size(); I < E; ++I)
- emitFileSummary(OSRef, SourceFiles[I], FileReports[I]);
+ auto FileReports = CoverageReport::prepareFileReports(
+ Coverage, Totals, SourceFiles, Opts, Filters);
+ bool EmptyFiles = false;
+ for (unsigned I = 0, E = FileReports.size(); I < E; ++I) {
+ if (FileReports[I].FunctionCoverage.getNumFunctions())
+ emitFileSummary(OSRef, SourceFiles[I], FileReports[I]);
+ else
+ EmptyFiles = true;
+ }
emitFileSummary(OSRef, "Totals", Totals, /*IsTotals=*/true);
- OSRef << EndTable << EndCenteredDiv
- << tag("h5", escape(Opts.getLLVMVersionString(), Opts));
+ OSRef << EndTable << EndCenteredDiv;
+
+ // Emit links to files which don't contain any functions. These are normally
+ // not very useful, but could be relevant for code which abuses the
+ // preprocessor.
+ if (EmptyFiles && Filters.empty()) {
+ OSRef << tag("p", "Files which contain no functions. (These "
+ "files contain code pulled into other files "
+ "by the preprocessor.)\n");
+ OSRef << BeginCenteredDiv << BeginTable;
+ for (unsigned I = 0, E = FileReports.size(); I < E; ++I)
+ if (!FileReports[I].FunctionCoverage.getNumFunctions()) {
+ std::string Link = buildLinkToFile(SourceFiles[I], FileReports[I]);
+ OSRef << tag("tr", tag("td", tag("pre", Link)), "light-row") << '\n';
+ }
+ OSRef << EndTable << EndCenteredDiv;
+ }
+
+ OSRef << tag("h5", escape(Opts.getLLVMVersionString(), Opts));
emitEpilog(OSRef);
return Error::success();
@@ -431,9 +466,9 @@ void SourceCoverageViewHTML::renderViewDivider(raw_ostream &, unsigned) {
// The table-based output makes view dividers unnecessary.
}
-void SourceCoverageViewHTML::renderLine(
- raw_ostream &OS, LineRef L, const coverage::CoverageSegment *WrappedSegment,
- CoverageSegmentArray Segments, unsigned ExpansionCol, unsigned) {
+void SourceCoverageViewHTML::renderLine(raw_ostream &OS, LineRef L,
+ const LineCoverageStats &LCS,
+ unsigned ExpansionCol, unsigned) {
StringRef Line = L.Line;
unsigned LineNo = L.LineNo;
@@ -445,6 +480,7 @@ void SourceCoverageViewHTML::renderLine(
// at the end of the line. Both are required but may be empty.
SmallVector<std::string, 8> Snippets;
+ CoverageSegmentArray Segments = LCS.getLineSegments();
unsigned LCol = 1;
auto Snip = [&](unsigned Start, unsigned Len) {
@@ -469,7 +505,7 @@ void SourceCoverageViewHTML::renderLine(
// 1 to set the highlight for snippet 2, segment 2 to set the highlight for
// snippet 3, and so on.
- Optional<std::string> Color;
+ Optional<StringRef> Color;
SmallVector<std::pair<unsigned, unsigned>, 2> HighlightedRanges;
auto Highlight = [&](const std::string &Snippet, unsigned LC, unsigned RC) {
if (getOptions().Debug)
@@ -477,11 +513,12 @@ void SourceCoverageViewHTML::renderLine(
return tag("span", Snippet, Color.getValue());
};
- auto CheckIfUncovered = [](const coverage::CoverageSegment *S) {
- return S && S->HasCount && S->Count == 0;
+ auto CheckIfUncovered = [&](const CoverageSegment *S) {
+ return S && (!S->IsGapRegion || (Color && *Color == "red")) &&
+ S->HasCount && S->Count == 0;
};
- if (CheckIfUncovered(WrappedSegment)) {
+ if (CheckIfUncovered(LCS.getWrappedSegment())) {
Color = "red";
if (!Snippets[0].empty())
Snippets[0] = Highlight(Snippets[0], 1, 1 + Snippets[0].size());
@@ -489,10 +526,10 @@ void SourceCoverageViewHTML::renderLine(
for (unsigned I = 0, E = Segments.size(); I < E; ++I) {
const auto *CurSeg = Segments[I];
- if (CurSeg->Col == ExpansionCol)
- Color = "cyan";
- else if (CheckIfUncovered(CurSeg))
+ if (CheckIfUncovered(CurSeg))
Color = "red";
+ else if (CurSeg->Col == ExpansionCol)
+ Color = "cyan";
else
Color = None;
@@ -518,25 +555,23 @@ void SourceCoverageViewHTML::renderLine(
// 4. Snippets[1:N+1] correspond to \p Segments[0:N]: use these to generate
// sub-line region count tooltips if needed.
- bool HasMultipleRegions = [&] {
- unsigned RegionCount = 0;
- for (const auto *S : Segments)
- if (S->HasCount && S->IsRegionEntry)
- if (++RegionCount > 1)
- return true;
- return false;
- }();
-
- if (shouldRenderRegionMarkers(HasMultipleRegions)) {
- for (unsigned I = 0, E = Segments.size(); I < E; ++I) {
+ if (shouldRenderRegionMarkers(LCS)) {
+ // Just consider the segments which start *and* end on this line.
+ for (unsigned I = 0, E = Segments.size() - 1; I < E; ++I) {
const auto *CurSeg = Segments[I];
- if (!CurSeg->IsRegionEntry || !CurSeg->HasCount)
+ if (!CurSeg->IsRegionEntry)
+ continue;
+ if (CurSeg->Count == LCS.getExecutionCount())
continue;
Snippets[I + 1] =
tag("div", Snippets[I + 1] + tag("span", formatCount(CurSeg->Count),
"tooltip-content"),
"tooltip");
+
+ if (getOptions().Debug)
+ errs() << "Marker at " << CurSeg->Line << ":" << CurSeg->Col << " = "
+ << formatCount(CurSeg->Count) << "\n";
}
}
@@ -556,9 +591,9 @@ void SourceCoverageViewHTML::renderLineCoverageColumn(
raw_ostream &OS, const LineCoverageStats &Line) {
std::string Count = "";
if (Line.isMapped())
- Count = tag("pre", formatCount(Line.ExecutionCount));
+ Count = tag("pre", formatCount(Line.getExecutionCount()));
std::string CoverageClass =
- (Line.ExecutionCount > 0) ? "covered-line" : "uncovered-line";
+ (Line.getExecutionCount() > 0) ? "covered-line" : "uncovered-line";
OS << tag("td", Count, CoverageClass);
}
@@ -571,16 +606,17 @@ void SourceCoverageViewHTML::renderLineNumberColumn(raw_ostream &OS,
}
void SourceCoverageViewHTML::renderRegionMarkers(raw_ostream &,
- CoverageSegmentArray,
+ const LineCoverageStats &Line,
unsigned) {
// Region markers are rendered in-line using tooltips.
}
-void SourceCoverageViewHTML::renderExpansionSite(
- raw_ostream &OS, LineRef L, const coverage::CoverageSegment *WrappedSegment,
- CoverageSegmentArray Segments, unsigned ExpansionCol, unsigned ViewDepth) {
+void SourceCoverageViewHTML::renderExpansionSite(raw_ostream &OS, LineRef L,
+ const LineCoverageStats &LCS,
+ unsigned ExpansionCol,
+ unsigned ViewDepth) {
// Render the line containing the expansion site. No extra formatting needed.
- renderLine(OS, L, WrappedSegment, Segments, ExpansionCol, ViewDepth);
+ renderLine(OS, L, LCS, ExpansionCol, ViewDepth);
}
void SourceCoverageViewHTML::renderExpansionView(raw_ostream &OS,
@@ -588,7 +624,7 @@ void SourceCoverageViewHTML::renderExpansionView(raw_ostream &OS,
unsigned ViewDepth) {
OS << BeginExpansionDiv;
ESV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/false,
- ViewDepth + 1);
+ /*ShowTitle=*/false, ViewDepth + 1);
OS << EndExpansionDiv;
}
@@ -604,7 +640,7 @@ void SourceCoverageViewHTML::renderInstantiationView(raw_ostream &OS,
<< EndSourceNameDiv;
else
ISV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/true,
- ViewDepth);
+ /*ShowTitle=*/false, ViewDepth);
OS << EndExpansionDiv;
}