aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-cov
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-cov')
-rw-r--r--llvm/tools/llvm-cov/CodeCoverage.cpp55
-rw-r--r--llvm/tools/llvm-cov/CoverageExporterJson.cpp44
-rw-r--r--llvm/tools/llvm-cov/CoverageReport.cpp47
-rw-r--r--llvm/tools/llvm-cov/CoverageSummaryInfo.cpp19
-rw-r--r--llvm/tools/llvm-cov/CoverageSummaryInfo.h50
-rw-r--r--llvm/tools/llvm-cov/CoverageViewOptions.h2
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageView.cpp14
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageView.h28
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp52
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageViewHTML.h3
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageViewText.cpp51
-rw-r--r--llvm/tools/llvm-cov/SourceCoverageViewText.h3
12 files changed, 361 insertions, 7 deletions
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index b5d763d..cf341e4 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -105,6 +105,11 @@ private:
const MemoryBuffer &File,
CoverageData &CoverageInfo);
+ /// Create source views for the MCDC records.
+ void attachMCDCSubViews(SourceCoverageView &View, StringRef SourceName,
+ ArrayRef<MCDCRecord> MCDCRecords,
+ const MemoryBuffer &File, CoverageData &CoverageInfo);
+
/// Create the source view of a particular function.
std::unique_ptr<SourceCoverageView>
createFunctionView(const FunctionRecord &Function,
@@ -352,6 +357,36 @@ void CodeCoverageTool::attachBranchSubViews(SourceCoverageView &View,
}
}
+void CodeCoverageTool::attachMCDCSubViews(SourceCoverageView &View,
+ StringRef SourceName,
+ ArrayRef<MCDCRecord> MCDCRecords,
+ const MemoryBuffer &File,
+ CoverageData &CoverageInfo) {
+ if (!ViewOpts.ShowMCDC)
+ return;
+
+ const auto *NextRecord = MCDCRecords.begin();
+ const auto *EndRecord = MCDCRecords.end();
+
+ // Group and process MCDC records that have the same line number into the
+ // same subview.
+ while (NextRecord != EndRecord) {
+ std::vector<MCDCRecord> ViewMCDCRecords;
+ unsigned CurrentLine = NextRecord->getDecisionRegion().LineEnd;
+
+ while (NextRecord != EndRecord &&
+ CurrentLine == NextRecord->getDecisionRegion().LineEnd) {
+ ViewMCDCRecords.push_back(*NextRecord++);
+ }
+
+ if (!ViewMCDCRecords.empty()) {
+ auto SubView = SourceCoverageView::create(SourceName, File, ViewOpts,
+ std::move(CoverageInfo));
+ View.addMCDCRecord(CurrentLine, ViewMCDCRecords, std::move(SubView));
+ }
+ }
+}
+
std::unique_ptr<SourceCoverageView>
CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
const CoverageMapping &Coverage) {
@@ -364,12 +399,15 @@ CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
auto Branches = FunctionCoverage.getBranches();
auto Expansions = FunctionCoverage.getExpansions();
+ auto MCDCRecords = FunctionCoverage.getMCDCRecords();
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);
+ attachMCDCSubViews(*View, DC.demangle(Function.Name), MCDCRecords,
+ SourceBuffer.get(), FunctionCoverage);
return View;
}
@@ -386,11 +424,14 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile,
auto Branches = FileCoverage.getBranches();
auto Expansions = FileCoverage.getExpansions();
+ auto MCDCRecords = FileCoverage.getMCDCRecords();
auto View = SourceCoverageView::create(SourceFile, SourceBuffer.get(),
ViewOpts, std::move(FileCoverage));
attachExpansionSubViews(*View, Expansions, Coverage);
attachBranchSubViews(*View, SourceFile, Branches, SourceBuffer.get(),
FileCoverage);
+ attachMCDCSubViews(*View, SourceFile, MCDCRecords, SourceBuffer.get(),
+ FileCoverage);
if (!ViewOpts.ShowFunctionInstantiations)
return View;
@@ -408,11 +449,14 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile,
auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
auto SubViewExpansions = SubViewCoverage.getExpansions();
auto SubViewBranches = SubViewCoverage.getBranches();
+ auto SubViewMCDCRecords = SubViewCoverage.getMCDCRecords();
SubView = SourceCoverageView::create(
Funcname, SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
attachBranchSubViews(*SubView, SourceFile, SubViewBranches,
SourceBuffer.get(), SubViewCoverage);
+ attachMCDCSubViews(*SubView, SourceFile, SubViewMCDCRecords,
+ SourceBuffer.get(), SubViewCoverage);
}
unsigned FileID = Function->CountedRegions.front().FileID;
@@ -752,6 +796,10 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
cl::desc("Show branch condition statistics in summary table"),
cl::init(true));
+ cl::opt<bool> MCDCSummary("show-mcdc-summary", cl::Optional,
+ cl::desc("Show MCDC statistics in summary table"),
+ cl::init(false));
+
cl::opt<bool> InstantiationSummary(
"show-instantiation-summary", cl::Optional,
cl::desc("Show instantiation statistics in summary table"));
@@ -923,6 +971,7 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
::exit(0);
}
+ ViewOpts.ShowMCDCSummary = MCDCSummary;
ViewOpts.ShowBranchSummary = BranchSummary;
ViewOpts.ShowRegionSummary = RegionSummary;
ViewOpts.ShowInstantiationSummary = InstantiationSummary;
@@ -968,6 +1017,11 @@ int CodeCoverageTool::doShow(int argc, const char **argv,
"percent", "Show True/False percent")),
cl::init(CoverageViewOptions::BranchOutputType::Off));
+ cl::opt<bool> ShowMCDC(
+ "show-mcdc", cl::Optional,
+ cl::desc("Show the MCDC Coverage for each applicable boolean expression"),
+ cl::cat(ViewCategory));
+
cl::opt<bool> ShowBestLineRegionsCounts(
"show-line-counts-or-regions", cl::Optional,
cl::desc("Show the execution counts for each line, or the execution "
@@ -1063,6 +1117,7 @@ int CodeCoverageTool::doShow(int argc, const char **argv,
ViewOpts.ShowExpandedRegions = ShowExpansions;
ViewOpts.ShowBranchCounts =
ShowBranches == CoverageViewOptions::BranchOutputType::Count;
+ ViewOpts.ShowMCDC = ShowMCDC;
ViewOpts.ShowBranchPercents =
ShowBranches == CoverageViewOptions::BranchOutputType::Percent;
ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
diff --git a/llvm/tools/llvm-cov/CoverageExporterJson.cpp b/llvm/tools/llvm-cov/CoverageExporterJson.cpp
index 9e43377..a424bbe 100644
--- a/llvm/tools/llvm-cov/CoverageExporterJson.cpp
+++ b/llvm/tools/llvm-cov/CoverageExporterJson.cpp
@@ -20,6 +20,8 @@
// -- 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
+// -- MCDC Records: array => List of MCDC records in the file
+// -- MCDC Values: array => List of T/F covered condition values
// -- 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
@@ -34,6 +36,7 @@
// -- FunctionCoverage: dict => Object summarizing function coverage
// -- RegionCoverage: dict => Object summarizing region coverage
// -- BranchCoverage: dict => Object summarizing branch coverage
+// -- MCDCCoverage: dict => Object summarizing MC/DC 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
@@ -43,6 +46,7 @@
// -- InstantiationCoverage: dict => Object summarizing inst. coverage
// -- RegionCoverage: dict => Object summarizing region coverage
// -- BranchCoverage: dict => Object summarizing branch coverage
+// -- MCDCCoverage: dict => Object summarizing MC/DC coverage
//
//===----------------------------------------------------------------------===//
@@ -97,6 +101,20 @@ json::Array renderBranch(const coverage::CountedRegion &Region) {
Region.ExpandedFileID, int64_t(Region.Kind)});
}
+json::Array gatherConditions(const coverage::MCDCRecord &Record) {
+ json::Array Conditions;
+ for (unsigned c = 0; c < Record.getNumConditions(); c++)
+ Conditions.push_back(Record.isConditionIndependencePairCovered(c));
+ return Conditions;
+}
+
+json::Array renderMCDCRecord(const coverage::MCDCRecord &Record) {
+ const llvm::coverage::CounterMappingRegion &CMR = Record.getDecisionRegion();
+ return json::Array({CMR.LineStart, CMR.ColumnStart, CMR.LineEnd,
+ CMR.ColumnEnd, CMR.ExpandedFileID, int64_t(CMR.Kind),
+ gatherConditions(Record)});
+}
+
json::Array renderRegions(ArrayRef<coverage::CountedRegion> Regions) {
json::Array RegionArray;
for (const auto &Region : Regions)
@@ -112,6 +130,13 @@ json::Array renderBranchRegions(ArrayRef<coverage::CountedRegion> Regions) {
return RegionArray;
}
+json::Array renderMCDCRecords(ArrayRef<coverage::MCDCRecord> Records) {
+ json::Array RecordArray;
+ for (auto &Record : Records)
+ RecordArray.push_back(renderMCDCRecord(Record));
+ return RecordArray;
+}
+
std::vector<llvm::coverage::CountedRegion>
collectNestedBranches(const coverage::CoverageMapping &Coverage,
ArrayRef<llvm::coverage::ExpansionRecord> Expansions) {
@@ -178,7 +203,14 @@ json::Object renderSummary(const FileCoverageSummary &Summary) {
{"covered", int64_t(Summary.BranchCoverage.getCovered())},
{"notcovered", int64_t(Summary.BranchCoverage.getNumBranches() -
Summary.BranchCoverage.getCovered())},
- {"percent", Summary.BranchCoverage.getPercentCovered()}})}});
+ {"percent", Summary.BranchCoverage.getPercentCovered()}})},
+ {"mcdc",
+ json::Object(
+ {{"count", int64_t(Summary.MCDCCoverage.getNumPairs())},
+ {"covered", int64_t(Summary.MCDCCoverage.getCoveredPairs())},
+ {"notcovered", int64_t(Summary.MCDCCoverage.getNumPairs() -
+ Summary.MCDCCoverage.getCoveredPairs())},
+ {"percent", Summary.MCDCCoverage.getPercentCovered()}})}});
}
json::Array renderFileExpansions(const coverage::CoverageMapping &Coverage,
@@ -206,6 +238,14 @@ json::Array renderFileBranches(const coverage::CoverageData &FileCoverage,
return BranchArray;
}
+json::Array renderFileMCDC(const coverage::CoverageData &FileCoverage,
+ const FileCoverageSummary &FileReport) {
+ json::Array MCDCRecordArray;
+ for (const auto &Record : FileCoverage.getMCDCRecords())
+ MCDCRecordArray.push_back(renderMCDCRecord(Record));
+ return MCDCRecordArray;
+}
+
json::Object renderFile(const coverage::CoverageMapping &Coverage,
const std::string &Filename,
const FileCoverageSummary &FileReport,
@@ -216,6 +256,7 @@ json::Object renderFile(const coverage::CoverageMapping &Coverage,
auto FileCoverage = Coverage.getCoverageForFile(Filename);
File["segments"] = renderFileSegments(FileCoverage, FileReport);
File["branches"] = renderFileBranches(FileCoverage, FileReport);
+ File["mcdc_records"] = renderFileMCDC(FileCoverage, FileReport);
if (!Options.SkipExpansions) {
File["expansions"] =
renderFileExpansions(Coverage, FileCoverage, FileReport);
@@ -264,6 +305,7 @@ json::Array renderFunctions(
{"count", clamp_uint64_to_int64(F.ExecutionCount)},
{"regions", renderRegions(F.CountedRegions)},
{"branches", renderBranchRegions(F.CountedBranchRegions)},
+ {"mcdc_records", renderMCDCRecords(F.MCDCRecords)},
{"filenames", json::Array(F.Filenames)}}));
return FunctionArray;
}
diff --git a/llvm/tools/llvm-cov/CoverageReport.cpp b/llvm/tools/llvm-cov/CoverageReport.cpp
index 518f6cd..bb12895 100644
--- a/llvm/tools/llvm-cov/CoverageReport.cpp
+++ b/llvm/tools/llvm-cov/CoverageReport.cpp
@@ -87,9 +87,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, 12, 18, 10};
-size_t FunctionReportColumns[] = {25, 10, 8, 8, 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, 20, 21, 10};
+size_t FunctionReportColumns[] = {25, 10, 8, 8, 10, 8, 8, 10, 8, 8, 20, 8, 8};
/// Adjust column widths to fit long file paths and function names.
void adjustColumnWidths(ArrayRef<StringRef> Files,
@@ -292,6 +292,22 @@ void CoverageReport::render(const FileCoverageSummary &File,
OS << column("-", FileReportColumns[15], Column::RightAlignment);
}
+ if (Options.ShowMCDCSummary) {
+ OS << format("%*u", FileReportColumns[16],
+ (unsigned)File.MCDCCoverage.getNumPairs());
+ Options.colored_ostream(OS, LineCoverageColor)
+ << format("%*u", FileReportColumns[17],
+ (unsigned)(File.MCDCCoverage.getNumPairs() -
+ File.MCDCCoverage.getCoveredPairs()));
+ if (File.MCDCCoverage.getNumPairs())
+ Options.colored_ostream(OS, LineCoverageColor)
+ << format("%*.2f", FileReportColumns[18] - 1,
+ File.MCDCCoverage.getPercentCovered())
+ << '%';
+ else
+ OS << column("-", FileReportColumns[18], Column::RightAlignment);
+ }
+
OS << "\n";
}
@@ -339,6 +355,19 @@ void CoverageReport::render(const FunctionCoverageSummary &Function,
Function.BranchCoverage.getPercentCovered())
<< '%';
}
+ if (Options.ShowMCDCSummary) {
+ OS << format("%*u", FunctionReportColumns[10],
+ (unsigned)Function.MCDCCoverage.getNumPairs());
+ Options.colored_ostream(OS, LineCoverageColor)
+ << format("%*u", FunctionReportColumns[11],
+ (unsigned)(Function.MCDCCoverage.getNumPairs() -
+ Function.MCDCCoverage.getCoveredPairs()));
+ Options.colored_ostream(
+ OS, determineCoveragePercentageColor(Function.MCDCCoverage))
+ << format("%*.2f", FunctionReportColumns[12] - 1,
+ Function.MCDCCoverage.getPercentCovered())
+ << '%';
+ }
OS << "\n";
}
@@ -371,6 +400,11 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
OS << column("Branches", FunctionReportColumns[7], Column::RightAlignment)
<< column("Miss", FunctionReportColumns[8], Column::RightAlignment)
<< column("Cover", FunctionReportColumns[9], Column::RightAlignment);
+ if (Options.ShowMCDCSummary)
+ OS << column("MC/DC Conditions", FunctionReportColumns[10],
+ Column::RightAlignment)
+ << column("Miss", FunctionReportColumns[11], Column::RightAlignment)
+ << column("Cover", FunctionReportColumns[12], Column::RightAlignment);
OS << "\n";
renderDivider(FunctionReportColumns, OS);
OS << "\n";
@@ -381,6 +415,7 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
Totals.RegionCoverage += Function.RegionCoverage;
Totals.LineCoverage += Function.LineCoverage;
Totals.BranchCoverage += Function.BranchCoverage;
+ Totals.MCDCCoverage += Function.MCDCCoverage;
render(Function, DC, OS);
}
if (Totals.ExecutionCount) {
@@ -503,6 +538,12 @@ void CoverageReport::renderFileReports(
<< column("Missed Branches", FileReportColumns[14],
Column::RightAlignment)
<< column("Cover", FileReportColumns[15], Column::RightAlignment);
+ if (Options.ShowMCDCSummary)
+ OS << column("MC/DC Conditions", FileReportColumns[16],
+ Column::RightAlignment)
+ << column("Missed Conditions", FileReportColumns[17],
+ Column::RightAlignment)
+ << column("Cover", FileReportColumns[18], 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 10e059a..93f24e9 100644
--- a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
+++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
@@ -44,6 +44,17 @@ static void sumBranchExpansions(size_t &NumBranches, size_t &CoveredBranches,
}
}
+static void sumMCDCPairs(size_t &NumPairs, size_t &CoveredPairs,
+ const ArrayRef<MCDCRecord> &Records) {
+ for (const auto &Record : Records)
+ for (unsigned C = 0; C < Record.getNumConditions(); C++) {
+ if (!Record.isCondFolded(C))
+ ++NumPairs;
+ if (Record.isConditionIndependencePairCovered(C))
+ ++CoveredPairs;
+ }
+}
+
FunctionCoverageSummary
FunctionCoverageSummary::get(const CoverageMapping &CM,
const coverage::FunctionRecord &Function) {
@@ -73,11 +84,15 @@ FunctionCoverageSummary::get(const CoverageMapping &CM,
sumBranches(NumBranches, CoveredBranches, CD.getBranches());
sumBranchExpansions(NumBranches, CoveredBranches, CM, CD.getExpansions());
+ size_t NumPairs = 0, CoveredPairs = 0;
+ sumMCDCPairs(NumPairs, CoveredPairs, CD.getMCDCRecords());
+
return FunctionCoverageSummary(
Function.Name, Function.ExecutionCount,
RegionCoverageInfo(CoveredRegions, NumCodeRegions),
LineCoverageInfo(CoveredLines, NumLines),
- BranchCoverageInfo(CoveredBranches, NumBranches));
+ BranchCoverageInfo(CoveredBranches, NumBranches),
+ MCDCCoverageInfo(CoveredPairs, NumPairs));
}
FunctionCoverageSummary
@@ -97,10 +112,12 @@ FunctionCoverageSummary::get(const InstantiationGroup &Group,
Summary.RegionCoverage = Summaries[0].RegionCoverage;
Summary.LineCoverage = Summaries[0].LineCoverage;
Summary.BranchCoverage = Summaries[0].BranchCoverage;
+ Summary.MCDCCoverage = Summaries[0].MCDCCoverage;
for (const auto &FCS : Summaries.drop_front()) {
Summary.RegionCoverage.merge(FCS.RegionCoverage);
Summary.LineCoverage.merge(FCS.LineCoverage);
Summary.BranchCoverage.merge(FCS.BranchCoverage);
+ Summary.MCDCCoverage.merge(FCS.MCDCCoverage);
}
return Summary;
}
diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.h b/llvm/tools/llvm-cov/CoverageSummaryInfo.h
index 46510dc..293311e 100644
--- a/llvm/tools/llvm-cov/CoverageSummaryInfo.h
+++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.h
@@ -142,6 +142,47 @@ public:
}
};
+/// Provides information about branches coverage for a function/file.
+class MCDCCoverageInfo {
+ /// The number of Independence Pairs that were covered.
+ size_t CoveredPairs;
+
+ /// The total number of Independence Pairs in a function/file.
+ size_t NumPairs;
+
+public:
+ MCDCCoverageInfo() : CoveredPairs(0), NumPairs(0) {}
+
+ MCDCCoverageInfo(size_t CoveredPairs, size_t NumPairs)
+ : CoveredPairs(CoveredPairs), NumPairs(NumPairs) {
+ assert(CoveredPairs <= NumPairs && "Covered pairs over-counted");
+ }
+
+ MCDCCoverageInfo &operator+=(const MCDCCoverageInfo &RHS) {
+ CoveredPairs += RHS.CoveredPairs;
+ NumPairs += RHS.NumPairs;
+ return *this;
+ }
+
+ void merge(const MCDCCoverageInfo &RHS) {
+ CoveredPairs = std::max(CoveredPairs, RHS.CoveredPairs);
+ NumPairs = std::max(NumPairs, RHS.NumPairs);
+ }
+
+ size_t getCoveredPairs() const { return CoveredPairs; }
+
+ size_t getNumPairs() const { return NumPairs; }
+
+ bool isFullyCovered() const { return CoveredPairs == NumPairs; }
+
+ double getPercentCovered() const {
+ assert(CoveredPairs <= NumPairs && "Covered pairs over-counted");
+ if (NumPairs == 0)
+ return 0.0;
+ return double(CoveredPairs) / double(NumPairs) * 100.0;
+ }
+};
+
/// Provides information about function coverage for a file.
class FunctionCoverageInfo {
/// The number of functions that were executed.
@@ -189,6 +230,7 @@ struct FunctionCoverageSummary {
RegionCoverageInfo RegionCoverage;
LineCoverageInfo LineCoverage;
BranchCoverageInfo BranchCoverage;
+ MCDCCoverageInfo MCDCCoverage;
FunctionCoverageSummary(const std::string &Name)
: Name(Name), ExecutionCount(0) {}
@@ -196,10 +238,11 @@ struct FunctionCoverageSummary {
FunctionCoverageSummary(const std::string &Name, uint64_t ExecutionCount,
const RegionCoverageInfo &RegionCoverage,
const LineCoverageInfo &LineCoverage,
- const BranchCoverageInfo &BranchCoverage)
+ const BranchCoverageInfo &BranchCoverage,
+ const MCDCCoverageInfo &MCDCCoverage)
: Name(Name), ExecutionCount(ExecutionCount),
RegionCoverage(RegionCoverage), LineCoverage(LineCoverage),
- BranchCoverage(BranchCoverage) {}
+ BranchCoverage(BranchCoverage), MCDCCoverage(MCDCCoverage) {}
/// Compute the code coverage summary for the given function coverage
/// mapping record.
@@ -219,6 +262,7 @@ struct FileCoverageSummary {
RegionCoverageInfo RegionCoverage;
LineCoverageInfo LineCoverage;
BranchCoverageInfo BranchCoverage;
+ MCDCCoverageInfo MCDCCoverage;
FunctionCoverageInfo FunctionCoverage;
FunctionCoverageInfo InstantiationCoverage;
@@ -230,6 +274,7 @@ struct FileCoverageSummary {
LineCoverage += RHS.LineCoverage;
FunctionCoverage += RHS.FunctionCoverage;
BranchCoverage += RHS.BranchCoverage;
+ MCDCCoverage += RHS.MCDCCoverage;
InstantiationCoverage += RHS.InstantiationCoverage;
return *this;
}
@@ -238,6 +283,7 @@ struct FileCoverageSummary {
RegionCoverage += Function.RegionCoverage;
LineCoverage += Function.LineCoverage;
BranchCoverage += Function.BranchCoverage;
+ MCDCCoverage += Function.MCDCCoverage;
FunctionCoverage.addFunction(/*Covered=*/Function.ExecutionCount > 0);
}
diff --git a/llvm/tools/llvm-cov/CoverageViewOptions.h b/llvm/tools/llvm-cov/CoverageViewOptions.h
index eb852859..6925cff 100644
--- a/llvm/tools/llvm-cov/CoverageViewOptions.h
+++ b/llvm/tools/llvm-cov/CoverageViewOptions.h
@@ -30,12 +30,14 @@ struct CoverageViewOptions {
bool ShowLineNumbers;
bool ShowLineStats;
bool ShowRegionMarkers;
+ bool ShowMCDC;
bool ShowBranchCounts;
bool ShowBranchPercents;
bool ShowExpandedRegions;
bool ShowFunctionInstantiations;
bool ShowFullFilenames;
bool ShowBranchSummary;
+ bool ShowMCDCSummary;
bool ShowRegionSummary;
bool ShowInstantiationSummary;
bool ShowDirectoryCoverage;
diff --git a/llvm/tools/llvm-cov/SourceCoverageView.cpp b/llvm/tools/llvm-cov/SourceCoverageView.cpp
index 7480b7f..c910edd 100644
--- a/llvm/tools/llvm-cov/SourceCoverageView.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageView.cpp
@@ -178,6 +178,12 @@ void SourceCoverageView::addBranch(unsigned Line,
BranchSubViews.emplace_back(Line, Regions, std::move(View));
}
+void SourceCoverageView::addMCDCRecord(
+ unsigned Line, ArrayRef<MCDCRecord> Records,
+ std::unique_ptr<SourceCoverageView> View) {
+ MCDCSubViews.emplace_back(Line, Records, std::move(View));
+}
+
void SourceCoverageView::addInstantiation(
StringRef FunctionName, unsigned Line,
std::unique_ptr<SourceCoverageView> View) {
@@ -203,12 +209,15 @@ void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
llvm::stable_sort(ExpansionSubViews);
llvm::stable_sort(InstantiationSubViews);
llvm::stable_sort(BranchSubViews);
+ llvm::stable_sort(MCDCSubViews);
auto NextESV = ExpansionSubViews.begin();
auto EndESV = ExpansionSubViews.end();
auto NextISV = InstantiationSubViews.begin();
auto EndISV = InstantiationSubViews.end();
auto NextBRV = BranchSubViews.begin();
auto EndBRV = BranchSubViews.end();
+ auto NextMSV = MCDCSubViews.begin();
+ auto EndMSV = MCDCSubViews.end();
// Get the coverage information for the file.
auto StartSegment = CoverageInfo.begin();
@@ -276,6 +285,11 @@ void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
renderBranchView(OS, *NextBRV, ViewDepth + 1);
RenderedSubView = true;
}
+ for (; NextMSV != EndMSV && NextMSV->Line == LI.line_number(); ++NextMSV) {
+ renderViewDivider(OS, ViewDepth + 1);
+ renderMCDCView(OS, *NextMSV, 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 c07595f..2e3fa8e 100644
--- a/llvm/tools/llvm-cov/SourceCoverageView.h
+++ b/llvm/tools/llvm-cov/SourceCoverageView.h
@@ -84,6 +84,23 @@ struct BranchView {
}
};
+/// A view that represents one or more MCDC regions on a given source line.
+struct MCDCView {
+ std::vector<MCDCRecord> Records;
+ std::unique_ptr<SourceCoverageView> View;
+ unsigned Line;
+
+ MCDCView(unsigned Line, ArrayRef<MCDCRecord> Records,
+ std::unique_ptr<SourceCoverageView> View)
+ : Records(Records), View(std::move(View)), Line(Line) {}
+
+ unsigned getLine() const { return Line; }
+
+ friend bool operator<(const MCDCView &LHS, const MCDCView &RHS) {
+ return LHS.Line < RHS.Line;
+ }
+};
+
/// A file manager that handles format-aware file creation.
class CoveragePrinter {
public:
@@ -160,6 +177,9 @@ class SourceCoverageView {
/// A container for all branches in the source on display.
std::vector<BranchView> BranchSubViews;
+ /// A container for all MCDC records in the source on display.
+ std::vector<MCDCView> MCDCSubViews;
+
/// A container for all instantiations (e.g template functions) in the source
/// on display.
std::vector<InstantiationView> InstantiationSubViews;
@@ -233,6 +253,10 @@ protected:
virtual void renderBranchView(raw_ostream &OS, BranchView &BRV,
unsigned ViewDepth) = 0;
+ /// Render an MCDC view.
+ virtual void renderMCDCView(raw_ostream &OS, MCDCView &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;
@@ -283,6 +307,10 @@ public:
void addBranch(unsigned Line, ArrayRef<CountedRegion> Regions,
std::unique_ptr<SourceCoverageView> View);
+ /// Add an MCDC subview to this view.
+ void addMCDCRecord(unsigned Line, ArrayRef<MCDCRecord> Records,
+ 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 79a0494..28c221d 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
@@ -335,6 +335,10 @@ void emitTableRow(raw_ostream &OS, const CoverageViewOptions &Opts,
AddCoverageTripleToColumn(FCS.BranchCoverage.getCovered(),
FCS.BranchCoverage.getNumBranches(),
FCS.BranchCoverage.getPercentCovered());
+ if (Opts.ShowMCDCSummary)
+ AddCoverageTripleToColumn(FCS.MCDCCoverage.getCoveredPairs(),
+ FCS.MCDCCoverage.getNumPairs(),
+ FCS.MCDCCoverage.getPercentCovered());
if (IsTotals)
OS << tag("tr", join(Columns.begin(), Columns.end(), ""), "light-row-bold");
@@ -385,6 +389,8 @@ static void emitColumnLabelsForIndex(raw_ostream &OS,
Columns.emplace_back(tag("td", "Region Coverage", "column-entry-bold"));
if (Opts.ShowBranchSummary)
Columns.emplace_back(tag("td", "Branch Coverage", "column-entry-bold"));
+ if (Opts.ShowMCDCSummary)
+ Columns.emplace_back(tag("td", "MC/DC", "column-entry-bold"));
OS << tag("tr", join(Columns.begin(), Columns.end(), ""));
}
@@ -955,6 +961,52 @@ void SourceCoverageViewHTML::renderBranchView(raw_ostream &OS, BranchView &BRV,
OS << EndExpansionDiv;
}
+void SourceCoverageViewHTML::renderMCDCView(raw_ostream &OS, MCDCView &MRV,
+ unsigned ViewDepth) {
+ for (auto &Record : MRV.Records) {
+ OS << BeginExpansionDiv;
+ OS << BeginPre;
+ OS << " MC/DC Decision Region (";
+
+ // Display Line + Column information.
+ const CounterMappingRegion &DecisionRegion = Record.getDecisionRegion();
+ std::string LineNoStr = utostr(uint64_t(DecisionRegion.LineStart));
+ std::string ColNoStr = utostr(uint64_t(DecisionRegion.ColumnStart));
+ std::string TargetName = "L" + LineNoStr;
+ OS << tag("span",
+ a("#" + TargetName, tag("span", LineNoStr + ":" + ColNoStr),
+ TargetName),
+ "line-number") +
+ ") to (";
+ LineNoStr = utostr(uint64_t(DecisionRegion.LineEnd));
+ ColNoStr = utostr(uint64_t(DecisionRegion.ColumnEnd));
+ OS << tag("span",
+ a("#" + TargetName, tag("span", LineNoStr + ":" + ColNoStr),
+ TargetName),
+ "line-number") +
+ ")\n\n";
+
+ // Display MC/DC Information.
+ OS << " Number of Conditions: " << Record.getNumConditions() << "\n";
+ for (unsigned i = 0; i < Record.getNumConditions(); i++) {
+ OS << " " << Record.getConditionHeaderString(i);
+ }
+ OS << "\n";
+ OS << " Executed MC/DC Test Vectors:\n\n ";
+ OS << Record.getTestVectorHeaderString();
+ for (unsigned i = 0; i < Record.getNumTestVectors(); i++)
+ OS << Record.getTestVectorString(i);
+ OS << "\n";
+ for (unsigned i = 0; i < Record.getNumConditions(); i++)
+ OS << Record.getConditionCoverageString(i);
+ OS << " MC/DC Coverage for Expression: ";
+ OS << format("%0.2f", Record.getPercentCovered()) << "%\n";
+ OS << EndPre;
+ OS << EndExpansionDiv;
+ }
+ return;
+}
+
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 c846379..7b97f05 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
+++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
@@ -91,6 +91,9 @@ class SourceCoverageViewHTML : public SourceCoverageView {
void renderBranchView(raw_ostream &OS, BranchView &BRV,
unsigned ViewDepth) override;
+ void renderMCDCView(raw_ostream &OS, MCDCView &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 44694a0..73b7ffe 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
@@ -337,6 +337,57 @@ void SourceCoverageViewText::renderBranchView(raw_ostream &OS, BranchView &BRV,
}
}
+void SourceCoverageViewText::renderMCDCView(raw_ostream &OS, MCDCView &MRV,
+ unsigned ViewDepth) {
+ for (auto &Record : MRV.Records) {
+ renderLinePrefix(OS, ViewDepth);
+ OS << "---> MC/DC Decision Region (";
+ // Display Line + Column information.
+ const CounterMappingRegion &DecisionRegion = Record.getDecisionRegion();
+ OS << DecisionRegion.LineStart << ":";
+ OS << DecisionRegion.ColumnStart << ") to (";
+ OS << DecisionRegion.LineEnd << ":";
+ OS << DecisionRegion.ColumnEnd << ")\n";
+ renderLinePrefix(OS, ViewDepth);
+ OS << "\n";
+
+ // Display MC/DC Information.
+ renderLinePrefix(OS, ViewDepth);
+ OS << " Number of Conditions: " << Record.getNumConditions() << "\n";
+ for (unsigned i = 0; i < Record.getNumConditions(); i++) {
+ renderLinePrefix(OS, ViewDepth);
+ OS << " " << Record.getConditionHeaderString(i);
+ }
+ renderLinePrefix(OS, ViewDepth);
+ OS << "\n";
+ renderLinePrefix(OS, ViewDepth);
+ OS << " Executed MC/DC Test Vectors:\n";
+ renderLinePrefix(OS, ViewDepth);
+ OS << "\n";
+ renderLinePrefix(OS, ViewDepth);
+ OS << " ";
+ OS << Record.getTestVectorHeaderString();
+ for (unsigned i = 0; i < Record.getNumTestVectors(); i++) {
+ renderLinePrefix(OS, ViewDepth);
+ OS << Record.getTestVectorString(i);
+ }
+ renderLinePrefix(OS, ViewDepth);
+ OS << "\n";
+ for (unsigned i = 0; i < Record.getNumConditions(); i++) {
+ renderLinePrefix(OS, ViewDepth);
+ OS << Record.getConditionCoverageString(i);
+ }
+ renderLinePrefix(OS, ViewDepth);
+ OS << " MC/DC Coverage for Decision: ";
+ colored_ostream(OS, raw_ostream::RED,
+ getOptions().Colors && Record.getPercentCovered() < 100.0,
+ /*Bold=*/false, /*BG=*/true)
+ << format("%0.2f", Record.getPercentCovered()) << "%\n";
+ renderLinePrefix(OS, ViewDepth);
+ 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 ade47ed..7cb47fc 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewText.h
+++ b/llvm/tools/llvm-cov/SourceCoverageViewText.h
@@ -77,6 +77,9 @@ class SourceCoverageViewText : public SourceCoverageView {
void renderBranchView(raw_ostream &OS, BranchView &BRV,
unsigned ViewDepth) override;
+ void renderMCDCView(raw_ostream &OS, MCDCView &BRV,
+ unsigned ViewDepth) override;
+
void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV,
unsigned ViewDepth) override;