af44085cffcde4903b09e9c5150f3705f87899a7
[oota-llvm.git] / tools / llvm-cov / SourceCoverageView.h
1 //===- SourceCoverageView.h - Code coverage view for source code ----------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This class implements rendering for code coverage of source code.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_COV_SOURCECOVERAGEVIEW_H
15 #define LLVM_COV_SOURCECOVERAGEVIEW_H
16
17 #include "CoverageViewOptions.h"
18 #include "SourceCoverageDataManager.h"
19 #include "llvm/ProfileData/CoverageMapping.h"
20 #include "llvm/Support/MemoryBuffer.h"
21 #include <vector>
22
23 namespace llvm {
24
25 class SourceCoverageView;
26
27 /// \brief A view that represents a macro or include expansion
28 struct ExpansionView {
29   coverage::CounterMappingRegion Region;
30   std::unique_ptr<SourceCoverageView> View;
31
32   ExpansionView(const coverage::CounterMappingRegion &Region,
33                 std::unique_ptr<SourceCoverageView> View)
34       : Region(Region), View(std::move(View)) {}
35
36   unsigned getLine() const { return Region.LineStart; }
37   unsigned getStartCol() const { return Region.ColumnStart; }
38   unsigned getEndCol() const { return Region.ColumnEnd; }
39
40   friend bool operator<(const ExpansionView &LHS, const ExpansionView &RHS) {
41     return LHS.Region.startLoc() < RHS.Region.startLoc();
42   }
43 };
44
45 /// \brief A view that represents a function instantiation
46 struct InstantiationView {
47   StringRef FunctionName;
48   unsigned Line;
49   std::unique_ptr<SourceCoverageView> View;
50
51   InstantiationView(StringRef FunctionName, unsigned Line,
52                     std::unique_ptr<SourceCoverageView> View)
53       : FunctionName(FunctionName), Line(Line), View(std::move(View)) {}
54
55   friend bool operator<(const InstantiationView &LHS,
56                         const InstantiationView &RHS) {
57     return LHS.Line < RHS.Line;
58   }
59 };
60
61 /// \brief A code coverage view of a specific source file.
62 /// It can have embedded coverage views.
63 class SourceCoverageView {
64 public:
65   /// \brief Coverage information for a single line.
66   struct LineCoverageInfo {
67     uint64_t ExecutionCount;
68     unsigned RegionCount;
69     bool Mapped;
70
71     LineCoverageInfo() : ExecutionCount(0), RegionCount(0), Mapped(false) {}
72
73     bool isMapped() const { return Mapped; }
74
75     bool hasMultipleRegions() const { return RegionCount > 1; }
76
77     void addRegionStartCount(uint64_t Count) {
78       Mapped = true;
79       ExecutionCount = Count;
80       ++RegionCount;
81     }
82
83     void addRegionCount(uint64_t Count) {
84       Mapped = true;
85       ExecutionCount = Count;
86     }
87   };
88
89   /// \brief A marker that points at the start
90   /// of a specific mapping region.
91   struct RegionMarker {
92     unsigned Line, Column;
93     uint64_t ExecutionCount;
94
95     RegionMarker(unsigned Line, unsigned Column, uint64_t Value)
96         : Line(Line), Column(Column), ExecutionCount(Value) {}
97   };
98
99   /// \brief A single line source range used to
100   /// render highlighted text.
101   struct HighlightRange {
102     enum HighlightKind {
103       /// The code that wasn't executed.
104       NotCovered,
105
106       /// The region of code that was expanded.
107       Expanded
108     };
109     HighlightKind Kind;
110     unsigned Line;
111     unsigned ColumnStart;
112     unsigned ColumnEnd;
113
114     HighlightRange(unsigned Line, unsigned ColumnStart, unsigned ColumnEnd,
115                    HighlightKind Kind = NotCovered)
116         : Kind(Kind), Line(Line), ColumnStart(ColumnStart),
117           ColumnEnd(ColumnEnd) {}
118
119     bool operator<(const HighlightRange &Other) const {
120       if (Line == Other.Line)
121         return ColumnStart < Other.ColumnStart;
122       return Line < Other.Line;
123     }
124
125     bool columnStartOverlaps(const HighlightRange &Other) const {
126       return ColumnStart <= Other.ColumnStart && ColumnEnd > Other.ColumnStart;
127     }
128     bool columnEndOverlaps(const HighlightRange &Other) const {
129       return ColumnEnd >= Other.ColumnEnd && ColumnStart < Other.ColumnEnd;
130     }
131     bool contains(const HighlightRange &Other) const {
132       if (Line != Other.Line)
133         return false;
134       return ColumnStart <= Other.ColumnStart && ColumnEnd >= Other.ColumnEnd;
135     }
136
137     bool overlaps(const HighlightRange &Other) const {
138       if (Line != Other.Line)
139         return false;
140       return columnStartOverlaps(Other) || columnEndOverlaps(Other);
141     }
142   };
143
144 private:
145   const MemoryBuffer &File;
146   const CoverageViewOptions &Options;
147   unsigned LineOffset;
148   std::vector<ExpansionView> ExpansionSubViews;
149   std::vector<InstantiationView> InstantiationSubViews;
150   std::vector<LineCoverageInfo> LineStats;
151   std::vector<HighlightRange> HighlightRanges;
152   std::vector<RegionMarker> Markers;
153
154   /// \brief Initialize the visible source range for this view.
155   void setUpVisibleRange(SourceCoverageDataManager &Data);
156
157   /// \brief Create the line coverage information using the coverage data.
158   void createLineCoverageInfo(SourceCoverageDataManager &Data);
159
160   /// \brief Create the line highlighting ranges using the coverage data.
161   void createHighlightRanges(SourceCoverageDataManager &Data);
162
163   /// \brief Create the region markers using the coverage data.
164   void createRegionMarkers(SourceCoverageDataManager &Data);
165
166   /// \brief Render a source line with highlighting.
167   void renderLine(raw_ostream &OS, StringRef Line,
168                   ArrayRef<HighlightRange> Ranges);
169
170   void renderIndent(raw_ostream &OS, unsigned Level);
171
172   void renderViewDivider(unsigned Offset, unsigned Length, raw_ostream &OS);
173
174   /// \brief Render the line's execution count column.
175   void renderLineCoverageColumn(raw_ostream &OS, const LineCoverageInfo &Line);
176
177   /// \brief Render the line number column.
178   void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo);
179
180   /// \brief Render all the region's execution counts on a line.
181   void renderRegionMarkers(raw_ostream &OS, ArrayRef<RegionMarker> Regions);
182
183   static const unsigned LineCoverageColumnWidth = 7;
184   static const unsigned LineNumberColumnWidth = 5;
185
186 public:
187   SourceCoverageView(const MemoryBuffer &File,
188                      const CoverageViewOptions &Options)
189       : File(File), Options(Options), LineOffset(0) {}
190
191   const CoverageViewOptions &getOptions() const { return Options; }
192
193   /// \brief Add an expansion subview to this view.
194   void addExpansion(const coverage::CounterMappingRegion &Region,
195                     std::unique_ptr<SourceCoverageView> View) {
196     ExpansionSubViews.emplace_back(Region, std::move(View));
197   }
198
199   /// \brief Add a function instantiation subview to this view.
200   void addInstantiation(StringRef FunctionName, unsigned Line,
201                         std::unique_ptr<SourceCoverageView> View) {
202     InstantiationSubViews.emplace_back(FunctionName, Line, std::move(View));
203   }
204
205   /// \brief Print the code coverage information for a specific
206   /// portion of a source file to the output stream.
207   void render(raw_ostream &OS, unsigned IndentLevel = 0);
208
209   /// \brief Load the coverage information required for rendering
210   /// from the mapping regions in the data manager.
211   void load(SourceCoverageDataManager &Data);
212 };
213
214 } // namespace llvm
215
216 #endif // LLVM_COV_SOURCECOVERAGEVIEW_H