blob: e2a798f4e692ceef6be95116c141d3490c9ac478 [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
50/// \brief Major version of the JSON Coverage Export Format.
51#define LLVM_COVERAGE_EXPORT_JSON_MAJOR 1
52
53/// \brief Minor version of the JSON Coverage Export Format.
54#define LLVM_COVERAGE_EXPORT_JSON_MINOR 0
55
56/// \brief Patch version of the JSON Coverage Export Format.
57#define LLVM_COVERAGE_EXPORT_JSON_PATCH 0
58
59/// \brief The semantic version combined as a string.
60#define LLVM_COVERAGE_EXPORT_JSON_STR "1.0.0"
61
62/// \brief Unique type identifier for JSON coverage export.
63#define LLVM_COVERAGE_EXPORT_JSON_TYPE_STR "llvm.coverage.json.export"
64
65using namespace llvm;
66using namespace coverage;
67
68class CoverageExporterJson {
69 /// \brief A Name of the object file coverage is for.
70 StringRef ObjectFilename;
71
72 /// \brief Output stream to print JSON to.
73 raw_ostream &OS;
74
75 /// \brief The full CoverageMapping object to export.
76 CoverageMapping Coverage;
77
78 /// \brief States that the JSON rendering machine can be in.
79 enum JsonState { None, NonEmptyElement, EmptyElement };
80
81 /// \brief Tracks state of the JSON output.
82 std::stack<JsonState> State;
83
84 /// \brief Get the object filename.
85 StringRef getObjectFilename() const { return ObjectFilename; }
86
87 /// \brief Emit a serialized scalar.
88 void emitSerialized(const int64_t Value) { OS << Value; }
89
90 /// \brief Emit a serialized string.
Vedant Kumar90be9db2016-07-27 04:08:32 +000091 void emitSerialized(const std::string &Value) {
92 OS << "\"";
93 for (char C : Value) {
94 if (C != '\\')
95 OS << C;
96 else
97 OS << "\\\\";
98 }
99 OS << "\"";
100 }
Vedant Kumar7101d732016-07-26 22:50:58 +0000101
102 /// \brief Emit a comma if there is a previous element to delimit.
103 void emitComma() {
104 if (State.top() == JsonState::NonEmptyElement) {
105 OS << ",";
106 } else if (State.top() == JsonState::EmptyElement) {
107 State.pop();
108 assert((State.size() >= 1) && "Closed too many JSON elements");
109 State.push(JsonState::NonEmptyElement);
110 }
111 }
112
113 /// \brief Emit a starting dictionary/object character.
114 void emitDictStart() {
115 emitComma();
116 State.push(JsonState::EmptyElement);
117 OS << "{";
118 }
119
120 /// \brief Emit a dictionary/object key but no value.
121 void emitDictKey(const std::string &Key) {
122 emitComma();
Vedant Kumar90be9db2016-07-27 04:08:32 +0000123 emitSerialized(Key);
124 OS << ":";
Vedant Kumar7101d732016-07-26 22:50:58 +0000125 State.pop();
126 assert((State.size() >= 1) && "Closed too many JSON elements");
127
128 // We do not want to emit a comma after this key.
129 State.push(JsonState::EmptyElement);
130 }
131
132 /// \brief Emit a dictionary/object key/value pair.
133 template <typename V>
134 void emitDictElement(const std::string &Key, const V &Value) {
135 emitComma();
136 emitSerialized(Key);
137 OS << ":";
138 emitSerialized(Value);
139 }
140
141 /// \brief Emit a closing dictionary/object character.
142 void emitDictEnd() {
143 State.pop();
144 assert((State.size() >= 1) && "Closed too many JSON elements");
145 OS << "}";
146 }
147
148 /// \brief Emit a starting array character.
149 void emitArrayStart() {
150 emitComma();
151 State.push(JsonState::EmptyElement);
152 OS << "[";
153 }
154
155 /// \brief Emit an array element.
156 template <typename V> void emitArrayElement(const V &Value) {
157 emitComma();
158 emitSerialized(Value);
159 }
160
161 /// \brief emit a closing array character.
162 void emitArrayEnd() {
163 State.pop();
164 assert((State.size() >= 1) && "Closed too many JSON elements");
165 OS << "]";
166 }
167
168 /// \brief Render the CoverageMapping object.
169 void renderRoot() {
170 // Start Root of JSON object.
171 emitDictStart();
172
173 emitDictElement("version", LLVM_COVERAGE_EXPORT_JSON_STR);
174 emitDictElement("type", LLVM_COVERAGE_EXPORT_JSON_TYPE_STR);
175 emitDictKey("data");
176
177 // Start List of Exports.
178 emitArrayStart();
179
180 // Start Export.
181 emitDictStart();
182 emitDictElement("object", getObjectFilename());
183
184 emitDictKey("files");
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000185
Vedant Kumar7101d732016-07-26 22:50:58 +0000186 FileCoverageSummary Totals = FileCoverageSummary("Totals");
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000187 std::vector<StringRef> SourceFiles = Coverage.getUniqueSourceFiles();
188 auto FileReports =
189 CoverageReport::prepareFileReports(Coverage, Totals, SourceFiles);
190 renderFiles(SourceFiles, FileReports);
Vedant Kumar7101d732016-07-26 22:50:58 +0000191
192 emitDictKey("functions");
193 renderFunctions(Coverage.getCoveredFunctions());
194
195 emitDictKey("totals");
196 renderSummary(Totals);
197
198 // End Export.
199 emitDictEnd();
200
201 // End List of Exports.
202 emitArrayEnd();
203
204 // End Root of JSON Object.
205 emitDictEnd();
206
207 assert((State.top() == JsonState::None) &&
208 "All Elements In JSON were Closed");
209 }
210
211 /// \brief Render an array of all the given functions.
212 void
213 renderFunctions(const iterator_range<FunctionRecordIterator> &Functions) {
214 // Start List of Functions.
215 emitArrayStart();
216
217 for (const auto &Function : Functions) {
218 // Start Function.
219 emitDictStart();
220
221 emitDictElement("name", Function.Name);
222 emitDictElement("count", Function.ExecutionCount);
223 emitDictKey("regions");
224
225 renderRegions(Function.CountedRegions);
226
227 emitDictKey("filenames");
228
229 // Start Filenames for Function.
230 emitArrayStart();
231
232 for (const auto &FileName : Function.Filenames)
233 emitArrayElement(FileName);
234
235 // End Filenames for Function.
236 emitArrayEnd();
237
238 // End Function.
239 emitDictEnd();
240 }
241
242 // End List of Functions.
243 emitArrayEnd();
244 }
245
246 /// \brief Render an array of all the source files, also pass back a Summary.
247 void renderFiles(ArrayRef<StringRef> SourceFiles,
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000248 ArrayRef<FileCoverageSummary> FileReports) {
Vedant Kumar7101d732016-07-26 22:50:58 +0000249 // Start List of Files.
250 emitArrayStart();
Vedant Kumar7101d732016-07-26 22:50:58 +0000251
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000252 for (unsigned I = 0, E = SourceFiles.size(); I < E; ++I) {
253 // Render the file.
254 auto FileCoverage = Coverage.getCoverageForFile(SourceFiles[I]);
255 renderFile(FileCoverage, FileReports[I]);
Vedant Kumar7101d732016-07-26 22:50:58 +0000256 }
257
258 // End List of Files.
259 emitArrayEnd();
260 }
261
262 /// \brief Render a single file.
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000263 void renderFile(const CoverageData &FileCoverage,
264 const FileCoverageSummary &FileReport) {
Vedant Kumar7101d732016-07-26 22:50:58 +0000265 // Start File.
266 emitDictStart();
267
268 emitDictElement("filename", FileCoverage.getFilename());
269 emitDictKey("segments");
270
271 // Start List of Segments.
272 emitArrayStart();
273
274 for (const auto &Segment : FileCoverage)
275 renderSegment(Segment);
276
277 // End List of Segments.
278 emitArrayEnd();
279
280 emitDictKey("expansions");
281
282 // Start List of Expansions.
283 emitArrayStart();
284
285 for (const auto &Expansion : FileCoverage.getExpansions())
286 renderExpansion(Expansion);
287
288 // End List of Expansions.
289 emitArrayEnd();
290
Vedant Kumar7101d732016-07-26 22:50:58 +0000291 emitDictKey("summary");
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000292 renderSummary(FileReport);
Vedant Kumar7101d732016-07-26 22:50:58 +0000293
294 // End File.
295 emitDictEnd();
296 }
297
298 /// \brief Render a CoverageSegment.
299 void renderSegment(const CoverageSegment &Segment) {
300 // Start Segment.
301 emitArrayStart();
302
303 emitArrayElement(Segment.Line);
304 emitArrayElement(Segment.Col);
305 emitArrayElement(Segment.Count);
306 emitArrayElement(Segment.HasCount);
307 emitArrayElement(Segment.IsRegionEntry);
308
309 // End Segment.
310 emitArrayEnd();
311 }
312
313 /// \brief Render an ExpansionRecord.
314 void renderExpansion(const ExpansionRecord &Expansion) {
315 // Start Expansion.
316 emitDictStart();
317
318 // Mark the beginning and end of this expansion in the source file.
319 emitDictKey("source_region");
320 renderRegion(Expansion.Region);
321
322 // Enumerate the coverage information for the expansion.
323 emitDictKey("target_regions");
324 renderRegions(Expansion.Function.CountedRegions);
325
326 emitDictKey("filenames");
327 // Start List of Filenames to map the fileIDs.
328 emitArrayStart();
329 for (const auto &Filename : Expansion.Function.Filenames)
330 emitArrayElement(Filename);
331 // End List of Filenames.
332 emitArrayEnd();
333
334 // End Expansion.
335 emitDictEnd();
336 }
337
338 /// \brief Render a list of CountedRegions.
339 void renderRegions(ArrayRef<CountedRegion> Regions) {
340 // Start List of Regions.
341 emitArrayStart();
342
343 for (const auto &Region : Regions)
344 renderRegion(Region);
345
346 // End List of Regions.
347 emitArrayEnd();
348 }
349
350 /// \brief Render a single CountedRegion.
351 void renderRegion(const CountedRegion &Region) {
352 // Start CountedRegion.
353 emitArrayStart();
354
355 emitArrayElement(Region.LineStart);
356 emitArrayElement(Region.ColumnStart);
357 emitArrayElement(Region.LineEnd);
358 emitArrayElement(Region.ColumnEnd);
359 emitArrayElement(Region.ExecutionCount);
360 emitArrayElement(Region.FileID);
361 emitArrayElement(Region.ExpandedFileID);
362 emitArrayElement(Region.Kind);
363
364 // End CountedRegion.
365 emitArrayEnd();
366 }
367
368 /// \brief Render a FileCoverageSummary.
369 void renderSummary(const FileCoverageSummary &Summary) {
370 // Start Summary for the file.
371 emitDictStart();
372
373 emitDictKey("lines");
374
375 // Start Line Coverage Summary.
376 emitDictStart();
377 emitDictElement("count", Summary.LineCoverage.NumLines);
378 emitDictElement("covered", Summary.LineCoverage.Covered);
379 emitDictElement("percent", Summary.LineCoverage.getPercentCovered());
380 emitDictElement("noncode", Summary.LineCoverage.NonCodeLines);
381 // End Line Coverage Summary.
382 emitDictEnd();
383
384 emitDictKey("functions");
385
386 // Start Function Coverage Summary.
387 emitDictStart();
388 emitDictElement("count", Summary.FunctionCoverage.NumFunctions);
389 emitDictElement("covered", Summary.FunctionCoverage.Executed);
390 emitDictElement("percent", Summary.FunctionCoverage.getPercentCovered());
391 // End Function Coverage Summary.
392 emitDictEnd();
393
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000394 emitDictKey("instantiations");
395
396 // Start Instantiation Coverage Summary.
397 emitDictStart();
398 emitDictElement("count", Summary.InstantiationCoverage.NumFunctions);
399 emitDictElement("covered", Summary.InstantiationCoverage.Executed);
400 emitDictElement("percent",
401 Summary.InstantiationCoverage.getPercentCovered());
402 // End Function Coverage Summary.
403 emitDictEnd();
404
Vedant Kumar7101d732016-07-26 22:50:58 +0000405 emitDictKey("regions");
406
407 // Start Region Coverage Summary.
408 emitDictStart();
409 emitDictElement("count", Summary.RegionCoverage.NumRegions);
410 emitDictElement("covered", Summary.RegionCoverage.Covered);
411 emitDictElement("notcovered", Summary.RegionCoverage.NotCovered);
412 emitDictElement("percent", Summary.RegionCoverage.getPercentCovered());
413 // End Region Coverage Summary.
414 emitDictEnd();
415
416 // End Summary for the file.
417 emitDictEnd();
418 }
419
420public:
421 CoverageExporterJson(StringRef ObjectFilename,
422 const CoverageMapping &CoverageMapping, raw_ostream &OS)
423 : ObjectFilename(ObjectFilename), OS(OS), Coverage(CoverageMapping) {
424 State.push(JsonState::None);
425 }
426
427 /// \brief Print the CoverageMapping.
428 void print() { renderRoot(); }
429};
430
431/// \brief Export the given CoverageMapping to a JSON Format.
432void exportCoverageDataToJson(StringRef ObjectFilename,
433 const CoverageMapping &CoverageMapping,
434 raw_ostream &OS) {
435 auto Exporter = CoverageExporterJson(ObjectFilename, CoverageMapping, OS);
436
437 Exporter.print();
438}