Index: test/tools/llvm-cov/Inputs/showProjectSummary.test =================================================================== --- test/tools/llvm-cov/Inputs/showProjectSummary.test +++ test/tools/llvm-cov/Inputs/showProjectSummary.test @@ -8,6 +8,10 @@ HTML-TITLE:

Test Suite

HTML:

Coverage Report

HTML:

Created:{{.*}}

+HTML-TOTAL: Function Coverage: +HTML-TOTAL: Instantiation Coverage: +HTML-TOTAL: Line Coverage: +HTML-TOTAL: Region Coverage: HTML-FILE:
{{.*}}showProjectSummary.cpp (Binary: showProjectSummary.covmapping)
HTML-FUNCTION:
main
HTML-HEADER:
Line
Index: test/tools/llvm-cov/showProjectSummary.cpp =================================================================== --- test/tools/llvm-cov/showProjectSummary.cpp +++ test/tools/llvm-cov/showProjectSummary.cpp @@ -23,6 +23,6 @@ // RUN: FileCheck -check-prefixes=HTML,HTML-FILE,HTML-HEADER -input-file %t.dir/coverage/tmp/showProjectSummary.cpp.html %S/Inputs/showProjectSummary.test // RUN: llvm-cov show %S/Inputs/showProjectSummary.covmapping -format=html -o %t.dir -instr-profile %t.profdata -project-title "Test Suite" -filename-equivalence %s // RUN: FileCheck -check-prefixes=HTML-TITLE,HTML,HTML-FILE,HTML-HEADER -input-file %t.dir/coverage/tmp/showProjectSummary.cpp.html %S/Inputs/showProjectSummary.test -// RUN: FileCheck -check-prefixes=HTML-TITLE,HTML,HTML-FOOTER -input-file %t.dir/index.html %S/Inputs/showProjectSummary.test +// RUN: FileCheck -check-prefixes=HTML-TITLE,HTML,HTML-TOTAL,HTML-FOOTER -input-file %t.dir/index.html %S/Inputs/showProjectSummary.test // RUN: llvm-cov show %S/Inputs/showProjectSummary.covmapping -format=html -o %t.dir -instr-profile %t.profdata -project-title "Test Suite" -filename-equivalence -name=main %s // RUN: FileCheck -check-prefixes=HTML-FUNCTION,HTML-HEADER -input-file %t.dir/functions.html %S/Inputs/showProjectSummary.test Index: tools/llvm-cov/SourceCoverageViewHTML.h =================================================================== --- tools/llvm-cov/SourceCoverageViewHTML.h +++ tools/llvm-cov/SourceCoverageViewHTML.h @@ -38,6 +38,9 @@ void emitFileSummary(raw_ostream &OS, StringRef SF, const FileCoverageSummary &FCS, bool IsTotals = false) const; + + void emitProjectSummary(raw_ostream &OS, + const FileCoverageSummary &PCS) const; }; /// \brief A code coverage view which supports html-based rendering. Index: tools/llvm-cov/SourceCoverageViewHTML.cpp =================================================================== --- tools/llvm-cov/SourceCoverageViewHTML.cpp +++ tools/llvm-cov/SourceCoverageViewHTML.cpp @@ -293,6 +293,19 @@ OS << tag("tr", join(Columns.begin(), Columns.end(), "")); } +/// Get the HTML for a coverage triple. +static std::string getCoverageTriple(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"; + return tag("td", tag("pre", RSO.str()), CellClass); +} + /// 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, @@ -300,22 +313,6 @@ bool IsTotals) const { SmallVector 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), 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)); @@ -331,21 +328,63 @@ } Columns.emplace_back(tag("td", tag("pre", Filename))); - AddCoverageTripleToColumn(FCS.FunctionCoverage.Executed, - FCS.FunctionCoverage.NumFunctions, - FCS.FunctionCoverage.getPercentCovered()); - AddCoverageTripleToColumn(FCS.InstantiationCoverage.Executed, - FCS.InstantiationCoverage.NumFunctions, - FCS.InstantiationCoverage.getPercentCovered()); - AddCoverageTripleToColumn(FCS.LineCoverage.Covered, FCS.LineCoverage.NumLines, - FCS.LineCoverage.getPercentCovered()); - AddCoverageTripleToColumn(FCS.RegionCoverage.Covered, - FCS.RegionCoverage.NumRegions, - FCS.RegionCoverage.getPercentCovered()); - + Columns.emplace_back(getCoverageTriple( + FCS.FunctionCoverage.Executed, FCS.FunctionCoverage.NumFunctions, + FCS.FunctionCoverage.getPercentCovered())); + Columns.emplace_back( + getCoverageTriple(FCS.InstantiationCoverage.Executed, + FCS.InstantiationCoverage.NumFunctions, + FCS.InstantiationCoverage.getPercentCovered())); + Columns.emplace_back(getCoverageTriple( + FCS.LineCoverage.NumLines - FCS.LineCoverage.NotCovered, + FCS.LineCoverage.NumLines, FCS.LineCoverage.getPercentCovered())); + Columns.emplace_back(getCoverageTriple( + FCS.RegionCoverage.NumRegions - FCS.RegionCoverage.NotCovered, + FCS.RegionCoverage.NumRegions, FCS.RegionCoverage.getPercentCovered())); OS << tag("tr", join(Columns.begin(), Columns.end(), ""), "light-row"); } +/// Render the project coverage summary (\p PCS) and the project directory (\p +/// ProjectDir) above the index table. +void CoveragePrinterHTML::emitProjectSummary( + raw_ostream &OS, const FileCoverageSummary &PCS) const { + + OS << "" + << ""; + + // Add a coverage row to the coverage summary table. + auto AddCoverageSummaryRow = [&OS](StringRef CoverageTitle, + StringRef CoverageValue) { + OS << tag("tr", + tag("td", CoverageTitle, "column-entry") + CoverageValue.str()); + }; + + AddCoverageSummaryRow( + "Function Coverage:", + getCoverageTriple(PCS.FunctionCoverage.Executed, + PCS.FunctionCoverage.NumFunctions, + PCS.FunctionCoverage.getPercentCovered())); + AddCoverageSummaryRow( + "Instantiation Coverage:", + getCoverageTriple(PCS.InstantiationCoverage.Executed, + PCS.InstantiationCoverage.NumFunctions, + PCS.InstantiationCoverage.getPercentCovered())); + AddCoverageSummaryRow( + "Line Coverage:", + getCoverageTriple(PCS.LineCoverage.NumLines - PCS.LineCoverage.NotCovered, + PCS.LineCoverage.NumLines, + PCS.LineCoverage.getPercentCovered())); + AddCoverageSummaryRow( + "Region Coverage:", + getCoverageTriple(PCS.RegionCoverage.NumRegions - + PCS.RegionCoverage.NotCovered, + PCS.RegionCoverage.NumRegions, + PCS.RegionCoverage.getPercentCovered())); + + OS << "" + << "
" << "
"; +} + Error CoveragePrinterHTML::createIndexFile( ArrayRef SourceFiles, const coverage::CoverageMapping &Coverage) { @@ -381,12 +420,15 @@ "here") + " for information about interpreting this report."); - // Emit a table containing links to reports for each file in the covmapping. - OSRef << BeginCenteredDiv << BeginTable; - emitColumnLabelsForIndex(OSRef); + // Emit a table containing the project coverage summary. FileCoverageSummary Totals("TOTALS"); auto FileReports = CoverageReport::prepareFileReports(Coverage, Totals, SourceFiles); + emitProjectSummary(OSRef, Totals); + + // Emit a table containing links to reports for each file in the covmapping. + OSRef << BeginCenteredDiv << BeginTable; + emitColumnLabelsForIndex(OSRef); for (unsigned I = 0, E = FileReports.size(); I < E; ++I) emitFileSummary(OSRef, SourceFiles[I], FileReports[I]); emitFileSummary(OSRef, "Totals", Totals, /*IsTotals=*/true);