aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools
diff options
context:
space:
mode:
authorAlan Phipps <a-phipps@ti.com>2020-12-28 11:20:48 -0600
committerAlan Phipps <a-phipps@ti.com>2021-01-05 09:51:51 -0600
commit9f2967bcfe2f7d1fc02281f0098306c90c2c10a5 (patch)
treea29793dac7b81d67601905911a389a2cf2cdde2e /llvm/tools
parent53c3acb89fcc25ba7ef1f1d76a79c241eeacb7f0 (diff)
downloadllvm-9f2967bcfe2f7d1fc02281f0098306c90c2c10a5.zip
llvm-9f2967bcfe2f7d1fc02281f0098306c90c2c10a5.tar.gz
llvm-9f2967bcfe2f7d1fc02281f0098306c90c2c10a5.tar.bz2
[Coverage] Add support for Branch Coverage in LLVM Source-Based Code Coverage
This is an enhancement to LLVM Source-Based Code Coverage in clang to track how many times individual branch-generating conditions are taken (evaluate to TRUE) and not taken (evaluate to FALSE). Individual conditions may comprise larger boolean expressions using boolean logical operators. This functionality is very similar to what is supported by GCOV except that it is very closely anchored to the ASTs. Differential Revision: https://reviews.llvm.org/D84467
Diffstat (limited to 'llvm/tools')
-rw-r--r--llvm/tools/llvm-cov/CodeCoverage.cpp64
-rw-r--r--llvm/tools/llvm-cov/CoverageExporterJson.cpp81
-rw-r--r--llvm/tools/llvm-cov/CoverageExporterLcov.cpp97
-rw-r--r--llvm/tools/llvm-cov/CoverageReport.cpp49
-rw-r--r--llvm/tools/llvm-cov/CoverageSummaryInfo.cpp42
-rw-r--r--llvm/tools/llvm-cov/CoverageSummaryInfo.h49
-rw-r--r--llvm/tools/llvm-cov/CoverageViewOptions.h6
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageView.cpp23
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageView.h28
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp72
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageViewHTML.h3
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageViewText.cpp50
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageViewText.h3
13 files changed, 548 insertions, 19 deletions
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index a453e97..baa9688 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -88,6 +88,12 @@ private:
ArrayRef<ExpansionRecord> Expansions,
const CoverageMapping &Coverage);
+ /// Create source views for the branches of the view.
+ void attachBranchSubViews(SourceCoverageView &View, StringRef SourceName,
+ ArrayRef<CountedRegion> Branches,
+ const MemoryBuffer &File,
+ CoverageData &CoverageInfo);
+
/// Create the source view of a particular function.
std::unique_ptr<SourceCoverageView>
createFunctionView(const FunctionRecord &Function,
@@ -268,15 +274,45 @@ void CodeCoverageTool::attachExpansionSubViews(
if (!SourceBuffer)
continue;
+ auto SubViewBranches = ExpansionCoverage.getBranches();
auto SubViewExpansions = ExpansionCoverage.getExpansions();
auto SubView =
SourceCoverageView::create(Expansion.Function.Name, SourceBuffer.get(),
ViewOpts, std::move(ExpansionCoverage));
attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
+ attachBranchSubViews(*SubView, Expansion.Function.Name, SubViewBranches,
+ SourceBuffer.get(), ExpansionCoverage);
View.addExpansion(Expansion.Region, std::move(SubView));
}
}
+void CodeCoverageTool::attachBranchSubViews(SourceCoverageView &View,
+ StringRef SourceName,
+ ArrayRef<CountedRegion> Branches,
+ const MemoryBuffer &File,
+ CoverageData &CoverageInfo) {
+ if (!ViewOpts.ShowBranchCounts && !ViewOpts.ShowBranchPercents)
+ return;
+
+ const auto *NextBranch = Branches.begin();
+ const auto *EndBranch = Branches.end();
+
+ // Group branches that have the same line number into the same subview.
+ while (NextBranch != EndBranch) {
+ std::vector<CountedRegion> ViewBranches;
+ unsigned CurrentLine = NextBranch->LineStart;
+
+ while (NextBranch != EndBranch && CurrentLine == NextBranch->LineStart)
+ ViewBranches.push_back(*NextBranch++);
+
+ if (!ViewBranches.empty()) {
+ auto SubView = SourceCoverageView::create(SourceName, File, ViewOpts,
+ std::move(CoverageInfo));
+ View.addBranch(CurrentLine, ViewBranches, std::move(SubView));
+ }
+ }
+}
+
std::unique_ptr<SourceCoverageView>
CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
const CoverageMapping &Coverage) {
@@ -287,11 +323,14 @@ CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
if (!SourceBuffer)
return nullptr;
+ auto Branches = FunctionCoverage.getBranches();
auto Expansions = FunctionCoverage.getExpansions();
auto View = SourceCoverageView::create(DC.demangle(Function.Name),
SourceBuffer.get(), ViewOpts,
std::move(FunctionCoverage));
attachExpansionSubViews(*View, Expansions, Coverage);
+ attachBranchSubViews(*View, DC.demangle(Function.Name), Branches,
+ SourceBuffer.get(), FunctionCoverage);
return View;
}
@@ -306,10 +345,13 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile,
if (FileCoverage.empty())
return nullptr;
+ auto Branches = FileCoverage.getBranches();
auto Expansions = FileCoverage.getExpansions();
auto View = SourceCoverageView::create(SourceFile, SourceBuffer.get(),
ViewOpts, std::move(FileCoverage));
attachExpansionSubViews(*View, Expansions, Coverage);
+ attachBranchSubViews(*View, SourceFile, Branches, SourceBuffer.get(),
+ FileCoverage);
if (!ViewOpts.ShowFunctionInstantiations)
return View;
@@ -326,9 +368,12 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile,
if (Function->ExecutionCount > 0) {
auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
auto SubViewExpansions = SubViewCoverage.getExpansions();
+ auto SubViewBranches = SubViewCoverage.getBranches();
SubView = SourceCoverageView::create(
Funcname, SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
+ attachBranchSubViews(*SubView, SourceFile, SubViewBranches,
+ SourceBuffer.get(), SubViewCoverage);
}
unsigned FileID = Function->CountedRegions.front().FileID;
@@ -645,6 +690,11 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
cl::desc("Show region statistics in summary table"),
cl::init(true));
+ cl::opt<bool> BranchSummary(
+ "show-branch-summary", cl::Optional,
+ cl::desc("Show branch condition statistics in summary table"),
+ cl::init(true));
+
cl::opt<bool> InstantiationSummary(
"show-instantiation-summary", cl::Optional,
cl::desc("Show instantiation statistics in summary table"));
@@ -788,6 +838,7 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
::exit(0);
}
+ ViewOpts.ShowBranchSummary = BranchSummary;
ViewOpts.ShowRegionSummary = RegionSummary;
ViewOpts.ShowInstantiationSummary = InstantiationSummary;
ViewOpts.ExportSummaryOnly = SummaryOnly;
@@ -822,6 +873,15 @@ int CodeCoverageTool::doShow(int argc, const char **argv,
cl::desc("Show the execution counts for each region"),
cl::cat(ViewCategory));
+ cl::opt<CoverageViewOptions::BranchOutputType> ShowBranches(
+ "show-branches", cl::Optional,
+ cl::desc("Show coverage for branch conditions"), cl::cat(ViewCategory),
+ cl::values(clEnumValN(CoverageViewOptions::BranchOutputType::Count,
+ "count", "Show True/False counts"),
+ clEnumValN(CoverageViewOptions::BranchOutputType::Percent,
+ "percent", "Show True/False percent")),
+ cl::init(CoverageViewOptions::BranchOutputType::Off));
+
cl::opt<bool> ShowBestLineRegionsCounts(
"show-line-counts-or-regions", cl::Optional,
cl::desc("Show the execution counts for each line, or the execution "
@@ -865,6 +925,10 @@ int CodeCoverageTool::doShow(int argc, const char **argv,
!ShowRegions || ShowBestLineRegionsCounts;
ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts;
ViewOpts.ShowExpandedRegions = ShowExpansions;
+ ViewOpts.ShowBranchCounts =
+ ShowBranches == CoverageViewOptions::BranchOutputType::Count;
+ ViewOpts.ShowBranchPercents =
+ ShowBranches == CoverageViewOptions::BranchOutputType::Percent;
ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
ViewOpts.ShowOutputDirectory = ShowOutputDirectory;
ViewOpts.TabSize = TabSize;
diff --git a/llvm/tools/llvm-cov/CoverageExporterJson.cpp b/llvm/tools/llvm-cov/CoverageExporterJson.cpp
index c8bb1aa..0a47dd2 100644
--- a/llvm/tools/llvm-cov/CoverageExporterJson.cpp
+++ b/llvm/tools/llvm-cov/CoverageExporterJson.cpp
@@ -18,6 +18,8 @@
// -- Export: dict => Json representation of one CoverageMapping
// -- Files: array => List of objects describing coverage for files
// -- File: dict => Coverage for a single file
+// -- Branches: array => List of Branches in the file
+// -- Branch: dict => Describes a branch of the file with counters
// -- Segments: array => List of Segments contained in the file
// -- Segment: dict => Describes a segment of the file with a counter
// -- Expansions: array => List of expansion records
@@ -25,10 +27,13 @@
// -- CountedRegion: dict => The region to be expanded
// -- TargetRegions: array => List of Regions in the expansion
// -- CountedRegion: dict => Single Region in the expansion
+// -- Branches: array => List of Branches in the expansion
+// -- Branch: dict => Describes a branch in expansion and counters
// -- Summary: dict => Object summarizing the coverage for this file
// -- LineCoverage: dict => Object summarizing line coverage
// -- FunctionCoverage: dict => Object summarizing function coverage
// -- RegionCoverage: dict => Object summarizing region coverage
+// -- BranchCoverage: dict => Object summarizing branch coverage
// -- Functions: array => List of objects describing coverage for functions
// -- Function: dict => Coverage info for a single function
// -- Filenames: array => List of filenames that the function relates to
@@ -37,6 +42,7 @@
// -- FunctionCoverage: dict => Object summarizing function coverage
// -- InstantiationCoverage: dict => Object summarizing inst. coverage
// -- RegionCoverage: dict => Object summarizing region coverage
+// -- BranchCoverage: dict => Object summarizing branch coverage
//
//===----------------------------------------------------------------------===//
@@ -84,6 +90,14 @@ json::Array renderRegion(const coverage::CountedRegion &Region) {
int64_t(Region.Kind)});
}
+json::Array renderBranch(const coverage::CountedRegion &Region) {
+ return json::Array(
+ {Region.LineStart, Region.ColumnStart, Region.LineEnd, Region.ColumnEnd,
+ clamp_uint64_to_int64(Region.ExecutionCount),
+ clamp_uint64_to_int64(Region.FalseExecutionCount), Region.FileID,
+ Region.ExpandedFileID, int64_t(Region.Kind)});
+}
+
json::Array renderRegions(ArrayRef<coverage::CountedRegion> Regions) {
json::Array RegionArray;
for (const auto &Region : Regions)
@@ -91,13 +105,49 @@ json::Array renderRegions(ArrayRef<coverage::CountedRegion> Regions) {
return RegionArray;
}
-json::Object renderExpansion(const coverage::ExpansionRecord &Expansion) {
+json::Array renderBranchRegions(ArrayRef<coverage::CountedRegion> Regions) {
+ json::Array RegionArray;
+ for (const auto &Region : Regions)
+ if (!Region.Folded)
+ RegionArray.push_back(renderBranch(Region));
+ return RegionArray;
+}
+
+std::vector<llvm::coverage::CountedRegion>
+collectNestedBranches(const coverage::CoverageMapping &Coverage,
+ ArrayRef<llvm::coverage::ExpansionRecord> Expansions) {
+ std::vector<llvm::coverage::CountedRegion> Branches;
+ for (const auto &Expansion : Expansions) {
+ auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion);
+
+ // Recursively collect branches from nested expansions.
+ auto NestedExpansions = ExpansionCoverage.getExpansions();
+ auto NestedExBranches = collectNestedBranches(Coverage, NestedExpansions);
+ Branches.insert(Branches.end(), NestedExBranches.begin(),
+ NestedExBranches.end());
+
+ // Add branches from this level of expansion.
+ auto ExBranches = ExpansionCoverage.getBranches();
+ for (auto B : ExBranches)
+ if (B.FileID == Expansion.FileID)
+ Branches.push_back(B);
+ }
+
+ return Branches;
+}
+
+json::Object renderExpansion(const coverage::CoverageMapping &Coverage,
+ const coverage::ExpansionRecord &Expansion) {
+ std::vector<llvm::coverage::ExpansionRecord> Expansions = {Expansion};
return json::Object(
{{"filenames", json::Array(Expansion.Function.Filenames)},
// Mark the beginning and end of this expansion in the source file.
{"source_region", renderRegion(Expansion.Region)},
// Enumerate the coverage information for the expansion.
- {"target_regions", renderRegions(Expansion.Function.CountedRegions)}});
+ {"target_regions", renderRegions(Expansion.Function.CountedRegions)},
+ // Enumerate the branch coverage information for the expansion.
+ {"branches",
+ renderBranchRegions(collectNestedBranches(Coverage, Expansions))}});
}
json::Object renderSummary(const FileCoverageSummary &Summary) {
@@ -123,14 +173,22 @@ json::Object renderSummary(const FileCoverageSummary &Summary) {
{"covered", int64_t(Summary.RegionCoverage.getCovered())},
{"notcovered", int64_t(Summary.RegionCoverage.getNumRegions() -
Summary.RegionCoverage.getCovered())},
- {"percent", Summary.RegionCoverage.getPercentCovered()}})}});
+ {"percent", Summary.RegionCoverage.getPercentCovered()}})},
+ {"branches",
+ json::Object(
+ {{"count", int64_t(Summary.BranchCoverage.getNumBranches())},
+ {"covered", int64_t(Summary.BranchCoverage.getCovered())},
+ {"notcovered", int64_t(Summary.BranchCoverage.getNumBranches() -
+ Summary.BranchCoverage.getCovered())},
+ {"percent", Summary.BranchCoverage.getPercentCovered()}})}});
}
-json::Array renderFileExpansions(const coverage::CoverageData &FileCoverage,
+json::Array renderFileExpansions(const coverage::CoverageMapping &Coverage,
+ const coverage::CoverageData &FileCoverage,
const FileCoverageSummary &FileReport) {
json::Array ExpansionArray;
for (const auto &Expansion : FileCoverage.getExpansions())
- ExpansionArray.push_back(renderExpansion(Expansion));
+ ExpansionArray.push_back(renderExpansion(Coverage, Expansion));
return ExpansionArray;
}
@@ -142,6 +200,14 @@ json::Array renderFileSegments(const coverage::CoverageData &FileCoverage,
return SegmentArray;
}
+json::Array renderFileBranches(const coverage::CoverageData &FileCoverage,
+ const FileCoverageSummary &FileReport) {
+ json::Array BranchArray;
+ for (const auto &Branch : FileCoverage.getBranches())
+ BranchArray.push_back(renderBranch(Branch));
+ return BranchArray;
+}
+
json::Object renderFile(const coverage::CoverageMapping &Coverage,
const std::string &Filename,
const FileCoverageSummary &FileReport,
@@ -151,8 +217,10 @@ json::Object renderFile(const coverage::CoverageMapping &Coverage,
// Calculate and render detailed coverage information for given file.
auto FileCoverage = Coverage.getCoverageForFile(Filename);
File["segments"] = renderFileSegments(FileCoverage, FileReport);
+ File["branches"] = renderFileBranches(FileCoverage, FileReport);
if (!Options.SkipExpansions) {
- File["expansions"] = renderFileExpansions(FileCoverage, FileReport);
+ File["expansions"] =
+ renderFileExpansions(Coverage, FileCoverage, FileReport);
}
}
File["summary"] = renderSummary(FileReport);
@@ -197,6 +265,7 @@ json::Array renderFunctions(
json::Object({{"name", F.Name},
{"count", clamp_uint64_to_int64(F.ExecutionCount)},
{"regions", renderRegions(F.CountedRegions)},
+ {"branches", renderBranchRegions(F.CountedBranchRegions)},
{"filenames", json::Array(F.Filenames)}}));
return FunctionArray;
}
diff --git a/llvm/tools/llvm-cov/CoverageExporterLcov.cpp b/llvm/tools/llvm-cov/CoverageExporterLcov.cpp
index 46c6b49..08115e0 100644
--- a/llvm/tools/llvm-cov/CoverageExporterLcov.cpp
+++ b/llvm/tools/llvm-cov/CoverageExporterLcov.cpp
@@ -26,6 +26,10 @@
// - "FNH:<number of functions hit>"
// - for each instrumented line:
// - "DA:<line number>,<execution count>[,<checksum>]
+// - for each branch:
+// - "BRDA:<line number>,<branch pair id>,<branch id>,<count>"
+// - "BRF:<number of branches found>"
+// - "BRH:<number of branches hit>"
// - "LH:<number of lines with non-zero execution count>"
// - "LF:<number of instrumented lines>"
// - "end_of_record"
@@ -71,11 +75,102 @@ void renderLineExecutionCounts(raw_ostream &OS,
}
}
+std::vector<llvm::coverage::CountedRegion>
+collectNestedBranches(const coverage::CoverageMapping &Coverage,
+ ArrayRef<llvm::coverage::ExpansionRecord> Expansions,
+ int ViewDepth = 0, int SrcLine = 0) {
+ std::vector<llvm::coverage::CountedRegion> Branches;
+ for (const auto &Expansion : Expansions) {
+ auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion);
+
+ // If we're at the top level, set the corresponding source line.
+ if (ViewDepth == 0)
+ SrcLine = Expansion.Region.LineStart;
+
+ // Recursively collect branches from nested expansions.
+ auto NestedExpansions = ExpansionCoverage.getExpansions();
+ auto NestedExBranches = collectNestedBranches(Coverage, NestedExpansions,
+ ViewDepth + 1, SrcLine);
+ Branches.insert(Branches.end(), NestedExBranches.begin(),
+ NestedExBranches.end());
+
+ // Add branches from this level of expansion.
+ auto ExBranches = ExpansionCoverage.getBranches();
+ for (auto B : ExBranches)
+ if (B.FileID == Expansion.FileID) {
+ B.LineStart = SrcLine;
+ Branches.push_back(B);
+ }
+ }
+
+ return Branches;
+}
+
+bool sortLine(llvm::coverage::CountedRegion I,
+ llvm::coverage::CountedRegion J) {
+ return (I.LineStart < J.LineStart) ||
+ ((I.LineStart == J.LineStart) && (I.ColumnStart < J.ColumnStart));
+}
+
+void renderBranchExecutionCounts(raw_ostream &OS,
+ const coverage::CoverageMapping &Coverage,
+ const coverage::CoverageData &FileCoverage) {
+ std::vector<llvm::coverage::CountedRegion> Branches =
+ FileCoverage.getBranches();
+
+ // Recursively collect branches for all file expansions.
+ std::vector<llvm::coverage::CountedRegion> ExBranches =
+ collectNestedBranches(Coverage, FileCoverage.getExpansions());
+
+ // Append Expansion Branches to Source Branches.
+ Branches.insert(Branches.end(), ExBranches.begin(), ExBranches.end());
+
+ // Sort branches based on line number to ensure branches corresponding to the
+ // same source line are counted together.
+ std::sort(Branches.begin(), Branches.end(), sortLine);
+
+ auto NextBranch = Branches.begin();
+ auto EndBranch = Branches.end();
+
+ // Branches with the same source line are enumerated individually
+ // (BranchIndex) as well as based on True/False pairs (PairIndex).
+ while (NextBranch != EndBranch) {
+ unsigned CurrentLine = NextBranch->LineStart;
+ unsigned PairIndex = 0;
+ unsigned BranchIndex = 0;
+
+ while (NextBranch != EndBranch && CurrentLine == NextBranch->LineStart) {
+ if (!NextBranch->Folded) {
+ unsigned BC1 = NextBranch->ExecutionCount;
+ unsigned BC2 = NextBranch->FalseExecutionCount;
+ bool BranchNotExecuted = (BC1 == 0 && BC2 == 0);
+
+ for (int I = 0; I < 2; I++, BranchIndex++) {
+ OS << "BRDA:" << CurrentLine << ',' << PairIndex << ','
+ << BranchIndex;
+ if (BranchNotExecuted)
+ OS << ',' << '-' << '\n';
+ else
+ OS << ',' << (I == 0 ? BC1 : BC2) << '\n';
+ }
+
+ PairIndex++;
+ }
+ NextBranch++;
+ }
+ }
+}
+
void renderLineSummary(raw_ostream &OS, const FileCoverageSummary &Summary) {
OS << "LF:" << Summary.LineCoverage.getNumLines() << '\n'
<< "LH:" << Summary.LineCoverage.getCovered() << '\n';
}
+void renderBranchSummary(raw_ostream &OS, const FileCoverageSummary &Summary) {
+ OS << "BRF:" << Summary.BranchCoverage.getNumBranches() << '\n'
+ << "BFH:" << Summary.BranchCoverage.getCovered() << '\n';
+}
+
void renderFile(raw_ostream &OS, const coverage::CoverageMapping &Coverage,
const std::string &Filename,
const FileCoverageSummary &FileReport, bool ExportSummaryOnly,
@@ -91,7 +186,9 @@ void renderFile(raw_ostream &OS, const coverage::CoverageMapping &Coverage,
// Calculate and render detailed coverage information for given file.
auto FileCoverage = Coverage.getCoverageForFile(Filename);
renderLineExecutionCounts(OS, FileCoverage);
+ renderBranchExecutionCounts(OS, Coverage, FileCoverage);
}
+ renderBranchSummary(OS, FileReport);
renderLineSummary(OS, FileReport);
OS << "end_of_record\n";
diff --git a/llvm/tools/llvm-cov/CoverageReport.cpp b/llvm/tools/llvm-cov/CoverageReport.cpp
index 8509710..2c08f53 100644
--- a/llvm/tools/llvm-cov/CoverageReport.cpp
+++ b/llvm/tools/llvm-cov/CoverageReport.cpp
@@ -86,9 +86,9 @@ Column column(StringRef Str, unsigned Width, const T &Value) {
}
// Specify the default column widths.
-size_t FileReportColumns[] = {25, 12, 18, 10, 12, 18, 10,
- 16, 16, 10, 12, 18, 10};
-size_t FunctionReportColumns[] = {25, 10, 8, 8, 10, 8, 8};
+size_t FileReportColumns[] = {25, 12, 18, 10, 12, 18, 10, 16,
+ 16, 10, 12, 18, 10, 12, 18, 10};
+size_t FunctionReportColumns[] = {25, 10, 8, 8, 10, 8, 8, 10, 8, 8};
/// Adjust column widths to fit long file paths and function names.
void adjustColumnWidths(ArrayRef<StringRef> Files,
@@ -239,6 +239,23 @@ void CoverageReport::render(const FileCoverageSummary &File,
<< '%';
else
OS << column("-", FileReportColumns[12], Column::RightAlignment);
+
+ if (Options.ShowBranchSummary) {
+ OS << format("%*u", FileReportColumns[13],
+ (unsigned)File.BranchCoverage.getNumBranches());
+ Options.colored_ostream(OS, LineCoverageColor)
+ << format("%*u", FileReportColumns[14],
+ (unsigned)(File.BranchCoverage.getNumBranches() -
+ File.BranchCoverage.getCovered()));
+ if (File.BranchCoverage.getNumBranches())
+ Options.colored_ostream(OS, LineCoverageColor)
+ << format("%*.2f", FileReportColumns[15] - 1,
+ File.BranchCoverage.getPercentCovered())
+ << '%';
+ else
+ OS << column("-", FileReportColumns[15], Column::RightAlignment);
+ }
+
OS << "\n";
}
@@ -273,6 +290,19 @@ void CoverageReport::render(const FunctionCoverageSummary &Function,
<< format("%*.2f", FunctionReportColumns[6] - 1,
Function.LineCoverage.getPercentCovered())
<< '%';
+ if (Options.ShowBranchSummary) {
+ OS << format("%*u", FunctionReportColumns[7],
+ (unsigned)Function.BranchCoverage.getNumBranches());
+ Options.colored_ostream(OS, LineCoverageColor)
+ << format("%*u", FunctionReportColumns[8],
+ (unsigned)(Function.BranchCoverage.getNumBranches() -
+ Function.BranchCoverage.getCovered()));
+ Options.colored_ostream(
+ OS, determineCoveragePercentageColor(Function.BranchCoverage))
+ << format("%*.2f", FunctionReportColumns[9] - 1,
+ Function.BranchCoverage.getPercentCovered())
+ << '%';
+ }
OS << "\n";
}
@@ -301,6 +331,10 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
<< column("Lines", FunctionReportColumns[4], Column::RightAlignment)
<< column("Miss", FunctionReportColumns[5], Column::RightAlignment)
<< column("Cover", FunctionReportColumns[6], Column::RightAlignment);
+ if (Options.ShowBranchSummary)
+ OS << column("Branches", FunctionReportColumns[7], Column::RightAlignment)
+ << column("Miss", FunctionReportColumns[8], Column::RightAlignment)
+ << column("Cover", FunctionReportColumns[9], Column::RightAlignment);
OS << "\n";
renderDivider(FunctionReportColumns, OS);
OS << "\n";
@@ -310,6 +344,7 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
++Totals.ExecutionCount;
Totals.RegionCoverage += Function.RegionCoverage;
Totals.LineCoverage += Function.LineCoverage;
+ Totals.BranchCoverage += Function.BranchCoverage;
render(Function, DC, OS);
}
if (Totals.ExecutionCount) {
@@ -420,7 +455,13 @@ void CoverageReport::renderFileReports(
<< column("Executed", FileReportColumns[9], Column::RightAlignment);
OS << column("Lines", FileReportColumns[10], Column::RightAlignment)
<< column("Missed Lines", FileReportColumns[11], Column::RightAlignment)
- << column("Cover", FileReportColumns[12], Column::RightAlignment) << "\n";
+ << column("Cover", FileReportColumns[12], Column::RightAlignment);
+ if (Options.ShowBranchSummary)
+ OS << column("Branches", FileReportColumns[13], Column::RightAlignment)
+ << column("Missed Branches", FileReportColumns[14],
+ Column::RightAlignment)
+ << column("Cover", FileReportColumns[15], Column::RightAlignment);
+ OS << "\n";
renderDivider(FileReportColumns, OS);
OS << "\n";
diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
index 929529c..4a0a861 100644
--- a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
+++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
@@ -16,6 +16,34 @@
using namespace llvm;
using namespace coverage;
+static void sumBranches(size_t &NumBranches, size_t &CoveredBranches,
+ const ArrayRef<CountedRegion> &Branches) {
+ for (const auto &BR : Branches) {
+ // Skip folded branches.
+ if (BR.Folded)
+ continue;
+
+ // "True" Condition Branches.
+ ++NumBranches;
+ if (BR.ExecutionCount > 0)
+ ++CoveredBranches;
+ // "False" Condition Branches.
+ ++NumBranches;
+ if (BR.FalseExecutionCount > 0)
+ ++CoveredBranches;
+ }
+}
+
+static void sumBranchExpansions(size_t &NumBranches, size_t &CoveredBranches,
+ const CoverageMapping &CM,
+ ArrayRef<ExpansionRecord> Expansions) {
+ for (const auto &Expansion : Expansions) {
+ auto CE = CM.getCoverageForExpansion(Expansion);
+ sumBranches(NumBranches, CoveredBranches, CE.getBranches());
+ sumBranchExpansions(NumBranches, CoveredBranches, CM, CE.getExpansions());
+ }
+}
+
FunctionCoverageSummary
FunctionCoverageSummary::get(const CoverageMapping &CM,
const coverage::FunctionRecord &Function) {
@@ -40,10 +68,16 @@ FunctionCoverageSummary::get(const CoverageMapping &CM,
++CoveredLines;
}
+ // Compute the branch coverage, including branches from expansions.
+ size_t NumBranches = 0, CoveredBranches = 0;
+ sumBranches(NumBranches, CoveredBranches, CD.getBranches());
+ sumBranchExpansions(NumBranches, CoveredBranches, CM, CD.getExpansions());
+
return FunctionCoverageSummary(
Function.Name, Function.ExecutionCount,
RegionCoverageInfo(CoveredRegions, NumCodeRegions),
- LineCoverageInfo(CoveredLines, NumLines));
+ LineCoverageInfo(CoveredLines, NumLines),
+ BranchCoverageInfo(CoveredBranches, NumBranches));
}
FunctionCoverageSummary
@@ -62,9 +96,15 @@ FunctionCoverageSummary::get(const InstantiationGroup &Group,
Summary.ExecutionCount = Group.getTotalExecutionCount();
Summary.RegionCoverage = Summaries[0].RegionCoverage;
Summary.LineCoverage = Summaries[0].LineCoverage;
+ Summary.BranchCoverage = Summaries[0].BranchCoverage;
for (const auto &FCS : Summaries.drop_front()) {
Summary.RegionCoverage.merge(FCS.RegionCoverage);
Summary.LineCoverage.merge(FCS.LineCoverage);
+
+ // Sum branch coverage across instantiation groups for the summary rather
+ // than "merge" the maximum count. This is a clearer view into whether all
+ // created branches are covered.
+ Summary.BranchCoverage += FCS.BranchCoverage;
}
return Summary;
}
diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.h b/llvm/tools/llvm-cov/CoverageSummaryInfo.h
index 97beacb..4bc1c24 100644
--- a/llvm/tools/llvm-cov/CoverageSummaryInfo.h
+++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.h
@@ -101,6 +101,42 @@ public:
}
};
+/// Provides information about branches coverage for a function/file.
+class BranchCoverageInfo {
+ /// The number of branches that were executed at least once.
+ size_t Covered;
+
+ /// The total number of branches in a function/file.
+ size_t NumBranches;
+
+public:
+ BranchCoverageInfo() : Covered(0), NumBranches(0) {}
+
+ BranchCoverageInfo(size_t Covered, size_t NumBranches)
+ : Covered(Covered), NumBranches(NumBranches) {
+ assert(Covered <= NumBranches && "Covered branches over-counted");
+ }
+
+ BranchCoverageInfo &operator+=(const BranchCoverageInfo &RHS) {
+ Covered += RHS.Covered;
+ NumBranches += RHS.NumBranches;
+ return *this;
+ }
+
+ size_t getCovered() const { return Covered; }
+
+ size_t getNumBranches() const { return NumBranches; }
+
+ bool isFullyCovered() const { return Covered == NumBranches; }
+
+ double getPercentCovered() const {
+ assert(Covered <= NumBranches && "Covered branches over-counted");
+ if (NumBranches == 0)
+ return 0.0;
+ return double(Covered) / double(NumBranches) * 100.0;
+ }
+};
+
/// Provides information about function coverage for a file.
class FunctionCoverageInfo {
/// The number of functions that were executed.
@@ -147,15 +183,19 @@ struct FunctionCoverageSummary {
uint64_t ExecutionCount;
RegionCoverageInfo RegionCoverage;
LineCoverageInfo LineCoverage;
+ BranchCoverageInfo BranchCoverage;
FunctionCoverageSummary(const std::string &Name)
- : Name(Name), ExecutionCount(0), RegionCoverage(), LineCoverage() {}
+ : Name(Name), ExecutionCount(0), RegionCoverage(), LineCoverage(),
+ BranchCoverage() {}
FunctionCoverageSummary(const std::string &Name, uint64_t ExecutionCount,
const RegionCoverageInfo &RegionCoverage,
- const LineCoverageInfo &LineCoverage)
+ const LineCoverageInfo &LineCoverage,
+ const BranchCoverageInfo &BranchCoverage)
: Name(Name), ExecutionCount(ExecutionCount),
- RegionCoverage(RegionCoverage), LineCoverage(LineCoverage) {}
+ RegionCoverage(RegionCoverage), LineCoverage(LineCoverage),
+ BranchCoverage(BranchCoverage) {}
/// Compute the code coverage summary for the given function coverage
/// mapping record.
@@ -174,6 +214,7 @@ struct FileCoverageSummary {
StringRef Name;
RegionCoverageInfo RegionCoverage;
LineCoverageInfo LineCoverage;
+ BranchCoverageInfo BranchCoverage;
FunctionCoverageInfo FunctionCoverage;
FunctionCoverageInfo InstantiationCoverage;
@@ -185,6 +226,7 @@ struct FileCoverageSummary {
RegionCoverage += RHS.RegionCoverage;
LineCoverage += RHS.LineCoverage;
FunctionCoverage += RHS.FunctionCoverage;
+ BranchCoverage += RHS.BranchCoverage;
InstantiationCoverage += RHS.InstantiationCoverage;
return *this;
}
@@ -192,6 +234,7 @@ struct FileCoverageSummary {
void addFunction(const FunctionCoverageSummary &Function) {
RegionCoverage += Function.RegionCoverage;
LineCoverage += Function.LineCoverage;
+ BranchCoverage += Function.BranchCoverage;
FunctionCoverage.addFunction(/*Covered=*/Function.ExecutionCount > 0);
}
diff --git a/llvm/tools/llvm-cov/CoverageViewOptions.h b/llvm/tools/llvm-cov/CoverageViewOptions.h
index dde0c69..eee4ba7 100644
--- a/llvm/tools/llvm-cov/CoverageViewOptions.h
+++ b/llvm/tools/llvm-cov/CoverageViewOptions.h
@@ -23,20 +23,26 @@ struct CoverageViewOptions {
Lcov
};
+ enum class BranchOutputType { Count, Percent, Off };
+
bool Debug;
bool Colors;
bool ShowLineNumbers;
bool ShowLineStats;
bool ShowRegionMarkers;
+ bool ShowBranchCounts;
+ bool ShowBranchPercents;
bool ShowExpandedRegions;
bool ShowFunctionInstantiations;
bool ShowFullFilenames;
+ bool ShowBranchSummary;
bool ShowRegionSummary;
bool ShowInstantiationSummary;
bool ExportSummaryOnly;
bool SkipExpansions;
bool SkipFunctions;
OutputFormat Format;
+ BranchOutputType ShowBranches;
std::string ShowOutputDirectory;
std::vector<std::string> DemanglerOpts;
uint32_t TabSize;
diff --git a/llvm/tools/llvm-cov/SourceCoverageView.cpp b/llvm/tools/llvm-cov/SourceCoverageView.cpp
index cd7395a..aca58a0 100644
--- a/llvm/tools/llvm-cov/SourceCoverageView.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageView.cpp
@@ -132,7 +132,8 @@ bool SourceCoverageView::shouldRenderRegionMarkers(
}
bool SourceCoverageView::hasSubViews() const {
- return !ExpansionSubViews.empty() || !InstantiationSubViews.empty();
+ return !ExpansionSubViews.empty() || !InstantiationSubViews.empty() ||
+ !BranchSubViews.empty();
}
std::unique_ptr<SourceCoverageView>
@@ -167,6 +168,12 @@ void SourceCoverageView::addExpansion(
ExpansionSubViews.emplace_back(Region, std::move(View));
}
+void SourceCoverageView::addBranch(unsigned Line,
+ ArrayRef<CountedRegion> Regions,
+ std::unique_ptr<SourceCoverageView> View) {
+ BranchSubViews.emplace_back(Line, Regions, std::move(View));
+}
+
void SourceCoverageView::addInstantiation(
StringRef FunctionName, unsigned Line,
std::unique_ptr<SourceCoverageView> View) {
@@ -187,14 +194,17 @@ void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
renderTableHeader(OS, (ViewDepth > 0) ? 0 : getFirstUncoveredLineNo(),
ViewDepth);
- // We need the expansions and instantiations sorted so we can go through them
- // while we iterate lines.
+ // We need the expansions, instantiations, and branches sorted so we can go
+ // through them while we iterate lines.
llvm::stable_sort(ExpansionSubViews);
llvm::stable_sort(InstantiationSubViews);
+ llvm::stable_sort(BranchSubViews);
auto NextESV = ExpansionSubViews.begin();
auto EndESV = ExpansionSubViews.end();
auto NextISV = InstantiationSubViews.begin();
auto EndISV = InstantiationSubViews.end();
+ auto NextBRV = BranchSubViews.begin();
+ auto EndBRV = BranchSubViews.end();
// Get the coverage information for the file.
auto StartSegment = CoverageInfo.begin();
@@ -234,7 +244,7 @@ void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
if (shouldRenderRegionMarkers(*LCI))
renderRegionMarkers(OS, *LCI, ViewDepth);
- // Show the expansions and instantiations for this line.
+ // Show the expansions, instantiations, and branches for this line.
bool RenderedSubView = false;
for (; NextESV != EndESV && NextESV->getLine() == LI.line_number();
++NextESV) {
@@ -257,6 +267,11 @@ void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
renderInstantiationView(OS, *NextISV, ViewDepth + 1);
RenderedSubView = true;
}
+ for (; NextBRV != EndBRV && NextBRV->Line == LI.line_number(); ++NextBRV) {
+ renderViewDivider(OS, ViewDepth + 1);
+ renderBranchView(OS, *NextBRV, ViewDepth + 1);
+ RenderedSubView = true;
+ }
if (RenderedSubView)
renderViewDivider(OS, ViewDepth + 1);
renderLineSuffix(OS, ViewDepth);
diff --git a/llvm/tools/llvm-cov/SourceCoverageView.h b/llvm/tools/llvm-cov/SourceCoverageView.h
index 9ae9284..5a9fcdd 100644
--- a/llvm/tools/llvm-cov/SourceCoverageView.h
+++ b/llvm/tools/llvm-cov/SourceCoverageView.h
@@ -67,6 +67,23 @@ struct InstantiationView {
}
};
+/// A view that represents one or more branch regions on a given source line.
+struct BranchView {
+ std::vector<CountedRegion> Regions;
+ std::unique_ptr<SourceCoverageView> View;
+ unsigned Line;
+
+ BranchView(unsigned Line, ArrayRef<CountedRegion> Regions,
+ std::unique_ptr<SourceCoverageView> View)
+ : Regions(Regions), View(std::move(View)), Line(Line) {}
+
+ unsigned getLine() const { return Line; }
+
+ friend bool operator<(const BranchView &LHS, const BranchView &RHS) {
+ return LHS.Line < RHS.Line;
+ }
+};
+
/// A file manager that handles format-aware file creation.
class CoveragePrinter {
public:
@@ -140,6 +157,9 @@ class SourceCoverageView {
/// A container for all expansions (e.g macros) in the source on display.
std::vector<ExpansionView> ExpansionSubViews;
+ /// A container for all branches in the source on display.
+ std::vector<BranchView> BranchSubViews;
+
/// A container for all instantiations (e.g template functions) in the source
/// on display.
std::vector<InstantiationView> InstantiationSubViews;
@@ -209,6 +229,10 @@ protected:
virtual void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV,
unsigned ViewDepth) = 0;
+ /// Render a branch view and any nested views.
+ virtual void renderBranchView(raw_ostream &OS, BranchView &BRV,
+ unsigned ViewDepth) = 0;
+
/// Render \p Title, a project title if one is available, and the
/// created time.
virtual void renderTitle(raw_ostream &OS, StringRef CellText) = 0;
@@ -255,6 +279,10 @@ public:
void addInstantiation(StringRef FunctionName, unsigned Line,
std::unique_ptr<SourceCoverageView> View);
+ /// Add a branch subview to this view.
+ void addBranch(unsigned Line, ArrayRef<CountedRegion> Regions,
+ std::unique_ptr<SourceCoverageView> View);
+
/// Print the code coverage information for a specific portion of a
/// source file to the output stream.
void print(raw_ostream &OS, bool WholeFile, bool ShowSourceName,
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
index 9d10def..4db5624 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
@@ -313,6 +313,8 @@ static void emitColumnLabelsForIndex(raw_ostream &OS,
Columns.emplace_back(tag("td", "Line Coverage", "column-entry-bold"));
if (Opts.ShowRegionSummary)
Columns.emplace_back(tag("td", "Region Coverage", "column-entry-bold"));
+ if (Opts.ShowBranchSummary)
+ Columns.emplace_back(tag("td", "Branch Coverage", "column-entry-bold"));
OS << tag("tr", join(Columns.begin(), Columns.end(), ""));
}
@@ -378,6 +380,10 @@ void CoveragePrinterHTML::emitFileSummary(raw_ostream &OS, StringRef SF,
AddCoverageTripleToColumn(FCS.RegionCoverage.getCovered(),
FCS.RegionCoverage.getNumRegions(),
FCS.RegionCoverage.getPercentCovered());
+ if (Opts.ShowBranchSummary)
+ AddCoverageTripleToColumn(FCS.BranchCoverage.getCovered(),
+ FCS.BranchCoverage.getNumBranches(),
+ FCS.BranchCoverage.getPercentCovered());
if (IsTotals)
OS << tag("tr", join(Columns.begin(), Columns.end(), ""), "light-row-bold");
@@ -650,6 +656,72 @@ void SourceCoverageViewHTML::renderExpansionView(raw_ostream &OS,
OS << EndExpansionDiv;
}
+void SourceCoverageViewHTML::renderBranchView(raw_ostream &OS, BranchView &BRV,
+ unsigned ViewDepth) {
+ // Render the child subview.
+ if (getOptions().Debug)
+ errs() << "Branch at line " << BRV.getLine() << '\n';
+
+ OS << BeginExpansionDiv;
+ OS << BeginPre;
+ for (const auto &R : BRV.Regions) {
+ // Calculate TruePercent and False Percent.
+ double TruePercent = 0.0;
+ double FalsePercent = 0.0;
+ unsigned Total = R.ExecutionCount + R.FalseExecutionCount;
+
+ if (!getOptions().ShowBranchCounts && Total != 0) {
+ TruePercent = ((double)(R.ExecutionCount) / (double)Total) * 100.0;
+ FalsePercent = ((double)(R.FalseExecutionCount) / (double)Total) * 100.0;
+ }
+
+ // Display Line + Column.
+ std::string LineNoStr = utostr(uint64_t(R.LineStart));
+ std::string ColNoStr = utostr(uint64_t(R.ColumnStart));
+ std::string TargetName = "L" + LineNoStr;
+
+ OS << " Branch (";
+ OS << tag("span",
+ a("#" + TargetName, tag("span", LineNoStr + ":" + ColNoStr),
+ TargetName),
+ "line-number") +
+ "): [";
+
+ if (R.Folded) {
+ OS << "Folded - Ignored]\n";
+ continue;
+ }
+
+ // Display TrueCount or TruePercent.
+ std::string TrueColor = R.ExecutionCount ? "None" : "red";
+ std::string TrueCovClass =
+ (R.ExecutionCount > 0) ? "covered-line" : "uncovered-line";
+
+ OS << tag("span", "True", TrueColor);
+ OS << ": ";
+ if (getOptions().ShowBranchCounts)
+ OS << tag("span", formatCount(R.ExecutionCount), TrueCovClass) << ", ";
+ else
+ OS << format("%0.2f", TruePercent) << "%, ";
+
+ // Display FalseCount or FalsePercent.
+ std::string FalseColor = R.FalseExecutionCount ? "None" : "red";
+ std::string FalseCovClass =
+ (R.FalseExecutionCount > 0) ? "covered-line" : "uncovered-line";
+
+ OS << tag("span", "False", FalseColor);
+ OS << ": ";
+ if (getOptions().ShowBranchCounts)
+ OS << tag("span", formatCount(R.FalseExecutionCount), FalseCovClass);
+ else
+ OS << format("%0.2f", FalsePercent) << "%";
+
+ OS << "]\n";
+ }
+ OS << EndPre;
+ OS << EndExpansionDiv;
+}
+
void SourceCoverageViewHTML::renderInstantiationView(raw_ostream &OS,
InstantiationView &ISV,
unsigned ViewDepth) {
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewHTML.h b/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
index 9834040..7d94675 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
+++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
@@ -68,6 +68,9 @@ class SourceCoverageViewHTML : public SourceCoverageView {
void renderExpansionView(raw_ostream &OS, ExpansionView &ESV,
unsigned ViewDepth) override;
+ void renderBranchView(raw_ostream &OS, BranchView &BRV,
+ unsigned ViewDepth) override;
+
void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV,
unsigned ViewDepth) override;
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
index fcabee2..948414a 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
@@ -10,11 +10,12 @@
///
//===----------------------------------------------------------------------===//
-#include "CoverageReport.h"
#include "SourceCoverageViewText.h"
+#include "CoverageReport.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Format.h"
using namespace llvm;
@@ -222,6 +223,53 @@ void SourceCoverageViewText::renderExpansionView(raw_ostream &OS,
/*ShowTitle=*/false, ViewDepth + 1);
}
+void SourceCoverageViewText::renderBranchView(raw_ostream &OS, BranchView &BRV,
+ unsigned ViewDepth) {
+ // Render the child subview.
+ if (getOptions().Debug)
+ errs() << "Branch at line " << BRV.getLine() << '\n';
+
+ for (const auto &R : BRV.Regions) {
+ double TruePercent = 0.0;
+ double FalsePercent = 0.0;
+ unsigned Total = R.ExecutionCount + R.FalseExecutionCount;
+
+ if (!getOptions().ShowBranchCounts && Total != 0) {
+ TruePercent = ((double)(R.ExecutionCount) / (double)Total) * 100.0;
+ FalsePercent = ((double)(R.FalseExecutionCount) / (double)Total) * 100.0;
+ }
+
+ renderLinePrefix(OS, ViewDepth);
+ OS << " Branch (" << R.LineStart << ":" << R.ColumnStart << "): [";
+
+ if (R.Folded) {
+ OS << "Folded - Ignored]\n";
+ continue;
+ }
+
+ colored_ostream(OS, raw_ostream::RED,
+ getOptions().Colors && !R.ExecutionCount,
+ /*Bold=*/false, /*BG=*/true)
+ << "True";
+
+ if (getOptions().ShowBranchCounts)
+ OS << ": " << formatCount(R.ExecutionCount) << ", ";
+ else
+ OS << ": " << format("%0.2f", TruePercent) << "%, ";
+
+ colored_ostream(OS, raw_ostream::RED,
+ getOptions().Colors && !R.FalseExecutionCount,
+ /*Bold=*/false, /*BG=*/true)
+ << "False";
+
+ if (getOptions().ShowBranchCounts)
+ OS << ": " << formatCount(R.FalseExecutionCount);
+ else
+ OS << ": " << format("%0.2f", FalsePercent) << "%";
+ OS << "]\n";
+ }
+}
+
void SourceCoverageViewText::renderInstantiationView(raw_ostream &OS,
InstantiationView &ISV,
unsigned ViewDepth) {
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.h b/llvm/tools/llvm-cov/SourceCoverageViewText.h
index c8c4632..b2be060 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewText.h
+++ b/llvm/tools/llvm-cov/SourceCoverageViewText.h
@@ -59,6 +59,9 @@ class SourceCoverageViewText : public SourceCoverageView {
void renderExpansionView(raw_ostream &OS, ExpansionView &ESV,
unsigned ViewDepth) override;
+ void renderBranchView(raw_ostream &OS, BranchView &BRV,
+ unsigned ViewDepth) override;
+
void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV,
unsigned ViewDepth) override;