Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ CHECK-SAME: "mcdc":{"count":0,"covered":0,"notcovered":0,"percent":0},
CHECK-SAME: "regions":{"count":1,"covered":1,"notcovered":0,"percent":100}}}
CHECK-SAME: ],
CHECK-SAME: "type":"llvm.coverage.json.export"
CHECK-SAME: "version":"3.0.1"
CHECK-SAME: "version":"3.1.0"
8 changes: 4 additions & 4 deletions llvm/test/tools/llvm-cov/mcdc-export-json.test
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// RUN: llvm-profdata merge %S/Inputs/mcdc-general.proftext -o %t.profdata
// RUN: llvm-cov export --format=text %S/Inputs/mcdc-general.o -instr-profile %t.profdata | FileCheck %s

// CHECK: 12,7,12,27,2,4,0,0,5,[true,true,true,true]
// CHECK: 15,7,15,13,1,2,0,0,5,[true,true]
// CHECK: 15,19,15,25,1,1,0,0,5,[true,false]
// CHECK: 18,7,19,15,1,3,0,0,5,[true,true,false,true]
// CHECK: 12,7,12,27,2,4,0,0,5,[true,true,true,true],[{"conditions":[false,null,false,null],"executed":true,"result":false},{"conditions":[false,null,true,false],"executed":true,"result":false},{"conditions":[true,false,false,null],"executed":true,"result":false},{"conditions":[true,false,true,false],"executed":true,"result":false},{"conditions":[true,false,true,true],"executed":true,"result":true},{"conditions":[true,true,null,null],"executed":true,"result":true}]
// CHECK: 15,7,15,13,1,2,0,0,5,[true,true],[{"conditions":[false,null],"executed":true,"result":false},{"conditions":[true,false],"executed":true,"result":false},{"conditions":[true,true],"executed":true,"result":true}]
// CHECK: 15,19,15,25,1,1,0,0,5,[true,false],[{"conditions":[false,null],"executed":true,"result":false},{"conditions":[true,true],"executed":true,"result":true}]
// CHECK: 18,7,19,15,1,3,0,0,5,[true,true,false,true],[{"conditions":[false,null,null,null],"executed":true,"result":false},{"conditions":[true,false,null,null],"executed":true,"result":false},{"conditions":[true,true,true,false],"executed":true,"result":false},{"conditions":[true,true,true,true],"executed":true,"result":true}]
// CHECK: "mcdc":{"count":12,"covered":10,"notcovered":2,"percent":83.333333333333343}

Instructions for regenerating the test:
Expand Down
63 changes: 44 additions & 19 deletions llvm/tools/llvm-cov/CoverageExporterJson.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
// -- 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
// -- MCDC Values: array => List of T/F covered condition values and
// list of executed test vectors
// -- 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
Expand Down Expand Up @@ -62,7 +63,7 @@
#include <utility>

/// The semantic version combined as a string.
#define LLVM_COVERAGE_EXPORT_JSON_STR "3.0.1"
#define LLVM_COVERAGE_EXPORT_JSON_STR "3.1.0"

/// Unique type identifier for JSON coverage export.
#define LLVM_COVERAGE_EXPORT_JSON_TYPE_STR "llvm.coverage.json.export"
Expand Down Expand Up @@ -108,13 +109,42 @@ json::Array gatherConditions(const coverage::MCDCRecord &Record) {
return Conditions;
}

json::Value renderCondState(const coverage::MCDCRecord::CondState CondState) {
switch (CondState) {
case coverage::MCDCRecord::MCDC_DontCare:
return json::Value(nullptr);
case coverage::MCDCRecord::MCDC_True:
return json::Value(true);
case coverage::MCDCRecord::MCDC_False:
return json::Value(false);
}
}

