xref: /freebsd-src/contrib/llvm-project/llvm/tools/llvm-cov/SourceCoverageView.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- SourceCoverageView.h - Code coverage view for source code ----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file This class implements rendering for code coverage of source code.
100b57cec5SDimitry Andric ///
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #ifndef LLVM_COV_SOURCECOVERAGEVIEW_H
140b57cec5SDimitry Andric #define LLVM_COV_SOURCECOVERAGEVIEW_H
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "CoverageViewOptions.h"
170b57cec5SDimitry Andric #include "CoverageSummaryInfo.h"
180b57cec5SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMapping.h"
190b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
200b57cec5SDimitry Andric #include <vector>
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric namespace llvm {
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric using namespace coverage;
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric class CoverageFiltersMatchAll;
270b57cec5SDimitry Andric class SourceCoverageView;
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric /// A view that represents a macro or include expansion.
300b57cec5SDimitry Andric struct ExpansionView {
310b57cec5SDimitry Andric   CounterMappingRegion Region;
320b57cec5SDimitry Andric   std::unique_ptr<SourceCoverageView> View;
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric   ExpansionView(const CounterMappingRegion &Region,
350b57cec5SDimitry Andric                 std::unique_ptr<SourceCoverageView> View)
360b57cec5SDimitry Andric       : Region(Region), View(std::move(View)) {}
370b57cec5SDimitry Andric   ExpansionView(ExpansionView &&RHS)
380b57cec5SDimitry Andric       : Region(std::move(RHS.Region)), View(std::move(RHS.View)) {}
390b57cec5SDimitry Andric   ExpansionView &operator=(ExpansionView &&RHS) {
400b57cec5SDimitry Andric     Region = std::move(RHS.Region);
410b57cec5SDimitry Andric     View = std::move(RHS.View);
420b57cec5SDimitry Andric     return *this;
430b57cec5SDimitry Andric   }
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric   unsigned getLine() const { return Region.LineStart; }
460b57cec5SDimitry Andric   unsigned getStartCol() const { return Region.ColumnStart; }
470b57cec5SDimitry Andric   unsigned getEndCol() const { return Region.ColumnEnd; }
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   friend bool operator<(const ExpansionView &LHS, const ExpansionView &RHS) {
500b57cec5SDimitry Andric     return LHS.Region.startLoc() < RHS.Region.startLoc();
510b57cec5SDimitry Andric   }
520b57cec5SDimitry Andric };
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric /// A view that represents a function instantiation.
550b57cec5SDimitry Andric struct InstantiationView {
560b57cec5SDimitry Andric   StringRef FunctionName;
570b57cec5SDimitry Andric   unsigned Line;
580b57cec5SDimitry Andric   std::unique_ptr<SourceCoverageView> View;
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   InstantiationView(StringRef FunctionName, unsigned Line,
610b57cec5SDimitry Andric                     std::unique_ptr<SourceCoverageView> View)
620b57cec5SDimitry Andric       : FunctionName(FunctionName), Line(Line), View(std::move(View)) {}
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   friend bool operator<(const InstantiationView &LHS,
650b57cec5SDimitry Andric                         const InstantiationView &RHS) {
660b57cec5SDimitry Andric     return LHS.Line < RHS.Line;
670b57cec5SDimitry Andric   }
680b57cec5SDimitry Andric };
690b57cec5SDimitry Andric 
70e8d8bef9SDimitry Andric /// A view that represents one or more branch regions on a given source line.
71e8d8bef9SDimitry Andric struct BranchView {
72*0fca6ea1SDimitry Andric   SmallVector<CountedRegion, 0> Regions;
73e8d8bef9SDimitry Andric   unsigned Line;
74e8d8bef9SDimitry Andric 
75*0fca6ea1SDimitry Andric   BranchView(unsigned Line, SmallVector<CountedRegion, 0> Regions)
76*0fca6ea1SDimitry Andric       : Regions(std::move(Regions)), Line(Line) {}
77e8d8bef9SDimitry Andric 
78e8d8bef9SDimitry Andric   unsigned getLine() const { return Line; }
79e8d8bef9SDimitry Andric 
80e8d8bef9SDimitry Andric   friend bool operator<(const BranchView &LHS, const BranchView &RHS) {
81e8d8bef9SDimitry Andric     return LHS.Line < RHS.Line;
82e8d8bef9SDimitry Andric   }
83e8d8bef9SDimitry Andric };
84e8d8bef9SDimitry Andric 
855f757f3fSDimitry Andric /// A view that represents one or more MCDC regions on a given source line.
865f757f3fSDimitry Andric struct MCDCView {
87*0fca6ea1SDimitry Andric   SmallVector<MCDCRecord, 0> Records;
885f757f3fSDimitry Andric   unsigned Line;
895f757f3fSDimitry Andric 
90*0fca6ea1SDimitry Andric   MCDCView(unsigned Line, SmallVector<MCDCRecord, 0> Records)
91*0fca6ea1SDimitry Andric       : Records(std::move(Records)), Line(Line) {}
925f757f3fSDimitry Andric 
935f757f3fSDimitry Andric   unsigned getLine() const { return Line; }
945f757f3fSDimitry Andric 
955f757f3fSDimitry Andric   friend bool operator<(const MCDCView &LHS, const MCDCView &RHS) {
965f757f3fSDimitry Andric     return LHS.Line < RHS.Line;
975f757f3fSDimitry Andric   }
985f757f3fSDimitry Andric };
995f757f3fSDimitry Andric 
1000b57cec5SDimitry Andric /// A file manager that handles format-aware file creation.
1010b57cec5SDimitry Andric class CoveragePrinter {
1020b57cec5SDimitry Andric public:
1030b57cec5SDimitry Andric   struct StreamDestructor {
1040b57cec5SDimitry Andric     void operator()(raw_ostream *OS) const;
1050b57cec5SDimitry Andric   };
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   using OwnedStream = std::unique_ptr<raw_ostream, StreamDestructor>;
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric protected:
1100b57cec5SDimitry Andric   const CoverageViewOptions &Opts;
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   CoveragePrinter(const CoverageViewOptions &Opts) : Opts(Opts) {}
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   /// Return `OutputDir/ToplevelDir/Path.Extension`. If \p InToplevel is
1155f757f3fSDimitry Andric   /// true, skip the ToplevelDir component. If \p Relative is true, skip the
1160b57cec5SDimitry Andric   /// OutputDir component.
1170b57cec5SDimitry Andric   std::string getOutputPath(StringRef Path, StringRef Extension,
1180b57cec5SDimitry Andric                             bool InToplevel, bool Relative = true) const;
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric   /// If directory output is enabled, create a file in that directory
1210b57cec5SDimitry Andric   /// at the path given by getOutputPath(). Otherwise, return stdout.
1220b57cec5SDimitry Andric   Expected<OwnedStream> createOutputStream(StringRef Path, StringRef Extension,
1230b57cec5SDimitry Andric                                            bool InToplevel) const;
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric   /// Return the sub-directory name for file coverage reports.
1260b57cec5SDimitry Andric   static StringRef getCoverageDir() { return "coverage"; }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric public:
1290b57cec5SDimitry Andric   static std::unique_ptr<CoveragePrinter>
1300b57cec5SDimitry Andric   create(const CoverageViewOptions &Opts);
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric   virtual ~CoveragePrinter() {}
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric   /// @name File Creation Interface
1350b57cec5SDimitry Andric   /// @{
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric   /// Create a file to print a coverage view into.
1380b57cec5SDimitry Andric   virtual Expected<OwnedStream> createViewFile(StringRef Path,
1390b57cec5SDimitry Andric                                                bool InToplevel) = 0;
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   /// Close a file which has been used to print a coverage view.
1420b57cec5SDimitry Andric   virtual void closeViewFile(OwnedStream OS) = 0;
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric   /// Create an index which lists reports for the given source files.
1450b57cec5SDimitry Andric   virtual Error createIndexFile(ArrayRef<std::string> SourceFiles,
1460b57cec5SDimitry Andric                                 const CoverageMapping &Coverage,
1470b57cec5SDimitry Andric                                 const CoverageFiltersMatchAll &Filters) = 0;
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric   /// @}
1500b57cec5SDimitry Andric };
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric /// A code coverage view of a source file or function.
1530b57cec5SDimitry Andric ///
1540b57cec5SDimitry Andric /// A source coverage view and its nested sub-views form a file-oriented
1550b57cec5SDimitry Andric /// representation of code coverage data. This view can be printed out by a
1560b57cec5SDimitry Andric /// renderer which implements the Rendering Interface.
1570b57cec5SDimitry Andric class SourceCoverageView {
1580b57cec5SDimitry Andric   /// A function or file name.
1590b57cec5SDimitry Andric   StringRef SourceName;
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric   /// A memory buffer backing the source on display.
1620b57cec5SDimitry Andric   const MemoryBuffer &File;
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric   /// Various options to guide the coverage renderer.
1650b57cec5SDimitry Andric   const CoverageViewOptions &Options;
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric   /// Complete coverage information about the source on display.
1680b57cec5SDimitry Andric   CoverageData CoverageInfo;
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric   /// A container for all expansions (e.g macros) in the source on display.
1710b57cec5SDimitry Andric   std::vector<ExpansionView> ExpansionSubViews;
1720b57cec5SDimitry Andric 
173e8d8bef9SDimitry Andric   /// A container for all branches in the source on display.
174*0fca6ea1SDimitry Andric   SmallVector<BranchView, 0> BranchSubViews;
175e8d8bef9SDimitry Andric 
1765f757f3fSDimitry Andric   /// A container for all MCDC records in the source on display.
177*0fca6ea1SDimitry Andric   SmallVector<MCDCView, 0> MCDCSubViews;
1785f757f3fSDimitry Andric 
1790b57cec5SDimitry Andric   /// A container for all instantiations (e.g template functions) in the source
1800b57cec5SDimitry Andric   /// on display.
1810b57cec5SDimitry Andric   std::vector<InstantiationView> InstantiationSubViews;
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric   /// Get the first uncovered line number for the source file.
1840b57cec5SDimitry Andric   unsigned getFirstUncoveredLineNo();
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric protected:
1870b57cec5SDimitry Andric   struct LineRef {
1880b57cec5SDimitry Andric     StringRef Line;
1890b57cec5SDimitry Andric     int64_t LineNo;
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric     LineRef(StringRef Line, int64_t LineNo) : Line(Line), LineNo(LineNo) {}
1920b57cec5SDimitry Andric   };
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric   using CoverageSegmentArray = ArrayRef<const CoverageSegment *>;
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric   /// @name Rendering Interface
1970b57cec5SDimitry Andric   /// @{
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric   /// Render a header for the view.
2000b57cec5SDimitry Andric   virtual void renderViewHeader(raw_ostream &OS) = 0;
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric   /// Render a footer for the view.
2030b57cec5SDimitry Andric   virtual void renderViewFooter(raw_ostream &OS) = 0;
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric   /// Render the source name for the view.
2060b57cec5SDimitry Andric   virtual void renderSourceName(raw_ostream &OS, bool WholeFile) = 0;
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric   /// Render the line prefix at the given \p ViewDepth.
2090b57cec5SDimitry Andric   virtual void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) = 0;
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric   /// Render the line suffix at the given \p ViewDepth.
2120b57cec5SDimitry Andric   virtual void renderLineSuffix(raw_ostream &OS, unsigned ViewDepth) = 0;
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric   /// Render a view divider at the given \p ViewDepth.
2150b57cec5SDimitry Andric   virtual void renderViewDivider(raw_ostream &OS, unsigned ViewDepth) = 0;
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric   /// Render a source line with highlighting.
2180b57cec5SDimitry Andric   virtual void renderLine(raw_ostream &OS, LineRef L,
2190b57cec5SDimitry Andric                           const LineCoverageStats &LCS, unsigned ExpansionCol,
2200b57cec5SDimitry Andric                           unsigned ViewDepth) = 0;
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric   /// Render the line's execution count column.
2230b57cec5SDimitry Andric   virtual void renderLineCoverageColumn(raw_ostream &OS,
2240b57cec5SDimitry Andric                                         const LineCoverageStats &Line) = 0;
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric   /// Render the line number column.
2270b57cec5SDimitry Andric   virtual void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) = 0;
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric   /// Render all the region's execution counts on a line.
2300b57cec5SDimitry Andric   virtual void renderRegionMarkers(raw_ostream &OS,
2310b57cec5SDimitry Andric                                    const LineCoverageStats &Line,
2320b57cec5SDimitry Andric                                    unsigned ViewDepth) = 0;
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric   /// Render the site of an expansion.
2350b57cec5SDimitry Andric   virtual void renderExpansionSite(raw_ostream &OS, LineRef L,
2360b57cec5SDimitry Andric                                    const LineCoverageStats &LCS,
2370b57cec5SDimitry Andric                                    unsigned ExpansionCol,
2380b57cec5SDimitry Andric                                    unsigned ViewDepth) = 0;
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric   /// Render an expansion view and any nested views.
2410b57cec5SDimitry Andric   virtual void renderExpansionView(raw_ostream &OS, ExpansionView &ESV,
2420b57cec5SDimitry Andric                                    unsigned ViewDepth) = 0;
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric   /// Render an instantiation view and any nested views.
2450b57cec5SDimitry Andric   virtual void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV,
2460b57cec5SDimitry Andric                                        unsigned ViewDepth) = 0;
2470b57cec5SDimitry Andric 
248e8d8bef9SDimitry Andric   /// Render a branch view and any nested views.
249e8d8bef9SDimitry Andric   virtual void renderBranchView(raw_ostream &OS, BranchView &BRV,
250e8d8bef9SDimitry Andric                                 unsigned ViewDepth) = 0;
251e8d8bef9SDimitry Andric 
2525f757f3fSDimitry Andric   /// Render an MCDC view.
2535f757f3fSDimitry Andric   virtual void renderMCDCView(raw_ostream &OS, MCDCView &BRV,
2545f757f3fSDimitry Andric                               unsigned ViewDepth) = 0;
2555f757f3fSDimitry Andric 
2560b57cec5SDimitry Andric   /// Render \p Title, a project title if one is available, and the
2570b57cec5SDimitry Andric   /// created time.
2580b57cec5SDimitry Andric   virtual void renderTitle(raw_ostream &OS, StringRef CellText) = 0;
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric   /// Render the table header for a given source file.
261*0fca6ea1SDimitry Andric   virtual void renderTableHeader(raw_ostream &OS, unsigned IndentLevel) = 0;
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric   /// @}
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric   /// Format a count using engineering notation with 3 significant
2660b57cec5SDimitry Andric   /// digits.
2670b57cec5SDimitry Andric   static std::string formatCount(uint64_t N);
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric   /// Check if region marker output is expected for a line.
2700b57cec5SDimitry Andric   bool shouldRenderRegionMarkers(const LineCoverageStats &LCS) const;
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric   /// Check if there are any sub-views attached to this view.
2730b57cec5SDimitry Andric   bool hasSubViews() const;
2740b57cec5SDimitry Andric 
2750b57cec5SDimitry Andric   SourceCoverageView(StringRef SourceName, const MemoryBuffer &File,
2760b57cec5SDimitry Andric                      const CoverageViewOptions &Options,
2770b57cec5SDimitry Andric                      CoverageData &&CoverageInfo)
2780b57cec5SDimitry Andric       : SourceName(SourceName), File(File), Options(Options),
2790b57cec5SDimitry Andric         CoverageInfo(std::move(CoverageInfo)) {}
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric public:
2820b57cec5SDimitry Andric   static std::unique_ptr<SourceCoverageView>
2830b57cec5SDimitry Andric   create(StringRef SourceName, const MemoryBuffer &File,
2840b57cec5SDimitry Andric          const CoverageViewOptions &Options, CoverageData &&CoverageInfo);
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric   virtual ~SourceCoverageView() {}
2870b57cec5SDimitry Andric 
2880b57cec5SDimitry Andric   /// Return the source name formatted for the host OS.
2890b57cec5SDimitry Andric   std::string getSourceName() const;
2900b57cec5SDimitry Andric 
2910b57cec5SDimitry Andric   const CoverageViewOptions &getOptions() const { return Options; }
2920b57cec5SDimitry Andric 
2930b57cec5SDimitry Andric   /// Add an expansion subview to this view.
2940b57cec5SDimitry Andric   void addExpansion(const CounterMappingRegion &Region,
2950b57cec5SDimitry Andric                     std::unique_ptr<SourceCoverageView> View);
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric   /// Add a function instantiation subview to this view.
2980b57cec5SDimitry Andric   void addInstantiation(StringRef FunctionName, unsigned Line,
2990b57cec5SDimitry Andric                         std::unique_ptr<SourceCoverageView> View);
3000b57cec5SDimitry Andric 
301e8d8bef9SDimitry Andric   /// Add a branch subview to this view.
302*0fca6ea1SDimitry Andric   void addBranch(unsigned Line, SmallVector<CountedRegion, 0> Regions);
303e8d8bef9SDimitry Andric 
3045f757f3fSDimitry Andric   /// Add an MCDC subview to this view.
305*0fca6ea1SDimitry Andric   void addMCDCRecord(unsigned Line, SmallVector<MCDCRecord, 0> Records);
3065f757f3fSDimitry Andric 
3070b57cec5SDimitry Andric   /// Print the code coverage information for a specific portion of a
3080b57cec5SDimitry Andric   /// source file to the output stream.
3090b57cec5SDimitry Andric   void print(raw_ostream &OS, bool WholeFile, bool ShowSourceName,
3100b57cec5SDimitry Andric              bool ShowTitle, unsigned ViewDepth = 0);
3110b57cec5SDimitry Andric };
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric } // namespace llvm
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric #endif // LLVM_COV_SOURCECOVERAGEVIEW_H
316