| //===- 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/CoverageMapping.h" |
| #include "llvm/Support/MemoryBuffer.h" |
| #include <vector> |
| |
| namespace llvm { |
| |
| class SourceCoverageView; |
| |
| /// \brief A view that represents a macro or include expansion |
| struct ExpansionView { |
| coverage::CounterMappingRegion Region; |
| std::unique_ptr<SourceCoverageView> View; |
| |
| ExpansionView(const coverage::CounterMappingRegion &Region, |
| std::unique_ptr<SourceCoverageView> 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<SourceCoverageView> View; |
| |
| InstantiationView(StringRef FunctionName, unsigned Line, |
| std::unique_ptr<SourceCoverageView> 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 A code coverage view of a specific source file. |
| /// It can have embedded coverage views. |
| class SourceCoverageView { |
| private: |
| /// \brief Coverage information for a single line. |
| struct LineCoverageInfo { |
| uint64_t ExecutionCount; |
| unsigned RegionCount; |
| bool Mapped; |
| |
| LineCoverageInfo() : 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; |
| } |
| }; |
| |
| const MemoryBuffer &File; |
| const CoverageViewOptions &Options; |
| coverage::CoverageData CoverageInfo; |
| std::vector<ExpansionView> ExpansionSubViews; |
| std::vector<InstantiationView> InstantiationSubViews; |
| |
| /// \brief Render a source line with highlighting. |
| void renderLine(raw_ostream &OS, StringRef Line, int64_t LineNumber, |
| const coverage::CoverageSegment *WrappedSegment, |
| ArrayRef<const coverage::CoverageSegment *> 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 LineCoverageInfo &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<const coverage::CoverageSegment *> Segments); |
| |
| static const unsigned LineCoverageColumnWidth = 7; |
| static const unsigned LineNumberColumnWidth = 5; |
| |
| public: |
| SourceCoverageView(const MemoryBuffer &File, |
| const CoverageViewOptions &Options, |
| coverage::CoverageData &&CoverageInfo) |
| : File(File), Options(Options), CoverageInfo(std::move(CoverageInfo)) {} |
| |
| const CoverageViewOptions &getOptions() const { return Options; } |
| |
| /// \brief Add an expansion subview to this view. |
| void addExpansion(const coverage::CounterMappingRegion &Region, |
| std::unique_ptr<SourceCoverageView> 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<SourceCoverageView> 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); |
| }; |
| |
| } // namespace llvm |
| |
| #endif // LLVM_COV_SOURCECOVERAGEVIEW_H |