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