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 | |