1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
|
//===- 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 "SourceCoverageDataManager.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 {
public:
/// \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) {
Mapped = true;
ExecutionCount = Count;
++RegionCount;
}
void addRegionCount(uint64_t Count) {
Mapped = true;
ExecutionCount = Count;
}
};
/// \brief A marker that points at the start
/// of a specific mapping region.
struct RegionMarker {
unsigned Line, Column;
uint64_t ExecutionCount;
RegionMarker(unsigned Line, unsigned Column, uint64_t Value)
: Line(Line), Column(Column), ExecutionCount(Value) {}
};
/// \brief A single line source range used to
/// render highlighted text.
struct HighlightRange {
enum HighlightKind {
/// The code that wasn't executed.
NotCovered,
/// The region of code that was expanded.
Expanded
};
HighlightKind Kind;
unsigned Line;
unsigned ColumnStart;
unsigned ColumnEnd;
HighlightRange(unsigned Line, unsigned ColumnStart, unsigned ColumnEnd,
HighlightKind Kind = NotCovered)
: Kind(Kind), Line(Line), ColumnStart(ColumnStart),
ColumnEnd(ColumnEnd) {}
bool operator<(const HighlightRange &Other) const {
if (Line == Other.Line)
return ColumnStart < Other.ColumnStart;
return Line < Other.Line;
}
bool columnStartOverlaps(const HighlightRange &Other) const {
return ColumnStart <= Other.ColumnStart && ColumnEnd > Other.ColumnStart;
}
bool columnEndOverlaps(const HighlightRange &Other) const {
return ColumnEnd >= Other.ColumnEnd && ColumnStart < Other.ColumnEnd;
}
bool contains(const HighlightRange &Other) const {
if (Line != Other.Line)
return false;
return ColumnStart <= Other.ColumnStart && ColumnEnd >= Other.ColumnEnd;
}
bool overlaps(const HighlightRange &Other) const {
if (Line != Other.Line)
return false;
return columnStartOverlaps(Other) || columnEndOverlaps(Other);
}
};
private:
const MemoryBuffer &File;
const CoverageViewOptions &Options;
unsigned LineOffset;
std::vector<ExpansionView> ExpansionSubViews;
std::vector<InstantiationView> InstantiationSubViews;
std::vector<LineCoverageInfo> LineStats;
std::vector<HighlightRange> HighlightRanges;
std::vector<RegionMarker> Markers;
/// \brief Initialize the visible source range for this view.
void setUpVisibleRange(SourceCoverageDataManager &Data);
/// \brief Create the line coverage information using the coverage data.
void createLineCoverageInfo(SourceCoverageDataManager &Data);
/// \brief Create the line highlighting ranges using the coverage data.
void createHighlightRanges(SourceCoverageDataManager &Data);
/// \brief Create the region markers using the coverage data.
void createRegionMarkers(SourceCoverageDataManager &Data);
/// \brief Render a source line with highlighting.
void renderLine(raw_ostream &OS, StringRef Line,
ArrayRef<HighlightRange> Ranges);
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<RegionMarker> Regions);
static const unsigned LineCoverageColumnWidth = 7;
static const unsigned LineNumberColumnWidth = 5;
public:
SourceCoverageView(const MemoryBuffer &File,
const CoverageViewOptions &Options)
: File(File), Options(Options), LineOffset(0) {}
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, unsigned IndentLevel = 0);
/// \brief Load the coverage information required for rendering
/// from the mapping regions in the data manager.
void load(SourceCoverageDataManager &Data);
};
} // namespace llvm
#endif // LLVM_COV_SOURCECOVERAGEVIEW_H
|