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