17330f729Sjoerg //===- SourceCoverageView.h - Code coverage view for source code ----------===// 27330f729Sjoerg // 37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information. 57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 67330f729Sjoerg // 77330f729Sjoerg //===----------------------------------------------------------------------===// 87330f729Sjoerg /// 97330f729Sjoerg /// \file This class implements rendering for code coverage of source code. 107330f729Sjoerg /// 117330f729Sjoerg //===----------------------------------------------------------------------===// 127330f729Sjoerg 137330f729Sjoerg #ifndef LLVM_COV_SOURCECOVERAGEVIEW_H 147330f729Sjoerg #define LLVM_COV_SOURCECOVERAGEVIEW_H 157330f729Sjoerg 167330f729Sjoerg #include "CoverageViewOptions.h" 177330f729Sjoerg #include "CoverageSummaryInfo.h" 187330f729Sjoerg #include "llvm/ProfileData/Coverage/CoverageMapping.h" 197330f729Sjoerg #include "llvm/Support/MemoryBuffer.h" 207330f729Sjoerg #include <vector> 217330f729Sjoerg 227330f729Sjoerg namespace llvm { 237330f729Sjoerg 247330f729Sjoerg using namespace coverage; 257330f729Sjoerg 267330f729Sjoerg class CoverageFiltersMatchAll; 277330f729Sjoerg class SourceCoverageView; 287330f729Sjoerg 297330f729Sjoerg /// A view that represents a macro or include expansion. 307330f729Sjoerg struct ExpansionView { 317330f729Sjoerg CounterMappingRegion Region; 327330f729Sjoerg std::unique_ptr<SourceCoverageView> View; 337330f729Sjoerg ExpansionViewExpansionView347330f729Sjoerg ExpansionView(const CounterMappingRegion &Region, 357330f729Sjoerg std::unique_ptr<SourceCoverageView> View) 367330f729Sjoerg : Region(Region), View(std::move(View)) {} ExpansionViewExpansionView377330f729Sjoerg ExpansionView(ExpansionView &&RHS) 387330f729Sjoerg : Region(std::move(RHS.Region)), View(std::move(RHS.View)) {} 397330f729Sjoerg ExpansionView &operator=(ExpansionView &&RHS) { 407330f729Sjoerg Region = std::move(RHS.Region); 417330f729Sjoerg View = std::move(RHS.View); 427330f729Sjoerg return *this; 437330f729Sjoerg } 447330f729Sjoerg getLineExpansionView457330f729Sjoerg unsigned getLine() const { return Region.LineStart; } getStartColExpansionView467330f729Sjoerg unsigned getStartCol() const { return Region.ColumnStart; } getEndColExpansionView477330f729Sjoerg unsigned getEndCol() const { return Region.ColumnEnd; } 487330f729Sjoerg 497330f729Sjoerg friend bool operator<(const ExpansionView &LHS, const ExpansionView &RHS) { 507330f729Sjoerg return LHS.Region.startLoc() < RHS.Region.startLoc(); 517330f729Sjoerg } 527330f729Sjoerg }; 537330f729Sjoerg 547330f729Sjoerg /// A view that represents a function instantiation. 557330f729Sjoerg struct InstantiationView { 567330f729Sjoerg StringRef FunctionName; 577330f729Sjoerg unsigned Line; 587330f729Sjoerg std::unique_ptr<SourceCoverageView> View; 597330f729Sjoerg InstantiationViewInstantiationView607330f729Sjoerg InstantiationView(StringRef FunctionName, unsigned Line, 617330f729Sjoerg std::unique_ptr<SourceCoverageView> View) 627330f729Sjoerg : FunctionName(FunctionName), Line(Line), View(std::move(View)) {} 637330f729Sjoerg 647330f729Sjoerg friend bool operator<(const InstantiationView &LHS, 657330f729Sjoerg const InstantiationView &RHS) { 667330f729Sjoerg return LHS.Line < RHS.Line; 677330f729Sjoerg } 687330f729Sjoerg }; 697330f729Sjoerg 70*82d56013Sjoerg /// A view that represents one or more branch regions on a given source line. 71*82d56013Sjoerg struct BranchView { 72*82d56013Sjoerg std::vector<CountedRegion> Regions; 73*82d56013Sjoerg std::unique_ptr<SourceCoverageView> View; 74*82d56013Sjoerg unsigned Line; 75*82d56013Sjoerg BranchViewBranchView76*82d56013Sjoerg BranchView(unsigned Line, ArrayRef<CountedRegion> Regions, 77*82d56013Sjoerg std::unique_ptr<SourceCoverageView> View) 78*82d56013Sjoerg : Regions(Regions), View(std::move(View)), Line(Line) {} 79*82d56013Sjoerg getLineBranchView80*82d56013Sjoerg unsigned getLine() const { return Line; } 81*82d56013Sjoerg 82*82d56013Sjoerg friend bool operator<(const BranchView &LHS, const BranchView &RHS) { 83*82d56013Sjoerg return LHS.Line < RHS.Line; 84*82d56013Sjoerg } 85*82d56013Sjoerg }; 86*82d56013Sjoerg 877330f729Sjoerg /// A file manager that handles format-aware file creation. 887330f729Sjoerg class CoveragePrinter { 897330f729Sjoerg public: 907330f729Sjoerg struct StreamDestructor { 917330f729Sjoerg void operator()(raw_ostream *OS) const; 927330f729Sjoerg }; 937330f729Sjoerg 947330f729Sjoerg using OwnedStream = std::unique_ptr<raw_ostream, StreamDestructor>; 957330f729Sjoerg 967330f729Sjoerg protected: 977330f729Sjoerg const CoverageViewOptions &Opts; 987330f729Sjoerg CoveragePrinter(const CoverageViewOptions & Opts)997330f729Sjoerg CoveragePrinter(const CoverageViewOptions &Opts) : Opts(Opts) {} 1007330f729Sjoerg 1017330f729Sjoerg /// Return `OutputDir/ToplevelDir/Path.Extension`. If \p InToplevel is 1027330f729Sjoerg /// false, skip the ToplevelDir component. If \p Relative is false, skip the 1037330f729Sjoerg /// OutputDir component. 1047330f729Sjoerg std::string getOutputPath(StringRef Path, StringRef Extension, 1057330f729Sjoerg bool InToplevel, bool Relative = true) const; 1067330f729Sjoerg 1077330f729Sjoerg /// If directory output is enabled, create a file in that directory 1087330f729Sjoerg /// at the path given by getOutputPath(). Otherwise, return stdout. 1097330f729Sjoerg Expected<OwnedStream> createOutputStream(StringRef Path, StringRef Extension, 1107330f729Sjoerg bool InToplevel) const; 1117330f729Sjoerg 1127330f729Sjoerg /// Return the sub-directory name for file coverage reports. getCoverageDir()1137330f729Sjoerg static StringRef getCoverageDir() { return "coverage"; } 1147330f729Sjoerg 1157330f729Sjoerg public: 1167330f729Sjoerg static std::unique_ptr<CoveragePrinter> 1177330f729Sjoerg create(const CoverageViewOptions &Opts); 1187330f729Sjoerg ~CoveragePrinter()1197330f729Sjoerg virtual ~CoveragePrinter() {} 1207330f729Sjoerg 1217330f729Sjoerg /// @name File Creation Interface 1227330f729Sjoerg /// @{ 1237330f729Sjoerg 1247330f729Sjoerg /// Create a file to print a coverage view into. 1257330f729Sjoerg virtual Expected<OwnedStream> createViewFile(StringRef Path, 1267330f729Sjoerg bool InToplevel) = 0; 1277330f729Sjoerg 1287330f729Sjoerg /// Close a file which has been used to print a coverage view. 1297330f729Sjoerg virtual void closeViewFile(OwnedStream OS) = 0; 1307330f729Sjoerg 1317330f729Sjoerg /// Create an index which lists reports for the given source files. 1327330f729Sjoerg virtual Error createIndexFile(ArrayRef<std::string> SourceFiles, 1337330f729Sjoerg const CoverageMapping &Coverage, 1347330f729Sjoerg const CoverageFiltersMatchAll &Filters) = 0; 1357330f729Sjoerg 1367330f729Sjoerg /// @} 1377330f729Sjoerg }; 1387330f729Sjoerg 1397330f729Sjoerg /// A code coverage view of a source file or function. 1407330f729Sjoerg /// 1417330f729Sjoerg /// A source coverage view and its nested sub-views form a file-oriented 1427330f729Sjoerg /// representation of code coverage data. This view can be printed out by a 1437330f729Sjoerg /// renderer which implements the Rendering Interface. 1447330f729Sjoerg class SourceCoverageView { 1457330f729Sjoerg /// A function or file name. 1467330f729Sjoerg StringRef SourceName; 1477330f729Sjoerg 1487330f729Sjoerg /// A memory buffer backing the source on display. 1497330f729Sjoerg const MemoryBuffer &File; 1507330f729Sjoerg 1517330f729Sjoerg /// Various options to guide the coverage renderer. 1527330f729Sjoerg const CoverageViewOptions &Options; 1537330f729Sjoerg 1547330f729Sjoerg /// Complete coverage information about the source on display. 1557330f729Sjoerg CoverageData CoverageInfo; 1567330f729Sjoerg 1577330f729Sjoerg /// A container for all expansions (e.g macros) in the source on display. 1587330f729Sjoerg std::vector<ExpansionView> ExpansionSubViews; 1597330f729Sjoerg 160*82d56013Sjoerg /// A container for all branches in the source on display. 161*82d56013Sjoerg std::vector<BranchView> BranchSubViews; 162*82d56013Sjoerg 1637330f729Sjoerg /// A container for all instantiations (e.g template functions) in the source 1647330f729Sjoerg /// on display. 1657330f729Sjoerg std::vector<InstantiationView> InstantiationSubViews; 1667330f729Sjoerg 1677330f729Sjoerg /// Get the first uncovered line number for the source file. 1687330f729Sjoerg unsigned getFirstUncoveredLineNo(); 1697330f729Sjoerg 1707330f729Sjoerg protected: 1717330f729Sjoerg struct LineRef { 1727330f729Sjoerg StringRef Line; 1737330f729Sjoerg int64_t LineNo; 1747330f729Sjoerg LineRefLineRef1757330f729Sjoerg LineRef(StringRef Line, int64_t LineNo) : Line(Line), LineNo(LineNo) {} 1767330f729Sjoerg }; 1777330f729Sjoerg 1787330f729Sjoerg using CoverageSegmentArray = ArrayRef<const CoverageSegment *>; 1797330f729Sjoerg 1807330f729Sjoerg /// @name Rendering Interface 1817330f729Sjoerg /// @{ 1827330f729Sjoerg 1837330f729Sjoerg /// Render a header for the view. 1847330f729Sjoerg virtual void renderViewHeader(raw_ostream &OS) = 0; 1857330f729Sjoerg 1867330f729Sjoerg /// Render a footer for the view. 1877330f729Sjoerg virtual void renderViewFooter(raw_ostream &OS) = 0; 1887330f729Sjoerg 1897330f729Sjoerg /// Render the source name for the view. 1907330f729Sjoerg virtual void renderSourceName(raw_ostream &OS, bool WholeFile) = 0; 1917330f729Sjoerg 1927330f729Sjoerg /// Render the line prefix at the given \p ViewDepth. 1937330f729Sjoerg virtual void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) = 0; 1947330f729Sjoerg 1957330f729Sjoerg /// Render the line suffix at the given \p ViewDepth. 1967330f729Sjoerg virtual void renderLineSuffix(raw_ostream &OS, unsigned ViewDepth) = 0; 1977330f729Sjoerg 1987330f729Sjoerg /// Render a view divider at the given \p ViewDepth. 1997330f729Sjoerg virtual void renderViewDivider(raw_ostream &OS, unsigned ViewDepth) = 0; 2007330f729Sjoerg 2017330f729Sjoerg /// Render a source line with highlighting. 2027330f729Sjoerg virtual void renderLine(raw_ostream &OS, LineRef L, 2037330f729Sjoerg const LineCoverageStats &LCS, unsigned ExpansionCol, 2047330f729Sjoerg unsigned ViewDepth) = 0; 2057330f729Sjoerg 2067330f729Sjoerg /// Render the line's execution count column. 2077330f729Sjoerg virtual void renderLineCoverageColumn(raw_ostream &OS, 2087330f729Sjoerg const LineCoverageStats &Line) = 0; 2097330f729Sjoerg 2107330f729Sjoerg /// Render the line number column. 2117330f729Sjoerg virtual void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) = 0; 2127330f729Sjoerg 2137330f729Sjoerg /// Render all the region's execution counts on a line. 2147330f729Sjoerg virtual void renderRegionMarkers(raw_ostream &OS, 2157330f729Sjoerg const LineCoverageStats &Line, 2167330f729Sjoerg unsigned ViewDepth) = 0; 2177330f729Sjoerg 2187330f729Sjoerg /// Render the site of an expansion. 2197330f729Sjoerg virtual void renderExpansionSite(raw_ostream &OS, LineRef L, 2207330f729Sjoerg const LineCoverageStats &LCS, 2217330f729Sjoerg unsigned ExpansionCol, 2227330f729Sjoerg unsigned ViewDepth) = 0; 2237330f729Sjoerg 2247330f729Sjoerg /// Render an expansion view and any nested views. 2257330f729Sjoerg virtual void renderExpansionView(raw_ostream &OS, ExpansionView &ESV, 2267330f729Sjoerg unsigned ViewDepth) = 0; 2277330f729Sjoerg 2287330f729Sjoerg /// Render an instantiation view and any nested views. 2297330f729Sjoerg virtual void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV, 2307330f729Sjoerg unsigned ViewDepth) = 0; 2317330f729Sjoerg 232*82d56013Sjoerg /// Render a branch view and any nested views. 233*82d56013Sjoerg virtual void renderBranchView(raw_ostream &OS, BranchView &BRV, 234*82d56013Sjoerg unsigned ViewDepth) = 0; 235*82d56013Sjoerg 2367330f729Sjoerg /// Render \p Title, a project title if one is available, and the 2377330f729Sjoerg /// created time. 2387330f729Sjoerg virtual void renderTitle(raw_ostream &OS, StringRef CellText) = 0; 2397330f729Sjoerg 2407330f729Sjoerg /// Render the table header for a given source file. 2417330f729Sjoerg virtual void renderTableHeader(raw_ostream &OS, unsigned FirstUncoveredLineNo, 2427330f729Sjoerg unsigned IndentLevel) = 0; 2437330f729Sjoerg 2447330f729Sjoerg /// @} 2457330f729Sjoerg 2467330f729Sjoerg /// Format a count using engineering notation with 3 significant 2477330f729Sjoerg /// digits. 2487330f729Sjoerg static std::string formatCount(uint64_t N); 2497330f729Sjoerg 2507330f729Sjoerg /// Check if region marker output is expected for a line. 2517330f729Sjoerg bool shouldRenderRegionMarkers(const LineCoverageStats &LCS) const; 2527330f729Sjoerg 2537330f729Sjoerg /// Check if there are any sub-views attached to this view. 2547330f729Sjoerg bool hasSubViews() const; 2557330f729Sjoerg SourceCoverageView(StringRef SourceName,const MemoryBuffer & File,const CoverageViewOptions & Options,CoverageData && CoverageInfo)2567330f729Sjoerg SourceCoverageView(StringRef SourceName, const MemoryBuffer &File, 2577330f729Sjoerg const CoverageViewOptions &Options, 2587330f729Sjoerg CoverageData &&CoverageInfo) 2597330f729Sjoerg : SourceName(SourceName), File(File), Options(Options), 2607330f729Sjoerg CoverageInfo(std::move(CoverageInfo)) {} 2617330f729Sjoerg 2627330f729Sjoerg public: 2637330f729Sjoerg static std::unique_ptr<SourceCoverageView> 2647330f729Sjoerg create(StringRef SourceName, const MemoryBuffer &File, 2657330f729Sjoerg const CoverageViewOptions &Options, CoverageData &&CoverageInfo); 2667330f729Sjoerg ~SourceCoverageView()2677330f729Sjoerg virtual ~SourceCoverageView() {} 2687330f729Sjoerg 2697330f729Sjoerg /// Return the source name formatted for the host OS. 2707330f729Sjoerg std::string getSourceName() const; 2717330f729Sjoerg getOptions()2727330f729Sjoerg const CoverageViewOptions &getOptions() const { return Options; } 2737330f729Sjoerg 2747330f729Sjoerg /// Add an expansion subview to this view. 2757330f729Sjoerg void addExpansion(const CounterMappingRegion &Region, 2767330f729Sjoerg std::unique_ptr<SourceCoverageView> View); 2777330f729Sjoerg 2787330f729Sjoerg /// Add a function instantiation subview to this view. 2797330f729Sjoerg void addInstantiation(StringRef FunctionName, unsigned Line, 2807330f729Sjoerg std::unique_ptr<SourceCoverageView> View); 2817330f729Sjoerg 282*82d56013Sjoerg /// Add a branch subview to this view. 283*82d56013Sjoerg void addBranch(unsigned Line, ArrayRef<CountedRegion> Regions, 284*82d56013Sjoerg std::unique_ptr<SourceCoverageView> View); 285*82d56013Sjoerg 2867330f729Sjoerg /// Print the code coverage information for a specific portion of a 2877330f729Sjoerg /// source file to the output stream. 2887330f729Sjoerg void print(raw_ostream &OS, bool WholeFile, bool ShowSourceName, 2897330f729Sjoerg bool ShowTitle, unsigned ViewDepth = 0); 2907330f729Sjoerg }; 2917330f729Sjoerg 2927330f729Sjoerg } // namespace llvm 2937330f729Sjoerg 2947330f729Sjoerg #endif // LLVM_COV_SOURCECOVERAGEVIEW_H 295