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