json::Array gatherTestVectors(coverage::MCDCRecord &Record) {
json::Array TestVectors;
unsigned NumConditions = Record.getNumConditions();
for (unsigned tv = 0; tv < Record.getNumTestVectors(); tv++) {

json::Array TVConditions;
for (unsigned c = 0; c < NumConditions; c++)
TVConditions.push_back(renderCondState(Record.getTVCondition(tv, c)));

TestVectors.push_back(
json::Object({{"executed", json::Value(true)},
{"result", renderCondState(Record.getTVResult(tv))},
{"conditions", std::move(TVConditions)}}));
}
return TestVectors;
}

json::Array renderMCDCRecord(const coverage::MCDCRecord &Record) {
const llvm::coverage::CounterMappingRegion &CMR = Record.getDecisionRegion();
const auto [TrueDecisions, FalseDecisions] = Record.getDecisions();
return json::Array({CMR.LineStart, CMR.ColumnStart, CMR.LineEnd,
CMR.ColumnEnd, TrueDecisions, FalseDecisions,
CMR.FileID, CMR.ExpandedFileID, int64_t(CMR.Kind),
gatherConditions(Record)});
return json::Array(
{CMR.LineStart, CMR.ColumnStart, CMR.LineEnd, CMR.ColumnEnd,
TrueDecisions, FalseDecisions, CMR.FileID, CMR.ExpandedFileID,
int64_t(CMR.Kind), gatherConditions(Record),
gatherTestVectors(const_cast<coverage::MCDCRecord &>(Record))});
}

json::Array renderRegions(ArrayRef<coverage::CountedRegion> Regions) {
Expand Down Expand Up @@ -216,32 +246,28 @@ json::Object renderSummary(const FileCoverageSummary &Summary) {
}

json::Array renderFileExpansions(const coverage::CoverageMapping &Coverage,
const coverage::CoverageData &FileCoverage,
const FileCoverageSummary &FileReport) {
const coverage::CoverageData &FileCoverage) {
json::Array ExpansionArray;
for (const auto &Expansion : FileCoverage.getExpansions())
ExpansionArray.push_back(renderExpansion(Coverage, Expansion));
return ExpansionArray;
}

json::Array renderFileSegments(const coverage::CoverageData &FileCoverage,
const FileCoverageSummary &FileReport) {
json::Array renderFileSegments(const coverage::CoverageData &FileCoverage) {
json::Array SegmentArray;
for (const auto &Segment : FileCoverage)
SegmentArray.push_back(renderSegment(Segment));
return SegmentArray;
}

json::Array renderFileBranches(const coverage::CoverageData &FileCoverage,
const FileCoverageSummary &FileReport) {
json::Array renderFileBranches(const coverage::CoverageData &FileCoverage) {
json::Array BranchArray;
for (const auto &Branch : FileCoverage.getBranches())
BranchArray.push_back(renderBranch(Branch));
return BranchArray;
}

json::Array renderFileMCDC(const coverage::CoverageData &FileCoverage,
const FileCoverageSummary &FileReport) {
json::Array renderFileMCDC(const coverage::CoverageData &FileCoverage) {
json::Array MCDCRecordArray;
for (const auto &Record : FileCoverage.getMCDCRecords())
MCDCRecordArray.push_back(renderMCDCRecord(Record));
Expand All @@ -256,12 +282,11 @@ json::Object renderFile(const coverage::CoverageMapping &Coverage,
if (!Options.ExportSummaryOnly) {
// Calculate and render detailed coverage information for given file.
auto FileCoverage = Coverage.getCoverageForFile(Filename);
File["segments"] = renderFileSegments(FileCoverage, FileReport);
File["branches"] = renderFileBranches(FileCoverage, FileReport);
File["mcdc_records"] = renderFileMCDC(FileCoverage, FileReport);
File["segments"] = renderFileSegments(FileCoverage);
File["branches"] = renderFileBranches(FileCoverage);
File["mcdc_records"] = renderFileMCDC(FileCoverage);
if (!Options.SkipExpansions) {
File["expansions"] =
renderFileExpansions(Coverage, FileCoverage, FileReport);
File["expansions"] = renderFileExpansions(Coverage, FileCoverage);
}
}
File["summary"] = renderSummary(FileReport);
Expand Down