//===- SourceCoverageView.h - Code coverage view for source code ----------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This class implements rendering for code coverage of source code. // //===----------------------------------------------------------------------===// #ifndef LLVM_COV_SOURCECOVERAGEVIEW_H #define LLVM_COV_SOURCECOVERAGEVIEW_H #include "CoverageViewOptions.h" #include "llvm/ProfileData/Coverage/CoverageMapping.h" #include "llvm/Support/MemoryBuffer.h" #include namespace llvm { class SourceCoverageView; /// \brief A view that represents a macro or include expansion struct ExpansionView { coverage::CounterMappingRegion Region; std::unique_ptr View; ExpansionView(const coverage::CounterMappingRegion &Region, std::unique_ptr View) : Region(Region), View(std::move(View)) {} ExpansionView(ExpansionView &&RHS) : Region(std::move(RHS.Region)), View(std::move(RHS.View)) {} ExpansionView &operator=(ExpansionView &&RHS) { Region = std::move(RHS.Region); View = std::move(RHS.View); return *this; } unsigned getLine() const { return Region.LineStart; } unsigned getStartCol() const { return Region.ColumnStart; } unsigned getEndCol() const { return Region.ColumnEnd; } friend bool operator<(const ExpansionView &LHS, const ExpansionView &RHS) { return LHS.Region.startLoc() < RHS.Region.startLoc(); } }; /// \brief A view that represents a function instantiation struct InstantiationView { StringRef FunctionName; unsigned Line; std::unique_ptr View; InstantiationView(StringRef FunctionName, unsigned Line, std::unique_ptr View) : FunctionName(FunctionName), Line(Line), View(std::move(View)) {} InstantiationView(InstantiationView &&RHS) : FunctionName(std::move(RHS.FunctionName)), Line(std::move(RHS.Line)), View(std::move(RHS.View)) {} InstantiationView &operator=(InstantiationView &&RHS) { FunctionName = std::move(RHS.FunctionName); Line = std::move(RHS.Line); View = std::move(RHS.View); return *this; } friend bool operator<(const InstantiationView &LHS, const InstantiationView &RHS) { return LHS.Line < RHS.Line; } }; /// \brief Coverage statistics for a single line. struct LineCoverageStats { uint64_t ExecutionCount; unsigned RegionCount; bool Mapped; LineCoverageStats() : ExecutionCount(0), RegionCount(0), Mapped(false) {} bool isMapped() const { return Mapped; } bool hasMultipleRegions() const { return RegionCount > 1; } void addRegionStartCount(uint64_t Count) { // The max of all region starts is the most interesting value. addRegionCount(RegionCount ? std::max(ExecutionCount, Count) : Count); ++RegionCount; } void addRegionCount(uint64_t Count) { Mapped = true; ExecutionCount = Count; } }; /// \brief A code coverage view of a specific source file. /// It can have embedded coverage views. class SourceCoverageView { private: /// A function or file name. StringRef SourceName; /// A memory buffer backing the source on display. const MemoryBuffer &File; /// Various options to guide the coverage renderer. const CoverageViewOptions &Options; /// Complete coverage information about the source on display. coverage::CoverageData CoverageInfo; /// A container for all expansions (e.g macros) in the source on display. std::vector ExpansionSubViews; /// A container for all instantiations (e.g template functions) in the source /// on display. std::vector InstantiationSubViews; /// \brief Render a source line with highlighting. void renderLine(raw_ostream &OS, StringRef Line, int64_t LineNumber, const coverage::CoverageSegment *WrappedSegment, ArrayRef Segments, unsigned ExpansionCol); void renderIndent(raw_ostream &OS, unsigned Level); void renderViewDivider(unsigned Offset, unsigned Length, raw_ostream &OS); /// \brief Render the line's execution count column. void renderLineCoverageColumn(raw_ostream &OS, const LineCoverageStats &Line); /// \brief Render the line number column. void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo); /// \brief Render all the region's execution counts on a line. void renderRegionMarkers(raw_ostream &OS, ArrayRef Segments); static const unsigned LineCoverageColumnWidth = 7; static const unsigned LineNumberColumnWidth = 5; public: SourceCoverageView(StringRef SourceName, const MemoryBuffer &File, const CoverageViewOptions &Options, coverage::CoverageData &&CoverageInfo) : SourceName(SourceName), File(File), Options(Options), CoverageInfo(std::move(CoverageInfo)) {} StringRef getSourceName() const { return SourceName; } const CoverageViewOptions &getOptions() const { return Options; } /// \brief Add an expansion subview to this view. void addExpansion(const coverage::CounterMappingRegion &Region, std::unique_ptr View) { ExpansionSubViews.emplace_back(Region, std::move(View)); } /// \brief Add a function instantiation subview to this view. void addInstantiation(StringRef FunctionName, unsigned Line, std::unique_ptr View) { InstantiationSubViews.emplace_back(FunctionName, Line, std::move(View)); } /// \brief Print the code coverage information for a specific /// portion of a source file to the output stream. void render(raw_ostream &OS, bool WholeFile, unsigned IndentLevel = 0); /// \brief Print the source name corresponding to this view. void renderSourceName(raw_ostream &OS); }; } // namespace llvm #endif // LLVM_COV_SOURCECOVERAGEVIEW_H