diff options
author | Alan Phipps <a-phipps@ti.com> | 2023-09-18 15:49:56 -0500 |
---|---|---|
committer | Alan Phipps <a-phipps@ti.com> | 2023-09-20 15:30:47 -0500 |
commit | 618a22144db5e45da8c95dc22064103e1b5e5b71 (patch) | |
tree | 3d354382909b78f7293bbce1e6e00351b6ff59c6 /llvm/tools | |
parent | 33dfd90700a11fb39802d0b1ab500f3a8efd7e78 (diff) | |
download | llvm-618a22144db5e45da8c95dc22064103e1b5e5b71.zip llvm-618a22144db5e45da8c95dc22064103e1b5e5b71.tar.gz llvm-618a22144db5e45da8c95dc22064103e1b5e5b71.tar.bz2 |
[Coverage][llvm-cov] Enable MC/DC Support in LLVM Source-based Code Coverage (2/3)
Part 2 of 3. This includes the Visualization and Evaluation components.
Differential Revision: https://reviews.llvm.org/D138847
Diffstat (limited to 'llvm/tools')
-rw-r--r-- | llvm/tools/llvm-cov/CodeCoverage.cpp | 55 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/CoverageExporterJson.cpp | 44 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/CoverageReport.cpp | 47 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/CoverageSummaryInfo.cpp | 19 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/CoverageSummaryInfo.h | 50 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/CoverageViewOptions.h | 2 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/SourceCoverageView.cpp | 14 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/SourceCoverageView.h | 28 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp | 52 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/SourceCoverageViewHTML.h | 3 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/SourceCoverageViewText.cpp | 51 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/SourceCoverageViewText.h | 3 |
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; |