| 1 | //===- CoverageSummaryInfo.cpp - Coverage summary for function/file -------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // These structures are used to represent code coverage metrics |
| 10 | // for functions/files. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "CoverageSummaryInfo.h" |
| 15 | |
| 16 | using namespace llvm; |
| 17 | using namespace coverage; |
| 18 | |
| 19 | static auto sumBranches(const ArrayRef<CountedRegion> &Branches) { |
| 20 | size_t NumBranches = 0; |
| 21 | size_t CoveredBranches = 0; |
| 22 | for (const auto &BR : Branches) { |
| 23 | if (!BR.TrueFolded) { |
| 24 | // "True" Condition Branches. |
| 25 | ++NumBranches; |
| 26 | if (BR.ExecutionCount > 0) |
| 27 | ++CoveredBranches; |
| 28 | } |
| 29 | if (!BR.FalseFolded) { |
| 30 | // "False" Condition Branches. |
| 31 | ++NumBranches; |
| 32 | if (BR.FalseExecutionCount > 0) |
| 33 | ++CoveredBranches; |
| 34 | } |
| 35 | } |
| 36 | return BranchCoverageInfo(CoveredBranches, NumBranches); |
| 37 | } |
| 38 | |
| 39 | static BranchCoverageInfo |
| 40 | sumBranchExpansions(const CoverageMapping &CM, |
| 41 | ArrayRef<ExpansionRecord> Expansions) { |
| 42 | BranchCoverageInfo BranchCoverage; |
| 43 | for (const auto &Expansion : Expansions) { |
| 44 | auto CE = CM.getCoverageForExpansion(Expansion); |
| 45 | BranchCoverage += sumBranches(Branches: CE.getBranches()); |
| 46 | BranchCoverage += sumBranchExpansions(CM, Expansions: CE.getExpansions()); |
| 47 | } |
| 48 | return BranchCoverage; |
| 49 | } |
| 50 | |
| 51 | auto sumMCDCPairs(const ArrayRef<MCDCRecord> &Records) { |
| 52 | size_t NumPairs = 0, CoveredPairs = 0; |
| 53 | for (const auto &Record : Records) { |
| 54 | const auto NumConditions = Record.getNumConditions(); |
| 55 | for (unsigned C = 0; C < NumConditions; C++) { |
| 56 | if (!Record.isCondFolded(Condition: C)) { |
| 57 | ++NumPairs; |
| 58 | if (Record.isConditionIndependencePairCovered(Condition: C)) |
| 59 | ++CoveredPairs; |
| 60 | } |
| 61 | } |
| 62 | } |
| 63 | return MCDCCoverageInfo(CoveredPairs, NumPairs); |
| 64 | } |
| 65 | |
| 66 | static std::pair<RegionCoverageInfo, LineCoverageInfo> |
| 67 | sumRegions(ArrayRef<CountedRegion> CodeRegions, const CoverageData &CD) { |
| 68 | // Compute the region coverage. |
| 69 | size_t NumCodeRegions = 0, CoveredRegions = 0; |
| 70 | for (auto &CR : CodeRegions) { |
| 71 | if (CR.Kind != CounterMappingRegion::CodeRegion) |
| 72 | continue; |
| 73 | ++NumCodeRegions; |
| 74 | if (CR.ExecutionCount != 0) |
| 75 | ++CoveredRegions; |
| 76 | } |
| 77 | |
| 78 | // Compute the line coverage |
| 79 | size_t NumLines = 0, CoveredLines = 0; |
| 80 | for (const auto &LCS : getLineCoverageStats(CD)) { |
| 81 | if (!LCS.isMapped()) |
| 82 | continue; |
| 83 | ++NumLines; |
| 84 | if (LCS.getExecutionCount()) |
| 85 | ++CoveredLines; |
| 86 | } |
| 87 | |
| 88 | return {RegionCoverageInfo(CoveredRegions, NumCodeRegions), |
| 89 | LineCoverageInfo(CoveredLines, NumLines)}; |
| 90 | } |
| 91 | |
| 92 | CoverageDataSummary::CoverageDataSummary(const CoverageData &CD, |
| 93 | ArrayRef<CountedRegion> CodeRegions) { |
| 94 | std::tie(args&: RegionCoverage, args&: LineCoverage) = sumRegions(CodeRegions, CD); |
| 95 | BranchCoverage = sumBranches(Branches: CD.getBranches()); |
| 96 | MCDCCoverage = sumMCDCPairs(Records: CD.getMCDCRecords()); |
| 97 | } |
| 98 | |
| 99 | FunctionCoverageSummary |
| 100 | FunctionCoverageSummary::get(const CoverageMapping &CM, |
| 101 | const coverage::FunctionRecord &Function) { |
| 102 | CoverageData CD = CM.getCoverageForFunction(Function); |
| 103 | |
| 104 | auto Summary = |
| 105 | FunctionCoverageSummary(Function.Name, Function.ExecutionCount); |
| 106 | |
| 107 | Summary += CoverageDataSummary(CD, Function.CountedRegions); |
| 108 | |
| 109 | // Compute the branch coverage, including branches from expansions. |
| 110 | Summary.BranchCoverage += sumBranchExpansions(CM, Expansions: CD.getExpansions()); |
| 111 | |
| 112 | return Summary; |
| 113 | } |
| 114 | |
| 115 | FunctionCoverageSummary |
| 116 | FunctionCoverageSummary::get(const InstantiationGroup &Group, |
| 117 | ArrayRef<FunctionCoverageSummary> Summaries) { |
| 118 | std::string Name; |
| 119 | if (Group.hasName()) { |
| 120 | Name = std::string(Group.getName()); |
| 121 | } else { |
| 122 | llvm::raw_string_ostream OS(Name); |
| 123 | OS << "Definition at line " << Group.getLine() << ", column " |
| 124 | << Group.getColumn(); |
| 125 | } |
| 126 | |
| 127 | FunctionCoverageSummary Summary(Name, Group.getTotalExecutionCount()); |
| 128 | Summary.RegionCoverage = Summaries[0].RegionCoverage; |
| 129 | Summary.LineCoverage = Summaries[0].LineCoverage; |
| 130 | Summary.BranchCoverage = Summaries[0].BranchCoverage; |
| 131 | Summary.MCDCCoverage = Summaries[0].MCDCCoverage; |
| 132 | for (const auto &FCS : Summaries.drop_front()) { |
| 133 | Summary.RegionCoverage.merge(RHS: FCS.RegionCoverage); |
| 134 | Summary.LineCoverage.merge(RHS: FCS.LineCoverage); |
| 135 | Summary.BranchCoverage.merge(RHS: FCS.BranchCoverage); |
| 136 | Summary.MCDCCoverage.merge(RHS: FCS.MCDCCoverage); |
| 137 | } |
| 138 | return Summary; |
| 139 | } |
| 140 | |