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(Covered, RHS.Covered);
46     NumRegions = std::max(NumRegions, 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(Covered, RHS.Covered);
87     NumLines = std::max(NumLines, 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(Covered, RHS.Covered);
128     NumBranches = std::max(NumBranches, 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(CoveredPairs, RHS.CoveredPairs);
169     NumPairs = std::max(NumPairs, 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=*/Function.ExecutionCount > 0);
288   }
289 
290   void addInstantiation(const FunctionCoverageSummary &Function) {
291     InstantiationCoverage.addFunction(/*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(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