Mercurial > hg > CbC > CbC_llvm
comparison tools/llvm-cov/SourceCoverageViewText.cpp @ 122:36195a0db682
merging ( incomplete )
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 17 Nov 2017 20:32:31 +0900 |
parents | 803732b1fca8 |
children | 3a76565eade5 |
comparison
equal
deleted
inserted
replaced
119:d9df2cbd60cd | 122:36195a0db682 |
---|---|
1 //===- SourceCoverageViewText.cpp - A text-based code coverage view -------===// | |
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 /// \file This file implements the text-based coverage renderer. | |
11 /// | |
12 //===----------------------------------------------------------------------===// | |
13 | |
14 #include "CoverageReport.h" | |
15 #include "SourceCoverageViewText.h" | |
16 #include "llvm/ADT/Optional.h" | |
17 #include "llvm/ADT/SmallString.h" | |
18 #include "llvm/ADT/StringExtras.h" | |
19 | |
20 using namespace llvm; | |
21 | |
22 Expected<CoveragePrinter::OwnedStream> | |
23 CoveragePrinterText::createViewFile(StringRef Path, bool InToplevel) { | |
24 return createOutputStream(Path, "txt", InToplevel); | |
25 } | |
26 | |
27 void CoveragePrinterText::closeViewFile(OwnedStream OS) { | |
28 OS->operator<<('\n'); | |
29 } | |
30 | |
31 Error CoveragePrinterText::createIndexFile( | |
32 ArrayRef<std::string> SourceFiles, const CoverageMapping &Coverage, | |
33 const CoverageFiltersMatchAll &Filters) { | |
34 auto OSOrErr = createOutputStream("index", "txt", /*InToplevel=*/true); | |
35 if (Error E = OSOrErr.takeError()) | |
36 return E; | |
37 auto OS = std::move(OSOrErr.get()); | |
38 raw_ostream &OSRef = *OS.get(); | |
39 | |
40 CoverageReport Report(Opts, Coverage); | |
41 Report.renderFileReports(OSRef, SourceFiles, Filters); | |
42 | |
43 Opts.colored_ostream(OSRef, raw_ostream::CYAN) << "\n" | |
44 << Opts.getLLVMVersionString(); | |
45 | |
46 return Error::success(); | |
47 } | |
48 | |
49 namespace { | |
50 | |
51 static const unsigned LineCoverageColumnWidth = 7; | |
52 static const unsigned LineNumberColumnWidth = 5; | |
53 | |
54 /// \brief Get the width of the leading columns. | |
55 unsigned getCombinedColumnWidth(const CoverageViewOptions &Opts) { | |
56 return (Opts.ShowLineStats ? LineCoverageColumnWidth + 1 : 0) + | |
57 (Opts.ShowLineNumbers ? LineNumberColumnWidth + 1 : 0); | |
58 } | |
59 | |
60 /// \brief The width of the line that is used to divide between the view and | |
61 /// the subviews. | |
62 unsigned getDividerWidth(const CoverageViewOptions &Opts) { | |
63 return getCombinedColumnWidth(Opts) + 4; | |
64 } | |
65 | |
66 } // anonymous namespace | |
67 | |
68 void SourceCoverageViewText::renderViewHeader(raw_ostream &) {} | |
69 | |
70 void SourceCoverageViewText::renderViewFooter(raw_ostream &) {} | |
71 | |
72 void SourceCoverageViewText::renderSourceName(raw_ostream &OS, bool WholeFile) { | |
73 getOptions().colored_ostream(OS, raw_ostream::CYAN) << getSourceName() | |
74 << ":\n"; | |
75 } | |
76 | |
77 void SourceCoverageViewText::renderLinePrefix(raw_ostream &OS, | |
78 unsigned ViewDepth) { | |
79 for (unsigned I = 0; I < ViewDepth; ++I) | |
80 OS << " |"; | |
81 } | |
82 | |
83 void SourceCoverageViewText::renderLineSuffix(raw_ostream &, unsigned) {} | |
84 | |
85 void SourceCoverageViewText::renderViewDivider(raw_ostream &OS, | |
86 unsigned ViewDepth) { | |
87 assert(ViewDepth != 0 && "Cannot render divider at top level"); | |
88 renderLinePrefix(OS, ViewDepth - 1); | |
89 OS.indent(2); | |
90 unsigned Length = getDividerWidth(getOptions()); | |
91 for (unsigned I = 0; I < Length; ++I) | |
92 OS << '-'; | |
93 OS << '\n'; | |
94 } | |
95 | |
96 void SourceCoverageViewText::renderLine(raw_ostream &OS, LineRef L, | |
97 const LineCoverageStats &LCS, | |
98 unsigned ExpansionCol, | |
99 unsigned ViewDepth) { | |
100 StringRef Line = L.Line; | |
101 unsigned LineNumber = L.LineNo; | |
102 auto *WrappedSegment = LCS.getWrappedSegment(); | |
103 CoverageSegmentArray Segments = LCS.getLineSegments(); | |
104 | |
105 Optional<raw_ostream::Colors> Highlight; | |
106 SmallVector<std::pair<unsigned, unsigned>, 2> HighlightedRanges; | |
107 | |
108 // The first segment overlaps from a previous line, so we treat it specially. | |
109 if (WrappedSegment && WrappedSegment->HasCount && WrappedSegment->Count == 0) | |
110 Highlight = raw_ostream::RED; | |
111 | |
112 // Output each segment of the line, possibly highlighted. | |
113 unsigned Col = 1; | |
114 for (const auto *S : Segments) { | |
115 unsigned End = std::min(S->Col, static_cast<unsigned>(Line.size()) + 1); | |
116 colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR, | |
117 getOptions().Colors && Highlight, /*Bold=*/false, | |
118 /*BG=*/true) | |
119 << Line.substr(Col - 1, End - Col); | |
120 if (getOptions().Debug && Highlight) | |
121 HighlightedRanges.push_back(std::make_pair(Col, End)); | |
122 Col = End; | |
123 if (Col == ExpansionCol) | |
124 Highlight = raw_ostream::CYAN; | |
125 else if ((!S->IsGapRegion || Highlight == raw_ostream::RED) && | |
126 S->HasCount && S->Count == 0) | |
127 Highlight = raw_ostream::RED; | |
128 else | |
129 Highlight = None; | |
130 } | |
131 | |
132 // Show the rest of the line. | |
133 colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR, | |
134 getOptions().Colors && Highlight, /*Bold=*/false, /*BG=*/true) | |
135 << Line.substr(Col - 1, Line.size() - Col + 1); | |
136 OS << '\n'; | |
137 | |
138 if (getOptions().Debug) { | |
139 for (const auto &Range : HighlightedRanges) | |
140 errs() << "Highlighted line " << LineNumber << ", " << Range.first | |
141 << " -> " << Range.second << '\n'; | |
142 if (Highlight) | |
143 errs() << "Highlighted line " << LineNumber << ", " << Col << " -> ?\n"; | |
144 } | |
145 } | |
146 | |
147 void SourceCoverageViewText::renderLineCoverageColumn( | |
148 raw_ostream &OS, const LineCoverageStats &Line) { | |
149 if (!Line.isMapped()) { | |
150 OS.indent(LineCoverageColumnWidth) << '|'; | |
151 return; | |
152 } | |
153 std::string C = formatCount(Line.getExecutionCount()); | |
154 OS.indent(LineCoverageColumnWidth - C.size()); | |
155 colored_ostream(OS, raw_ostream::MAGENTA, | |
156 Line.hasMultipleRegions() && getOptions().Colors) | |
157 << C; | |
158 OS << '|'; | |
159 } | |
160 | |
161 void SourceCoverageViewText::renderLineNumberColumn(raw_ostream &OS, | |
162 unsigned LineNo) { | |
163 SmallString<32> Buffer; | |
164 raw_svector_ostream BufferOS(Buffer); | |
165 BufferOS << LineNo; | |
166 auto Str = BufferOS.str(); | |
167 // Trim and align to the right. | |
168 Str = Str.substr(0, std::min(Str.size(), (size_t)LineNumberColumnWidth)); | |
169 OS.indent(LineNumberColumnWidth - Str.size()) << Str << '|'; | |
170 } | |
171 | |
172 void SourceCoverageViewText::renderRegionMarkers(raw_ostream &OS, | |
173 const LineCoverageStats &Line, | |
174 unsigned ViewDepth) { | |
175 renderLinePrefix(OS, ViewDepth); | |
176 OS.indent(getCombinedColumnWidth(getOptions())); | |
177 | |
178 CoverageSegmentArray Segments = Line.getLineSegments(); | |
179 | |
180 // Just consider the segments which start *and* end on this line. | |
181 if (Segments.size() > 1) | |
182 Segments = Segments.drop_back(); | |
183 | |
184 unsigned PrevColumn = 1; | |
185 for (const auto *S : Segments) { | |
186 if (!S->IsRegionEntry) | |
187 continue; | |
188 if (S->Count == Line.getExecutionCount()) | |
189 continue; | |
190 // Skip to the new region. | |
191 if (S->Col > PrevColumn) | |
192 OS.indent(S->Col - PrevColumn); | |
193 PrevColumn = S->Col + 1; | |
194 std::string C = formatCount(S->Count); | |
195 PrevColumn += C.size(); | |
196 OS << '^' << C; | |
197 | |
198 if (getOptions().Debug) | |
199 errs() << "Marker at " << S->Line << ":" << S->Col << " = " | |
200 << formatCount(S->Count) << "\n"; | |
201 } | |
202 OS << '\n'; | |
203 } | |
204 | |
205 void SourceCoverageViewText::renderExpansionSite(raw_ostream &OS, LineRef L, | |
206 const LineCoverageStats &LCS, | |
207 unsigned ExpansionCol, | |
208 unsigned ViewDepth) { | |
209 renderLinePrefix(OS, ViewDepth); | |
210 OS.indent(getCombinedColumnWidth(getOptions()) + (ViewDepth == 0 ? 0 : 1)); | |
211 renderLine(OS, L, LCS, ExpansionCol, ViewDepth); | |
212 } | |
213 | |
214 void SourceCoverageViewText::renderExpansionView(raw_ostream &OS, | |
215 ExpansionView &ESV, | |
216 unsigned ViewDepth) { | |
217 // Render the child subview. | |
218 if (getOptions().Debug) | |
219 errs() << "Expansion at line " << ESV.getLine() << ", " << ESV.getStartCol() | |
220 << " -> " << ESV.getEndCol() << '\n'; | |
221 ESV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/false, | |
222 /*ShowTitle=*/false, ViewDepth + 1); | |
223 } | |
224 | |
225 void SourceCoverageViewText::renderInstantiationView(raw_ostream &OS, | |
226 InstantiationView &ISV, | |
227 unsigned ViewDepth) { | |
228 renderLinePrefix(OS, ViewDepth); | |
229 OS << ' '; | |
230 if (!ISV.View) | |
231 getOptions().colored_ostream(OS, raw_ostream::RED) | |
232 << "Unexecuted instantiation: " << ISV.FunctionName << "\n"; | |
233 else | |
234 ISV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/true, | |
235 /*ShowTitle=*/false, ViewDepth); | |
236 } | |
237 | |
238 void SourceCoverageViewText::renderTitle(raw_ostream &OS, StringRef Title) { | |
239 if (getOptions().hasProjectTitle()) | |
240 getOptions().colored_ostream(OS, raw_ostream::CYAN) | |
241 << getOptions().ProjectTitle << "\n"; | |
242 | |
243 getOptions().colored_ostream(OS, raw_ostream::CYAN) << Title << "\n"; | |
244 | |
245 if (getOptions().hasCreatedTime()) | |
246 getOptions().colored_ostream(OS, raw_ostream::CYAN) | |
247 << getOptions().CreatedTimeStr << "\n"; | |
248 } | |
249 | |
250 void SourceCoverageViewText::renderTableHeader(raw_ostream &, unsigned, | |
251 unsigned) {} |