blob: 1b5a1ac01c55e3848487ac6c8eedc896c60b5c66 [file] [log] [blame]
Vedant Kumar7101d732016-07-26 22:50:58 +00001//===- CoverageExporterJson.cpp - Code coverage export --------------------===//
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 file implements export of code coverage data to JSON.
11//
12//===----------------------------------------------------------------------===//
13
14//===----------------------------------------------------------------------===//
15//
16// The json code coverage export follows the following format
17// Root: dict => Root Element containing metadata
18// -- Data: array => Homogeneous array of one or more export objects
19// ---- Export: dict => Json representation of one CoverageMapping
20// ------ Files: array => List of objects describing coverage for files
21// -------- File: dict => Coverage for a single file
22// ---------- Segments: array => List of Segments contained in the file
23// ------------ Segment: dict => Describes a segment of the file with a counter
24// ---------- Expansions: array => List of expansion records
25// ------------ Expansion: dict => Object that descibes a single expansion
26// -------------- CountedRegion: dict => The region to be expanded
27// -------------- TargetRegions: array => List of Regions in the expansion
28// ---------------- CountedRegion: dict => Single Region in the expansion
29// ---------- Summary: dict => Object summarizing the coverage for this file
30// ------------ LineCoverage: dict => Object summarizing line coverage
31// ------------ FunctionCoverage: dict => Object summarizing function coverage
32// ------------ RegionCoverage: dict => Object summarizing region coverage
33// ------ Functions: array => List of objects describing coverage for functions
34// -------- Function: dict => Coverage info for a single function
35// ---------- Filenames: array => List of filenames that the function relates to
36// ---- Summary: dict => Object summarizing the coverage for the entire binary
37// ------ LineCoverage: dict => Object summarizing line coverage
38// ------ FunctionCoverage: dict => Object summarizing function coverage
Vedant Kumar3c46abb2016-09-19 00:38:29 +000039// ------ InstantiationCoverage: dict => Object summarizing inst. coverage
Vedant Kumar7101d732016-07-26 22:50:58 +000040// ------ RegionCoverage: dict => Object summarizing region coverage
41//
42//===----------------------------------------------------------------------===//
43
Vedant Kumar3c46abb2016-09-19 00:38:29 +000044#include "CoverageReport.h"
Vedant Kumar7101d732016-07-26 22:50:58 +000045#include "CoverageSummaryInfo.h"
46#include "CoverageViewOptions.h"
47#include "llvm/ProfileData/Coverage/CoverageMapping.h"
48#include <stack>
49
Vedant Kumar7101d732016-07-26 22:50:58 +000050/// \brief The semantic version combined as a string.
Vedant Kumarb8d06942016-09-19 01:46:01 +000051#define LLVM_COVERAGE_EXPORT_JSON_STR "1.1.0"
Vedant Kumar7101d732016-07-26 22:50:58 +000052
53/// \brief Unique type identifier for JSON coverage export.
54#define LLVM_COVERAGE_EXPORT_JSON_TYPE_STR "llvm.coverage.json.export"
55
56using namespace llvm;
57using namespace coverage;
58
59class CoverageExporterJson {
60 /// \brief A Name of the object file coverage is for.
61 StringRef ObjectFilename;
62
63 /// \brief Output stream to print JSON to.
64 raw_ostream &OS;
65
66 /// \brief The full CoverageMapping object to export.
Vedant Kumar7cb9f002016-10-12 22:27:49 +000067 const CoverageMapping &Coverage;
Vedant Kumar7101d732016-07-26 22:50:58 +000068
69 /// \brief States that the JSON rendering machine can be in.
70 enum JsonState { None, NonEmptyElement, EmptyElement };
71
72 /// \brief Tracks state of the JSON output.
73 std::stack<JsonState> State;
74
75 /// \brief Get the object filename.
76 StringRef getObjectFilename() const { return ObjectFilename; }
77
78 /// \brief Emit a serialized scalar.
79 void emitSerialized(const int64_t Value) { OS << Value; }
80
81 /// \brief Emit a serialized string.
Vedant Kumar90be9db2016-07-27 04:08:32 +000082 void emitSerialized(const std::string &Value) {
83 OS << "\"";
84 for (char C : Value) {
85 if (C != '\\')
86 OS << C;
87 else
88 OS << "\\\\";
89 }
90 OS << "\"";
91 }
Vedant Kumar7101d732016-07-26 22:50:58 +000092
93 /// \brief Emit a comma if there is a previous element to delimit.
94 void emitComma() {
95 if (State.top() == JsonState::NonEmptyElement) {
96 OS << ",";
97 } else if (State.top() == JsonState::EmptyElement) {
98 State.pop();
99 assert((State.size() >= 1) && "Closed too many JSON elements");
100 State.push(JsonState::NonEmptyElement);
101 }
102 }
103
104 /// \brief Emit a starting dictionary/object character.
105 void emitDictStart() {
106 emitComma();
107 State.push(JsonState::EmptyElement);
108 OS << "{";
109 }
110
111 /// \brief Emit a dictionary/object key but no value.
112 void emitDictKey(const std::string &Key) {
113 emitComma();
Vedant Kumar90be9db2016-07-27 04:08:32 +0000114 emitSerialized(Key);
115 OS << ":";
Vedant Kumar7101d732016-07-26 22:50:58 +0000116 State.pop();
117 assert((State.size() >= 1) && "Closed too many JSON elements");
118
119 // We do not want to emit a comma after this key.
120 State.push(JsonState::EmptyElement);
121 }
122
123 /// \brief Emit a dictionary/object key/value pair.
124 template <typename V>
125 void emitDictElement(const std::string &Key, const V &Value) {
126 emitComma();
127 emitSerialized(Key);
128 OS << ":";
129 emitSerialized(Value);
130 }
131
132 /// \brief Emit a closing dictionary/object character.
133 void emitDictEnd() {
134 State.pop();
135 assert((State.size() >= 1) && "Closed too many JSON elements");
136 OS << "}";
137 }
138
139 /// \brief Emit a starting array character.
140 void emitArrayStart() {
141 emitComma();
142 State.push(JsonState::EmptyElement);
143 OS << "[";
144 }
145
146 /// \brief Emit an array element.
147 template <typename V> void emitArrayElement(const V &Value) {
148 emitComma();
149 emitSerialized(Value);
150 }
151
152 /// \brief emit a closing array character.
153 void emitArrayEnd() {
154 State.pop();
155 assert((State.size() >= 1) && "Closed too many JSON elements");
156 OS << "]";
157 }
158
159 /// \brief Render the CoverageMapping object.
160 void renderRoot() {
161 // Start Root of JSON object.
162 emitDictStart();
163
164 emitDictElement("version", LLVM_COVERAGE_EXPORT_JSON_STR);
165 emitDictElement("type", LLVM_COVERAGE_EXPORT_JSON_TYPE_STR);
166 emitDictKey("data");
167
168 // Start List of Exports.
169 emitArrayStart();
170
171 // Start Export.
172 emitDictStart();
173 emitDictElement("object", getObjectFilename());
174
175 emitDictKey("files");
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000176
Vedant Kumar7101d732016-07-26 22:50:58 +0000177 FileCoverageSummary Totals = FileCoverageSummary("Totals");
Vedant Kumarbc647982016-09-23 18:57:32 +0000178 std::vector<std::string> SourceFiles;
179 for (StringRef SF : Coverage.getUniqueSourceFiles())
180 SourceFiles.emplace_back(SF);
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000181 auto FileReports =
182 CoverageReport::prepareFileReports(Coverage, Totals, SourceFiles);
183 renderFiles(SourceFiles, FileReports);
Vedant Kumar7101d732016-07-26 22:50:58 +0000184
185 emitDictKey("functions");
186 renderFunctions(Coverage.getCoveredFunctions());
187
188 emitDictKey("totals");
189 renderSummary(Totals);
190
191 // End Export.
192 emitDictEnd();
193
194 // End List of Exports.
195 emitArrayEnd();
196
197 // End Root of JSON Object.
198 emitDictEnd();
199
200 assert((State.top() == JsonState::None) &&
201 "All Elements In JSON were Closed");
202 }
203
204 /// \brief Render an array of all the given functions.
205 void
206 renderFunctions(const iterator_range<FunctionRecordIterator> &Functions) {
207 // Start List of Functions.
208 emitArrayStart();
209
210 for (const auto &Function : Functions) {
211 // Start Function.
212 emitDictStart();
213
214 emitDictElement("name", Function.Name);
215 emitDictElement("count", Function.ExecutionCount);
216 emitDictKey("regions");
217
218 renderRegions(Function.CountedRegions);
219
220 emitDictKey("filenames");
221
222 // Start Filenames for Function.
223 emitArrayStart();
224
225 for (const auto &FileName : Function.Filenames)
226 emitArrayElement(FileName);
227
228 // End Filenames for Function.
229 emitArrayEnd();
230
231 // End Function.
232 emitDictEnd();
233 }
234
235 // End List of Functions.
236 emitArrayEnd();
237 }
238
239 /// \brief Render an array of all the source files, also pass back a Summary.
Vedant Kumarbc647982016-09-23 18:57:32 +0000240 void renderFiles(ArrayRef<std::string> SourceFiles,
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000241 ArrayRef<FileCoverageSummary> FileReports) {
Vedant Kumar7101d732016-07-26 22:50:58 +0000242 // Start List of Files.
243 emitArrayStart();
Vedant Kumar7101d732016-07-26 22:50:58 +0000244
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000245 for (unsigned I = 0, E = SourceFiles.size(); I < E; ++I) {
246 // Render the file.
247 auto FileCoverage = Coverage.getCoverageForFile(SourceFiles[I]);
248 renderFile(FileCoverage, FileReports[I]);
Vedant Kumar7101d732016-07-26 22:50:58 +0000249 }
250
251 // End List of Files.
252 emitArrayEnd();
253 }
254
255 /// \brief Render a single file.
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000256 void renderFile(const CoverageData &FileCoverage,
257 const FileCoverageSummary &FileReport) {
Vedant Kumar7101d732016-07-26 22:50:58 +0000258 // Start File.
259 emitDictStart();
260
261 emitDictElement("filename", FileCoverage.getFilename());
262 emitDictKey("segments");
263
264 // Start List of Segments.
265 emitArrayStart();
266
267 for (const auto &Segment : FileCoverage)
268 renderSegment(Segment);
269
270 // End List of Segments.
271 emitArrayEnd();
272
273 emitDictKey("expansions");
274
275 // Start List of Expansions.
276 emitArrayStart();
277
278 for (const auto &Expansion : FileCoverage.getExpansions())
279 renderExpansion(Expansion);
280
281 // End List of Expansions.
282 emitArrayEnd();
283
Vedant Kumar7101d732016-07-26 22:50:58 +0000284 emitDictKey("summary");
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000285 renderSummary(FileReport);
Vedant Kumar7101d732016-07-26 22:50:58 +0000286
287 // End File.
288 emitDictEnd();
289 }
290
291 /// \brief Render a CoverageSegment.
292 void renderSegment(const CoverageSegment &Segment) {
293 // Start Segment.
294 emitArrayStart();
295
296 emitArrayElement(Segment.Line);
297 emitArrayElement(Segment.Col);
298 emitArrayElement(Segment.Count);
299 emitArrayElement(Segment.HasCount);
300 emitArrayElement(Segment.IsRegionEntry);
301
302 // End Segment.
303 emitArrayEnd();
304 }
305
306 /// \brief Render an ExpansionRecord.
307 void renderExpansion(const ExpansionRecord &Expansion) {
308 // Start Expansion.
309 emitDictStart();
310
311 // Mark the beginning and end of this expansion in the source file.
312 emitDictKey("source_region");
313 renderRegion(Expansion.Region);
314
315 // Enumerate the coverage information for the expansion.
316 emitDictKey("target_regions");
317 renderRegions(Expansion.Function.CountedRegions);
318
319 emitDictKey("filenames");
320 // Start List of Filenames to map the fileIDs.
321 emitArrayStart();
322 for (const auto &Filename : Expansion.Function.Filenames)
323 emitArrayElement(Filename);
324 // End List of Filenames.
325 emitArrayEnd();
326
327 // End Expansion.
328 emitDictEnd();
329 }
330
331 /// \brief Render a list of CountedRegions.
332 void renderRegions(ArrayRef<CountedRegion> Regions) {
333 // Start List of Regions.
334 emitArrayStart();
335
336 for (const auto &Region : Regions)
337 renderRegion(Region);
338
339 // End List of Regions.
340 emitArrayEnd();
341 }
342
343 /// \brief Render a single CountedRegion.
344 void renderRegion(const CountedRegion &Region) {
345 // Start CountedRegion.
346 emitArrayStart();
347
348 emitArrayElement(Region.LineStart);
349 emitArrayElement(Region.ColumnStart);
350 emitArrayElement(Region.LineEnd);
351 emitArrayElement(Region.ColumnEnd);
352 emitArrayElement(Region.ExecutionCount);
353 emitArrayElement(Region.FileID);
354 emitArrayElement(Region.ExpandedFileID);
355 emitArrayElement(Region.Kind);
356
357 // End CountedRegion.
358 emitArrayEnd();
359 }
360
361 /// \brief Render a FileCoverageSummary.
362 void renderSummary(const FileCoverageSummary &Summary) {
363 // Start Summary for the file.
364 emitDictStart();
365
366 emitDictKey("lines");
367
368 // Start Line Coverage Summary.
369 emitDictStart();
370 emitDictElement("count", Summary.LineCoverage.NumLines);
371 emitDictElement("covered", Summary.LineCoverage.Covered);
372 emitDictElement("percent", Summary.LineCoverage.getPercentCovered());
Vedant Kumar7101d732016-07-26 22:50:58 +0000373 // End Line Coverage Summary.
374 emitDictEnd();
375
376 emitDictKey("functions");
377
378 // Start Function Coverage Summary.
379 emitDictStart();
380 emitDictElement("count", Summary.FunctionCoverage.NumFunctions);
381 emitDictElement("covered", Summary.FunctionCoverage.Executed);
382 emitDictElement("percent", Summary.FunctionCoverage.getPercentCovered());
383 // End Function Coverage Summary.
384 emitDictEnd();
385
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000386 emitDictKey("instantiations");
387
388 // Start Instantiation Coverage Summary.
389 emitDictStart();
390 emitDictElement("count", Summary.InstantiationCoverage.NumFunctions);
391 emitDictElement("covered", Summary.InstantiationCoverage.Executed);
392 emitDictElement("percent",
393 Summary.InstantiationCoverage.getPercentCovered());
394 // End Function Coverage Summary.
395 emitDictEnd();
396
Vedant Kumar7101d732016-07-26 22:50:58 +0000397 emitDictKey("regions");
398
399 // Start Region Coverage Summary.
400 emitDictStart();
401 emitDictElement("count", Summary.RegionCoverage.NumRegions);
402 emitDictElement("covered", Summary.RegionCoverage.Covered);
403 emitDictElement("notcovered", Summary.RegionCoverage.NotCovered);
404 emitDictElement("percent", Summary.RegionCoverage.getPercentCovered());
405 // End Region Coverage Summary.
406 emitDictEnd();
407
408 // End Summary for the file.
409 emitDictEnd();
410 }
411
412public:
413 CoverageExporterJson(StringRef ObjectFilename,
414 const CoverageMapping &CoverageMapping, raw_ostream &OS)
415 : ObjectFilename(ObjectFilename), OS(OS), Coverage(CoverageMapping) {
416 State.push(JsonState::None);
417 }
418
419 /// \brief Print the CoverageMapping.
420 void print() { renderRoot(); }
421};
422
423/// \brief Export the given CoverageMapping to a JSON Format.
424void exportCoverageDataToJson(StringRef ObjectFilename,
425 const CoverageMapping &CoverageMapping,
426 raw_ostream &OS) {
427 auto Exporter = CoverageExporterJson(ObjectFilename, CoverageMapping, OS);
428
429 Exporter.print();
430}