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