1 | //===- CoverageSummaryInfo.h - 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 | #ifndef LLVM_COV_COVERAGESUMMARYINFO_H |
15 | #define LLVM_COV_COVERAGESUMMARYINFO_H |
16 | |
17 | #include "llvm/ProfileData/Coverage/CoverageMapping.h" |
18 | #include "llvm/Support/raw_ostream.h" |
19 | |
20 | namespace llvm { |
21 | |
22 | /// Provides information about region coverage for a function/file. |
23 | class RegionCoverageInfo { |
24 | /// The number of regions that were executed at least once. |
25 | size_t Covered; |
26 | |
27 | /// The total number of regions in a function/file. |
28 | size_t NumRegions; |
29 | |
30 | public: |
31 | RegionCoverageInfo() : Covered(0), NumRegions(0) {} |
32 | |
33 | RegionCoverageInfo(size_t Covered, size_t NumRegions) |
34 | : Covered(Covered), NumRegions(NumRegions) { |
35 | assert(Covered <= NumRegions && "Covered regions over-counted" ); |
36 | } |
37 | |
38 | RegionCoverageInfo &operator+=(const RegionCoverageInfo &RHS) { |
39 | Covered += RHS.Covered; |
40 | NumRegions += RHS.NumRegions; |
41 | return *this; |
42 | } |
43 | |
44 | void merge(const RegionCoverageInfo &RHS) { |
45 | Covered = std::max(a: Covered, b: RHS.Covered); |
46 | NumRegions = std::max(a: NumRegions, b: RHS.NumRegions); |
47 | } |
48 | |
49 | size_t getCovered() const { return Covered; } |
50 | |
51 | size_t getNumRegions() const { return NumRegions; } |
52 | |
53 | bool isFullyCovered() const { return Covered == NumRegions; } |
54 | |
55 | double getPercentCovered() const { |
56 | assert(Covered <= NumRegions && "Covered regions over-counted" ); |
57 | if (NumRegions == 0) |
58 | return 0.0; |
59 | return double(Covered) / double(NumRegions) * 100.0; |
60 | } |
61 | }; |
62 | |
63 | /// Provides information about line coverage for a function/file. |
64 | class LineCoverageInfo { |
65 | /// The number of lines that were executed at least once. |
66 | size_t Covered; |
67 | |
68 | /// The total number of lines in a function/file. |
69 | size_t NumLines; |
70 | |
71 | public: |
72 | LineCoverageInfo() : Covered(0), NumLines(0) {} |
73 | |
74 | LineCoverageInfo(size_t Covered, size_t NumLines) |
75 | : Covered(Covered), NumLines(NumLines) { |
76 | assert(Covered <= NumLines && "Covered lines over-counted" ); |
77 | } |
78 | |
79 | LineCoverageInfo &operator+=(const LineCoverageInfo &RHS) { |
80 | Covered += RHS.Covered; |
81 | NumLines += RHS.NumLines; |
82 | return *this; |
83 | } |
84 | |
85 | void merge(const LineCoverageInfo &RHS) { |
86 | Covered = std::max(a: Covered, b: RHS.Covered); |
87 | NumLines = std::max(a: NumLines, b: RHS.NumLines); |
88 | } |
89 | |
90 | size_t getCovered() const { return Covered; } |
91 | |
92 | size_t getNumLines() const { return NumLines; } |
93 | |
94 | bool isFullyCovered() const { return Covered == NumLines; } |
95 | |
96 | double getPercentCovered() const { |
97 | assert(Covered <= NumLines && "Covered lines over-counted" ); |
98 | if (NumLines == 0) |
99 | return 0.0; |
100 | return double(Covered) / double(NumLines) * 100.0; |
101 | } |
102 | }; |
103 | |
104 | /// Provides information about branches coverage for a function/file. |
105 | class BranchCoverageInfo { |
106 | /// The number of branches that were executed at least once. |
107 | size_t Covered; |
108 | |
109 | /// The total number of branches in a function/file. |
110 | size_t NumBranches; |
111 | |
112 | public: |
113 | BranchCoverageInfo() : Covered(0), NumBranches(0) {} |
114 | |
115 | BranchCoverageInfo(size_t Covered, size_t NumBranches) |
116 | : Covered(Covered), NumBranches(NumBranches) { |
117 | assert(Covered <= NumBranches && "Covered branches over-counted" ); |
118 | } |
119 | |
120 | BranchCoverageInfo &operator+=(const BranchCoverageInfo &RHS) { |
121 | Covered += RHS.Covered; |
122 | NumBranches += RHS.NumBranches; |
123 | return *this; |
124 | } |
125 | |
126 | void merge(const BranchCoverageInfo &RHS) { |
127 | Covered = std::max(a: Covered, b: RHS.Covered); |
128 | NumBranches = std::max(a: NumBranches, b: RHS.NumBranches); |
129 | } |
130 | |
131 | size_t getCovered() const { return Covered; } |
132 | |
133 | size_t getNumBranches() const { return NumBranches; } |
134 | |
135 | bool isFullyCovered() const { return Covered == NumBranches; } |
136 | |
137 | double getPercentCovered() const { |
138 | assert(Covered <= NumBranches && "Covered branches over-counted" ); |
139 | if (NumBranches == 0) |
140 | return 0.0; |
141 | return double(Covered) / double(NumBranches) * 100.0; |
142 | } |
143 | }; |
144 | |
145 | /// Provides information about MC/DC coverage for a function/file. |
146 | class MCDCCoverageInfo { |
147 | /// The number of Independence Pairs that were covered. |
148 | size_t CoveredPairs; |
149 | |
150 | /// The total number of Independence Pairs in a function/file. |
151 | size_t NumPairs; |
152 | |
153 | public: |
154 | MCDCCoverageInfo() : CoveredPairs(0), NumPairs(0) {} |
155 | |
156 | MCDCCoverageInfo(size_t CoveredPairs, size_t NumPairs) |
157 | : CoveredPairs(CoveredPairs), NumPairs(NumPairs) { |
158 | assert(CoveredPairs <= NumPairs && "Covered pairs over-counted" ); |
159 | } |
160 | |
161 | MCDCCoverageInfo &operator+=(const MCDCCoverageInfo &RHS) { |
162 | CoveredPairs += RHS.CoveredPairs; |
163 | NumPairs += RHS.NumPairs; |
164 | return *this; |
165 | } |
166 | |
167 | void merge(const MCDCCoverageInfo &RHS) { |
168 | CoveredPairs = std::max(a: CoveredPairs, b: RHS.CoveredPairs); |
169 | NumPairs = std::max(a: NumPairs, b: RHS.NumPairs); |
170 | } |
171 | |
172 | size_t getCoveredPairs() const { return CoveredPairs; } |
173 | |
174 | size_t getNumPairs() const { return NumPairs; } |
175 | |
176 | bool isFullyCovered() const { return CoveredPairs == NumPairs; } |
177 | |
178 | double getPercentCovered() const { |
179 | assert(CoveredPairs <= NumPairs && "Covered pairs over-counted" ); |
180 | if (NumPairs == 0) |
181 | return 0.0; |
182 | return double(CoveredPairs) / double(NumPairs) * 100.0; |
183 | } |
184 | }; |
185 | |
186 | /// Provides information about function coverage for a file. |
187 | class FunctionCoverageInfo { |
188 | /// The number of functions that were executed. |
189 | size_t Executed; |
190 | |
191 | /// The total number of functions in this file. |
192 | size_t NumFunctions; |
193 | |
194 | public: |
195 | FunctionCoverageInfo() : Executed(0), NumFunctions(0) {} |
196 | |
197 | FunctionCoverageInfo(size_t Executed, size_t NumFunctions) |
198 | : Executed(Executed), NumFunctions(NumFunctions) {} |
199 | |
200 | FunctionCoverageInfo &operator+=(const FunctionCoverageInfo &RHS) { |
201 | Executed += RHS.Executed; |
202 | NumFunctions += RHS.NumFunctions; |
203 | return *this; |
204 | } |
205 | |
206 | void addFunction(bool Covered) { |
207 | if (Covered) |
208 | ++Executed; |
209 | ++NumFunctions; |
210 | } |
211 | |
212 | size_t getExecuted() const { return Executed; } |
213 | |
214 | size_t getNumFunctions() const { return NumFunctions; } |
215 | |
216 | bool isFullyCovered() const { return Executed == NumFunctions; } |
217 | |
218 | double getPercentCovered() const { |
219 | assert(Executed <= NumFunctions && "Covered functions over-counted" ); |
220 | if (NumFunctions == 0) |
221 | return 0.0; |
222 | return double(Executed) / double(NumFunctions) * 100.0; |
223 | } |
224 | }; |
225 | |
226 | /// A summary of function's code coverage. |
227 | struct FunctionCoverageSummary { |
228 | std::string Name; |
229 | uint64_t ExecutionCount; |
230 | RegionCoverageInfo RegionCoverage; |
231 | LineCoverageInfo LineCoverage; |
232 | BranchCoverageInfo BranchCoverage; |
233 | MCDCCoverageInfo MCDCCoverage; |
234 | |
235 | FunctionCoverageSummary(const std::string &Name) |
236 | : Name(Name), ExecutionCount(0) {} |
237 | |
238 | FunctionCoverageSummary(const std::string &Name, uint64_t ExecutionCount, |
239 | const RegionCoverageInfo &RegionCoverage, |
240 | const LineCoverageInfo &LineCoverage, |
241 | const BranchCoverageInfo &BranchCoverage, |
242 | const MCDCCoverageInfo &MCDCCoverage) |
243 | : Name(Name), ExecutionCount(ExecutionCount), |
244 | RegionCoverage(RegionCoverage), LineCoverage(LineCoverage), |
245 | BranchCoverage(BranchCoverage), MCDCCoverage(MCDCCoverage) {} |
246 | |
247 | /// Compute the code coverage summary for the given function coverage |
248 | /// mapping record. |
249 | static FunctionCoverageSummary get(const coverage::CoverageMapping &CM, |
250 | const coverage::FunctionRecord &Function); |
251 | |
252 | /// Compute the code coverage summary for an instantiation group \p Group, |
253 | /// given a list of summaries for each instantiation in \p Summaries. |
254 | static FunctionCoverageSummary |
255 | get(const coverage::InstantiationGroup &Group, |
256 | ArrayRef<FunctionCoverageSummary> Summaries); |
257 | }; |
258 | |
259 | /// A summary of file's code coverage. |
260 | struct FileCoverageSummary { |
261 | StringRef Name; |
262 | RegionCoverageInfo RegionCoverage; |
263 | LineCoverageInfo LineCoverage; |
264 | BranchCoverageInfo BranchCoverage; |
265 | MCDCCoverageInfo MCDCCoverage; |
266 | FunctionCoverageInfo FunctionCoverage; |
267 | FunctionCoverageInfo InstantiationCoverage; |
268 | |
269 | FileCoverageSummary() = default; |
270 | FileCoverageSummary(StringRef Name) : Name(Name) {} |
271 | |
272 | FileCoverageSummary &operator+=(const FileCoverageSummary &RHS) { |
273 | RegionCoverage += RHS.RegionCoverage; |
274 | LineCoverage += RHS.LineCoverage; |
275 | FunctionCoverage += RHS.FunctionCoverage; |
276 | BranchCoverage += RHS.BranchCoverage; |
277 | MCDCCoverage += RHS.MCDCCoverage; |
278 | InstantiationCoverage += RHS.InstantiationCoverage; |
279 | return *this; |
280 | } |
281 | |
282 | void addFunction(const FunctionCoverageSummary &Function) { |
283 | RegionCoverage += Function.RegionCoverage; |
284 | LineCoverage += Function.LineCoverage; |
285 | BranchCoverage += Function.BranchCoverage; |
286 | MCDCCoverage += Function.MCDCCoverage; |
287 | FunctionCoverage.addFunction(/*Covered=*/Covered: Function.ExecutionCount > 0); |
288 | } |
289 | |
290 | void addInstantiation(const FunctionCoverageSummary &Function) { |
291 | InstantiationCoverage.addFunction(/*Covered=*/Covered: Function.ExecutionCount > 0); |
292 | } |
293 | }; |
294 | |
295 | /// A cache for demangled symbols. |
296 | struct DemangleCache { |
297 | StringMap<std::string> DemangledNames; |
298 | |
299 | /// Demangle \p Sym if possible. Otherwise, just return \p Sym. |
300 | StringRef demangle(StringRef Sym) const { |
301 | const auto DemangledName = DemangledNames.find(Key: Sym); |
302 | if (DemangledName == DemangledNames.end()) |
303 | return Sym; |
304 | return DemangledName->getValue(); |
305 | } |
306 | }; |
307 | |
308 | } // namespace llvm |
309 | |
310 | #endif // LLVM_COV_COVERAGESUMMARYINFO_H |
311 | |