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