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 34 ExpansionView(const CounterMappingRegion &Region, 35 std::unique_ptr<SourceCoverageView> View) 36 : Region(Region), View(std::move(View)) {} 37 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 45 unsigned getLine() const { return Region.LineStart; } 46 unsigned getStartCol() const { return Region.ColumnStart; } 47 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 60 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 view that represents one or more branch regions on a given source line. 71 struct BranchView { 72 std::vector<CountedRegion> Regions; 73 std::unique_ptr<SourceCoverageView> View; 74 unsigned Line; 75 76 BranchView(unsigned Line, ArrayRef<CountedRegion> Regions, 77 std::unique_ptr<SourceCoverageView> View) 78 : Regions(Regions), View(std::move(View)), Line(Line) {} 79 80 unsigned getLine() const { return Line; } 81 82 friend bool operator<(const BranchView &LHS, const BranchView &RHS) { 83 return LHS.Line < RHS.Line; 84 } 85 }; 86 87 /// A view that represents one or more MCDC regions on a given source line. 88 struct MCDCView { 89 std::vector<MCDCRecord> Records; 90 std::unique_ptr<SourceCoverageView> View; 91 unsigned Line; 92 93 MCDCView(unsigned Line, ArrayRef<MCDCRecord> Records, 94 std::unique_ptr<SourceCoverageView> View) 95 : Records(Records), View(std::move(View)), Line(Line) {} 96 97 unsigned getLine() const { return Line; } 98 99 friend bool operator<(const MCDCView &LHS, const MCDCView &RHS) { 100 return LHS.Line < RHS.Line; 101 } 102 }; 103 104 /// A file manager that handles format-aware file creation. 105 class CoveragePrinter { 106 public: 107 struct StreamDestructor { 108 void operator()(raw_ostream *OS) const; 109 }; 110 111 using OwnedStream = std::unique_ptr<raw_ostream, StreamDestructor>; 112 113 protected: 114 const CoverageViewOptions &Opts; 115 116 CoveragePrinter(const CoverageViewOptions &Opts) : Opts(Opts) {} 117 118 /// Return `OutputDir/ToplevelDir/Path.Extension`. If \p InToplevel is 119 /// true, skip the ToplevelDir component. If \p Relative is true, skip the 120 /// OutputDir component. 121 std::string getOutputPath(StringRef Path, StringRef Extension, 122 bool InToplevel, bool Relative = true) const; 123 124 /// If directory output is enabled, create a file in that directory 125 /// at the path given by getOutputPath(). Otherwise, return stdout. 126 Expected<OwnedStream> createOutputStream(StringRef Path, StringRef Extension, 127 bool InToplevel) const; 128 129 /// Return the sub-directory name for file coverage reports. 130 static StringRef getCoverageDir() { return "coverage"; } 131 132 public: 133 static std::unique_ptr<CoveragePrinter> 134 create(const CoverageViewOptions &Opts); 135 136 virtual ~CoveragePrinter() {} 137 138 /// @name File Creation Interface 139 /// @{ 140 141 /// Create a file to print a coverage view into. 142 virtual Expected<OwnedStream> createViewFile(StringRef Path, 143 bool InToplevel) = 0; 144 145 /// Close a file which has been used to print a coverage view. 146 virtual void closeViewFile(OwnedStream OS) = 0; 147 148 /// Create an index which lists reports for the given source files. 149 virtual Error createIndexFile(ArrayRef<std::string> SourceFiles, 150 const CoverageMapping &Coverage, 151 const CoverageFiltersMatchAll &Filters) = 0; 152 153 /// @} 154 }; 155 156 /// A code coverage view of a source file or function. 157 /// 158 /// A source coverage view and its nested sub-views form a file-oriented 159 /// representation of code coverage data. This view can be printed out by a 160 /// renderer which implements the Rendering Interface. 161 class SourceCoverageView { 162 /// A function or file name. 163 StringRef SourceName; 164 165 /// A memory buffer backing the source on display. 166 const MemoryBuffer &File; 167 168 /// Various options to guide the coverage renderer. 169 const CoverageViewOptions &Options; 170 171 /// Complete coverage information about the source on display. 172 CoverageData CoverageInfo; 173 174 /// A container for all expansions (e.g macros) in the source on display. 175 std::vector<ExpansionView> ExpansionSubViews; 176 177 /// A container for all branches in the source on display. 178 std::vector<BranchView> BranchSubViews; 179 180 /// A container for all MCDC records in the source on display. 181 std::vector<MCDCView> MCDCSubViews; 182 183 /// A container for all instantiations (e.g template functions) in the source 184 /// on display. 185 std::vector<InstantiationView> InstantiationSubViews; 186 187 /// Get the first uncovered line number for the source file. 188 unsigned getFirstUncoveredLineNo(); 189 190 protected: 191 struct LineRef { 192 StringRef Line; 193 int64_t LineNo; 194 195 LineRef(StringRef Line, int64_t LineNo) : Line(Line), LineNo(LineNo) {} 196 }; 197 198 using CoverageSegmentArray = ArrayRef<const CoverageSegment *>; 199 200 /// @name Rendering Interface 201 /// @{ 202 203 /// Render a header for the view. 204 virtual void renderViewHeader(raw_ostream &OS) = 0; 205 206 /// Render a footer for the view. 207 virtual void renderViewFooter(raw_ostream &OS) = 0; 208 209 /// Render the source name for the view. 210 virtual void renderSourceName(raw_ostream &OS, bool WholeFile) = 0; 211 212 /// Render the line prefix at the given \p ViewDepth. 213 virtual void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) = 0; 214 215 /// Render the line suffix at the given \p ViewDepth. 216 virtual void renderLineSuffix(raw_ostream &OS, unsigned ViewDepth) = 0; 217 218 /// Render a view divider at the given \p ViewDepth. 219 virtual void renderViewDivider(raw_ostream &OS, unsigned ViewDepth) = 0; 220 221 /// Render a source line with highlighting. 222 virtual void renderLine(raw_ostream &OS, LineRef L, 223 const LineCoverageStats &LCS, unsigned ExpansionCol, 224 unsigned ViewDepth) = 0; 225 226 /// Render the line's execution count column. 227 virtual void renderLineCoverageColumn(raw_ostream &OS, 228 const LineCoverageStats &Line) = 0; 229 230 /// Render the line number column. 231 virtual void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) = 0; 232 233 /// Render all the region's execution counts on a line. 234 virtual void renderRegionMarkers(raw_ostream &OS, 235 const LineCoverageStats &Line, 236 unsigned ViewDepth) = 0; 237 238 /// Render the site of an expansion. 239 virtual void renderExpansionSite(raw_ostream &OS, LineRef L, 240 const LineCoverageStats &LCS, 241 unsigned ExpansionCol, 242 unsigned ViewDepth) = 0; 243 244 /// Render an expansion view and any nested views. 245 virtual void renderExpansionView(raw_ostream &OS, ExpansionView &ESV, 246 unsigned ViewDepth) = 0; 247 248 /// Render an instantiation view and any nested views. 249 virtual void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV, 250 unsigned ViewDepth) = 0; 251 252 /// Render a branch view and any nested views. 253 virtual void renderBranchView(raw_ostream &OS, BranchView &BRV, 254 unsigned ViewDepth) = 0; 255 256 /// Render an MCDC view. 257 virtual void renderMCDCView(raw_ostream &OS, MCDCView &BRV, 258 unsigned ViewDepth) = 0; 259 260 /// Render \p Title, a project title if one is available, and the 261 /// created time. 262 virtual void renderTitle(raw_ostream &OS, StringRef CellText) = 0; 263 264 /// Render the table header for a given source file. 265 virtual void renderTableHeader(raw_ostream &OS, unsigned FirstUncoveredLineNo, 266 unsigned IndentLevel) = 0; 267 268 /// @} 269 270 /// Format a count using engineering notation with 3 significant 271 /// digits. 272 static std::string formatCount(uint64_t N); 273 274 /// Check if region marker output is expected for a line. 275 bool shouldRenderRegionMarkers(const LineCoverageStats &LCS) const; 276 277 /// Check if there are any sub-views attached to this view. 278 bool hasSubViews() const; 279 280 SourceCoverageView(StringRef SourceName, const MemoryBuffer &File, 281 const CoverageViewOptions &Options, 282 CoverageData &&CoverageInfo) 283 : SourceName(SourceName), File(File), Options(Options), 284 CoverageInfo(std::move(CoverageInfo)) {} 285 286 public: 287 static std::unique_ptr<SourceCoverageView> 288 create(StringRef SourceName, const MemoryBuffer &File, 289 const CoverageViewOptions &Options, CoverageData &&CoverageInfo); 290 291 virtual ~SourceCoverageView() {} 292 293 /// Return the source name formatted for the host OS. 294 std::string getSourceName() const; 295 296 const CoverageViewOptions &getOptions() const { return Options; } 297 298 /// Add an expansion subview to this view. 299 void addExpansion(const CounterMappingRegion &Region, 300 std::unique_ptr<SourceCoverageView> View); 301 302 /// Add a function instantiation subview to this view. 303 void addInstantiation(StringRef FunctionName, unsigned Line, 304 std::unique_ptr<SourceCoverageView> View); 305 306 /// Add a branch subview to this view. 307 void addBranch(unsigned Line, ArrayRef<CountedRegion> Regions, 308 std::unique_ptr<SourceCoverageView> View); 309 310 /// Add an MCDC subview to this view. 311 void addMCDCRecord(unsigned Line, ArrayRef<MCDCRecord> Records, 312 std::unique_ptr<SourceCoverageView> View); 313 314 /// Print the code coverage information for a specific portion of a 315 /// source file to the output stream. 316 void print(raw_ostream &OS, bool WholeFile, bool ShowSourceName, 317 bool ShowTitle, unsigned ViewDepth = 0); 318 }; 319 320 } // namespace llvm 321 322 #endif // LLVM_COV_SOURCECOVERAGEVIEW_H 323