mirror of
https://github.com/RPCS3/llvm.git
synced 2025-02-10 20:42:32 +00:00
[llvm-cov] Emit a summary in the report directory's index
llvm-cov writes out an index file in '-output-dir' mode, albeit not a very informative one. Try to fix that by using the CoverageReport API to include some basic summary information in the index file. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@281011 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
85e096da4e
commit
84dc7510c9
@ -35,9 +35,9 @@ int main() { // TEXT: [[@LINE]]| 161|int main(
|
||||
// RUN: FileCheck -check-prefixes=TEXT,WHOLE-FILE -input-file %t.dir/coverage/tmp/showLineExecutionCounts.cpp.txt %s
|
||||
// RUN: FileCheck -check-prefixes=TEXT,FILTER -input-file %t.dir/functions.txt %s
|
||||
//
|
||||
// Test index creation.
|
||||
// RUN: FileCheck -check-prefix=INDEX -input-file %t.dir/index.txt %s
|
||||
// INDEX: showLineExecutionCounts.cpp.txt
|
||||
// RUN: llvm-cov export %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -name=main 2>/dev/null > %t.export.json
|
||||
// RUN: FileCheck -input-file %t.export.json %S/Inputs/lineExecutionCounts.json
|
||||
// RUN: cat %t.export.json | %python -c "import json, sys; json.loads(sys.stdin.read())"
|
||||
//
|
||||
// Test html output.
|
||||
// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -format html -o %t.html.dir -instr-profile %t.profdata -filename-equivalence %s
|
||||
@ -69,7 +69,24 @@ int main() { // TEXT: [[@LINE]]| 161|int main(
|
||||
// HTML: <td class='line-number'><a name='L[[@LINE-44]]'><pre>[[@LINE-44]]</pre></a></td><td class='covered-line'><pre>161</pre></td><td class='code'><pre>}
|
||||
// HTML-WHOLE-FILE: <td class='line-number'><a name='L[[@LINE-44]]'><pre>[[@LINE-44]]</pre></a></td><td class='uncovered-line'></td><td class='code'><pre>// after
|
||||
// HTML-FILTER-NOT: <td class='line-number'><a name='L[[@LINE-45]]'><pre>[[@LINE-45]]</pre></a></td><td class='uncovered-line'></td><td class='code'><pre>// after
|
||||
|
||||
// RUN: llvm-cov export %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -name=main 2>/dev/null > %t.export.json
|
||||
// RUN: FileCheck -input-file %t.export.json %S/Inputs/lineExecutionCounts.json
|
||||
// RUN: cat %t.export.json | %python -c "import json, sys; json.loads(sys.stdin.read())"
|
||||
//
|
||||
// Test index creation.
|
||||
// RUN: FileCheck -check-prefix=TEXT-INDEX -input-file %t.dir/index.txt %s
|
||||
// TEXT-INDEX: Filename
|
||||
// TEXT-INDEX-NEXT: ---
|
||||
// TEXT-INDEX-NEXT: {{.*}}showLineExecutionCounts.cpp
|
||||
//
|
||||
// RUN: FileCheck -check-prefix HTML-INDEX -input-file %t.html.dir/index.html %s
|
||||
// HTML-INDEX-LABEL: <table>
|
||||
// HTML-INDEX: <td class='column-entry'>Filename</td>
|
||||
// HTML-INDEX: <td class='column-entry'>Region Coverage</td>
|
||||
// HTML-INDEX: <td class='column-entry'>Function Coverage</td>
|
||||
// HTML-INDEX: <td class='column-entry'>Line Coverage</td>
|
||||
// HTML-INDEX: <a href='coverage{{.*}}showLineExecutionCounts.cpp.html'{{.*}}showLineExecutionCounts.cpp</a>
|
||||
// HTML-INDEX: <td class='column-entry-red'>
|
||||
// HTML-INDEX: 70.00% (7/10)
|
||||
// HTML-INDEX: <td class='column-entry-green'>
|
||||
// HTML-INDEX: 100.00% (1/1)
|
||||
// HTML-INDEX: <td class='column-entry-yellow'>
|
||||
// HTML-INDEX: 80.00% (16/20)
|
||||
// HTML-INDEX: TOTALS
|
||||
|
@ -15,6 +15,11 @@ STYLE-DAG: .source-name-title
|
||||
STYLE-DAG: .centered
|
||||
STYLE-DAG: .expansion-view
|
||||
STYLE-DAG: .line-number
|
||||
STYLE-DAG: .light-row
|
||||
STYLE-DAG: .column-entry
|
||||
STYLE-DAG: .column-entry-yellow
|
||||
STYLE-DAG: .column-entry-red
|
||||
STYLE-DAG: .column-entry-green
|
||||
STYLE-DAG: .covered-line
|
||||
STYLE-DAG: .uncovered-line
|
||||
STYLE-DAG: .tooltip
|
||||
|
@ -679,7 +679,7 @@ int CodeCoverageTool::show(int argc, const char **argv,
|
||||
|
||||
// Create an index out of the source files.
|
||||
if (ViewOpts.hasOutputDirectory()) {
|
||||
if (Error E = Printer->createIndexFile(SourceFiles)) {
|
||||
if (Error E = Printer->createIndexFile(SourceFiles, *Coverage)) {
|
||||
error("Could not create index file!", toString(std::move(E)));
|
||||
return 1;
|
||||
}
|
||||
|
@ -142,7 +142,8 @@ public:
|
||||
virtual void closeViewFile(OwnedStream OS) = 0;
|
||||
|
||||
/// \brief Create an index which lists reports for the given source files.
|
||||
virtual Error createIndexFile(ArrayRef<StringRef> SourceFiles) = 0;
|
||||
virtual Error createIndexFile(ArrayRef<StringRef> SourceFiles,
|
||||
const coverage::CoverageMapping &Coverage) = 0;
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
|
||||
namespace llvm {
|
||||
|
||||
struct FileCoverageSummary;
|
||||
|
||||
/// \brief A coverage printer for html output.
|
||||
class CoveragePrinterHTML : public CoveragePrinter {
|
||||
public:
|
||||
@ -26,10 +28,16 @@ public:
|
||||
|
||||
void closeViewFile(OwnedStream OS) override;
|
||||
|
||||
Error createIndexFile(ArrayRef<StringRef> SourceFiles) override;
|
||||
Error createIndexFile(ArrayRef<StringRef> SourceFiles,
|
||||
const coverage::CoverageMapping &Coverage) override;
|
||||
|
||||
CoveragePrinterHTML(const CoverageViewOptions &Opts)
|
||||
: CoveragePrinter(Opts) {}
|
||||
|
||||
private:
|
||||
void emitFileSummary(raw_ostream &OS, StringRef SF,
|
||||
const FileCoverageSummary &FCS,
|
||||
bool IsTotals = false) const;
|
||||
};
|
||||
|
||||
/// \brief A code coverage view which supports html-based rendering.
|
||||
|
@ -11,6 +11,7 @@
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CoverageReport.h"
|
||||
#include "SourceCoverageViewText.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
@ -27,15 +28,17 @@ void CoveragePrinterText::closeViewFile(OwnedStream OS) {
|
||||
OS->operator<<('\n');
|
||||
}
|
||||
|
||||
Error CoveragePrinterText::createIndexFile(ArrayRef<StringRef> SourceFiles) {
|
||||
Error CoveragePrinterText::createIndexFile(
|
||||
ArrayRef<StringRef> SourceFiles,
|
||||
const coverage::CoverageMapping &Coverage) {
|
||||
auto OSOrErr = createOutputStream("index", "txt", /*InToplevel=*/true);
|
||||
if (Error E = OSOrErr.takeError())
|
||||
return E;
|
||||
auto OS = std::move(OSOrErr.get());
|
||||
raw_ostream &OSRef = *OS.get();
|
||||
|
||||
for (StringRef SF : SourceFiles)
|
||||
OSRef << getOutputPath(SF, "txt", /*InToplevel=*/false) << '\n';
|
||||
CoverageReport Report(Opts, Coverage);
|
||||
Report.renderFileReports(OSRef);
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
@ -26,7 +26,8 @@ public:
|
||||
|
||||
void closeViewFile(OwnedStream OS) override;
|
||||
|
||||
Error createIndexFile(ArrayRef<StringRef> SourceFiles) override;
|
||||
Error createIndexFile(ArrayRef<StringRef> SourceFiles,
|
||||
const coverage::CoverageMapping &Coverage) override;
|
||||
|
||||
CoveragePrinterText(const CoverageViewOptions &Opts)
|
||||
: CoveragePrinter(Opts) {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user