1 | //===- SourceCoverageView.h - Code coverage view for source code ----------===// |
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 | /// \file This class implements rendering for code coverage of source code. |
10 | /// |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_COV_SOURCECOVERAGEVIEW_H |
14 | #define LLVM_COV_SOURCECOVERAGEVIEW_H |
15 | |
16 | #include "CoverageViewOptions.h" |
17 | #include "CoverageSummaryInfo.h" |
18 | #include "llvm/ProfileData/Coverage/CoverageMapping.h" |
19 | #include "llvm/Support/MemoryBuffer.h" |
20 | #include <vector> |
21 | |
22 | namespace llvm { |
23 | |
24 | using namespace coverage; |
25 | |
26 | class CoverageFiltersMatchAll; |
27 | class SourceCoverageView; |
28 | |
29 | /// A view that represents a macro or include expansion. |
30 | struct ExpansionView { |
31 | CounterMappingRegion Region; |
32 | std::unique_ptr<SourceCoverageView> View; |
33 | |
34 | ExpansionView(const CounterMappingRegion &Region, |
35 | std::unique_ptr<SourceCoverageView> View) |
36 | : Region(Region), View(std::move(View)) {} |
37 | ExpansionView(ExpansionView &&RHS) |
38 | : Region(std::move(RHS.Region)), View(std::move(RHS.View)) {} |
39 | ExpansionView &operator=(ExpansionView &&RHS) { |
40 | Region = std::move(RHS.Region); |
41 | View = std::move(RHS.View); |
42 | return *this; |
43 | } |
44 | |
45 | unsigned getLine() const { return Region.LineStart; } |
46 | unsigned getStartCol() const { return Region.ColumnStart; } |
47 | unsigned getEndCol() const { return Region.ColumnEnd; } |
48 | |
49 | friend bool operator<(const ExpansionView &LHS, const ExpansionView &RHS) { |
50 | return LHS.Region.startLoc() < RHS.Region.startLoc(); |
51 | } |
52 | }; |
53 | |
54 | /// A view that represents a function instantiation. |
55 | struct InstantiationView { |
56 | StringRef FunctionName; |
57 | unsigned Line; |
58 | std::unique_ptr<SourceCoverageView> View; |
59 | |
60 | InstantiationView(StringRef FunctionName, unsigned Line, |
61 | std::unique_ptr<SourceCoverageView> View) |
62 | : FunctionName(FunctionName), Line(Line), View(std::move(View)) {} |
63 | |
64 | friend bool operator<(const InstantiationView &LHS, |
65 | const InstantiationView &RHS) { |
66 | return LHS.Line < RHS.Line; |
67 | } |
68 | }; |
69 | |
70 | /// A view that represents one or more branch regions on a given source line. |
71 | struct BranchView { |
72 | SmallVector<CountedRegion, 0> Regions; |
73 | std::unique_ptr<SourceCoverageView> View; |
74 | unsigned Line; |
75 | |
76 | BranchView(unsigned Line, SmallVector<CountedRegion, 0> Regions, |
77 | std::unique_ptr<SourceCoverageView> View) |
78 | : Regions(std::move(Regions)), View(std::move(View)), Line(Line) {} |
79 | |
80 | unsigned getLine() const { return Line; } |
81 | |
82 | friend bool operator<(const BranchView &LHS, const BranchView &RHS) { |
83 | return LHS.Line < RHS.Line; |
84 | } |
85 | }; |
86 | |
87 | /// A view that represents one or more MCDC regions on a given source line. |
88 | struct MCDCView { |
89 | SmallVector<MCDCRecord, 0> Records; |
90 | std::unique_ptr<SourceCoverageView> View; |
91 | unsigned Line; |
92 | |
93 | MCDCView(unsigned Line, SmallVector<MCDCRecord, 0> Records, |
94 | std::unique_ptr<SourceCoverageView> View) |
95 | : Records(std::move(Records)), View(std::move(View)), Line(Line) {} |
96 | |
97 | unsigned getLine() const { return Line; } |
98 | |
99 | friend bool operator<(const MCDCView &LHS, const MCDCView &RHS) { |
100 | return LHS.Line < RHS.Line; |
101 | } |
102 | }; |
103 | |
104 | /// A file manager that handles format-aware file creation. |
105 | class CoveragePrinter { |
106 | public: |
107 | struct StreamDestructor { |
108 | void operator()(raw_ostream *OS) const; |
109 | }; |
110 | |
111 | using OwnedStream = std::unique_ptr<raw_ostream, StreamDestructor>; |
112 | |
113 | protected: |
114 | const CoverageViewOptions &Opts; |
115 | |
116 | CoveragePrinter(const CoverageViewOptions &Opts) : Opts(Opts) {} |
117 | |
118 | /// Return `OutputDir/ToplevelDir/Path.Extension`. If \p InToplevel is |
119 | /// true, skip the ToplevelDir component. If \p Relative is true, skip the |
120 | /// OutputDir component. |
121 | std::string getOutputPath(StringRef Path, StringRef Extension, |
122 | bool InToplevel, bool Relative = true) const; |
123 | |
124 | /// If directory output is enabled, create a file in that directory |
125 | /// at the path given by getOutputPath(). Otherwise, return stdout. |
126 | Expected<OwnedStream> createOutputStream(StringRef Path, StringRef Extension, |
127 | bool InToplevel) const; |
128 | |
129 | /// Return the sub-directory name for file coverage reports. |
130 | static StringRef getCoverageDir() { return "coverage" ; } |
131 | |
132 | public: |
133 | static std::unique_ptr<CoveragePrinter> |
134 | create(const CoverageViewOptions &Opts); |
135 | |
136 | virtual ~CoveragePrinter() {} |
137 | |
138 | /// @name File Creation Interface |
139 | /// @{ |
140 | |
141 | /// Create a file to print a coverage view into. |
142 | virtual Expected<OwnedStream> createViewFile(StringRef Path, |
143 | bool InToplevel) = 0; |
144 | |
145 | /// Close a file which has been used to print a coverage view. |
146 | virtual void closeViewFile(OwnedStream OS) = 0; |
147 | |
148 | /// Create an index which lists reports for the given source files. |
149 | virtual Error createIndexFile(ArrayRef<std::string> SourceFiles, |
150 | const CoverageMapping &Coverage, |
151 | const CoverageFiltersMatchAll &Filters) = 0; |
152 | |
153 | /// @} |
154 | }; |
155 | |
156 | /// A code coverage view of a source file or function. |
157 | /// |
158 | /// A source coverage view and its nested sub-views form a file-oriented |
159 | /// representation of code coverage data. This view can be printed out by a |
160 | /// renderer which implements the Rendering Interface. |
161 | class SourceCoverageView { |
162 | /// A function or file name. |
163 | StringRef SourceName; |
164 | |
165 | /// A memory buffer backing the source on display. |
166 | const MemoryBuffer &File; |
167 | |
168 | /// Various options to guide the coverage renderer. |
169 | const CoverageViewOptions &Options; |
170 | |
171 | /// Complete coverage information about the source on display. |
172 | CoverageData CoverageInfo; |
173 | |
174 | /// A container for all expansions (e.g macros) in the source on display. |
175 | std::vector<ExpansionView> ExpansionSubViews; |
176 | |
177 | /// A container for all branches in the source on display. |
178 | SmallVector<BranchView, 0> BranchSubViews; |
179 | |
180 | /// A container for all MCDC records in the source on display. |
181 | SmallVector<MCDCView, 0> MCDCSubViews; |
182 | |
183 | /// A container for all instantiations (e.g template functions) in the source |
184 | /// on display. |
185 | std::vector<InstantiationView> InstantiationSubViews; |
186 | |
187 | /// Get the first uncovered line number for the source file. |
188 | unsigned getFirstUncoveredLineNo(); |
189 | |
190 | protected: |
191 | struct LineRef { |
192 | StringRef Line; |
193 | int64_t LineNo; |
194 | |
195 | LineRef(StringRef Line, int64_t LineNo) : Line(Line), LineNo(LineNo) {} |
196 | }; |
197 | |
198 | using CoverageSegmentArray = ArrayRef<const CoverageSegment *>; |
199 | |
200 | /// @name Rendering Interface |
201 | /// @{ |
202 | |
203 | /// Render a header for the view. |
204 | virtual void (raw_ostream &OS) = 0; |
205 | |
206 | /// Render a footer for the view. |
207 | virtual void (raw_ostream &OS) = 0; |
208 | |
209 | /// Render the source name for the view. |
210 | virtual void renderSourceName(raw_ostream &OS, bool WholeFile) = 0; |
211 | |
212 | /// Render the line prefix at the given \p ViewDepth. |
213 | virtual void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) = 0; |
214 | |
215 | /// Render the line suffix at the given \p ViewDepth. |
216 | virtual void renderLineSuffix(raw_ostream &OS, unsigned ViewDepth) = 0; |
217 | |
218 | /// Render a view divider at the given \p ViewDepth. |
219 | virtual void renderViewDivider(raw_ostream &OS, unsigned ViewDepth) = 0; |
220 | |
221 | /// Render a source line with highlighting. |
222 | virtual void renderLine(raw_ostream &OS, LineRef L, |
223 | const LineCoverageStats &LCS, unsigned ExpansionCol, |
224 | unsigned ViewDepth) = 0; |
225 | |
226 | /// Render the line's execution count column. |
227 | virtual void renderLineCoverageColumn(raw_ostream &OS, |
228 | const LineCoverageStats &Line) = 0; |
229 | |
230 | /// Render the line number column. |
231 | virtual void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) = 0; |
232 | |
233 | /// Render all the region's execution counts on a line. |
234 | virtual void renderRegionMarkers(raw_ostream &OS, |
235 | const LineCoverageStats &Line, |
236 | unsigned ViewDepth) = 0; |
237 | |
238 | /// Render the site of an expansion. |
239 | virtual void renderExpansionSite(raw_ostream &OS, LineRef L, |
240 | const LineCoverageStats &LCS, |
241 | unsigned ExpansionCol, |
242 | unsigned ViewDepth) = 0; |
243 | |
244 | /// Render an expansion view and any nested views. |
245 | virtual void renderExpansionView(raw_ostream &OS, ExpansionView &ESV, |
246 | unsigned ViewDepth) = 0; |
247 | |
248 | /// Render an instantiation view and any nested views. |
249 | virtual void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV, |
250 | unsigned ViewDepth) = 0; |
251 | |
252 | /// Render a branch view and any nested views. |
253 | virtual void renderBranchView(raw_ostream &OS, BranchView &BRV, |
254 | unsigned ViewDepth) = 0; |
255 | |
256 | /// Render an MCDC view. |
257 | virtual void renderMCDCView(raw_ostream &OS, MCDCView &BRV, |
258 | unsigned ViewDepth) = 0; |
259 | |
260 | /// Render \p Title, a project title if one is available, and the |
261 | /// created time. |
262 | virtual void renderTitle(raw_ostream &OS, StringRef CellText) = 0; |
263 | |
264 | /// Render the table header for a given source file. |
265 | virtual void (raw_ostream &OS, unsigned FirstUncoveredLineNo, |
266 | unsigned IndentLevel) = 0; |
267 | |
268 | /// @} |
269 | |
270 | /// Format a count using engineering notation with 3 significant |
271 | /// digits. |
272 | static std::string formatCount(uint64_t N); |
273 | |
274 | /// Check if region marker output is expected for a line. |
275 | bool shouldRenderRegionMarkers(const LineCoverageStats &LCS) const; |
276 | |
277 | /// Check if there are any sub-views attached to this view. |
278 | bool hasSubViews() const; |
279 | |
280 | SourceCoverageView(StringRef SourceName, const MemoryBuffer &File, |
281 | const CoverageViewOptions &Options, |
282 | CoverageData &&CoverageInfo) |
283 | : SourceName(SourceName), File(File), Options(Options), |
284 | CoverageInfo(std::move(CoverageInfo)) {} |
285 | |
286 | public: |
287 | static std::unique_ptr<SourceCoverageView> |
288 | create(StringRef SourceName, const MemoryBuffer &File, |
289 | const CoverageViewOptions &Options, CoverageData &&CoverageInfo); |
290 | |
291 | virtual ~SourceCoverageView() {} |
292 | |
293 | /// Return the source name formatted for the host OS. |
294 | std::string getSourceName() const; |
295 | |
296 | const CoverageViewOptions &getOptions() const { return Options; } |
297 | |
298 | /// Add an expansion subview to this view. |
299 | void addExpansion(const CounterMappingRegion &Region, |
300 | std::unique_ptr<SourceCoverageView> View); |
301 | |
302 | /// Add a function instantiation subview to this view. |
303 | void addInstantiation(StringRef FunctionName, unsigned Line, |
304 | std::unique_ptr<SourceCoverageView> View); |
305 | |
306 | /// Add a branch subview to this view. |
307 | void addBranch(unsigned Line, SmallVector<CountedRegion, 0> Regions, |
308 | std::unique_ptr<SourceCoverageView> View); |
309 | |
310 | /// Add an MCDC subview to this view. |
311 | void addMCDCRecord(unsigned Line, SmallVector<MCDCRecord, 0> Records, |
312 | std::unique_ptr<SourceCoverageView> View); |
313 | |
314 | /// Print the code coverage information for a specific portion of a |
315 | /// source file to the output stream. |
316 | void print(raw_ostream &OS, bool WholeFile, bool ShowSourceName, |
317 | bool ShowTitle, unsigned ViewDepth = 0); |
318 | }; |
319 | |
320 | } // namespace llvm |
321 | |
322 | #endif // LLVM_COV_SOURCECOVERAGEVIEW_H |
323 | |