blob: 5b6b09f048e391f9026cd06c710a3a47a457ccdf [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 Kumar5c61c702016-10-25 00:08:33 +000051#define LLVM_COVERAGE_EXPORT_JSON_STR "2.0.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 {
Vedant Kumar72c3a112017-09-08 18:44:49 +000060 const CoverageViewOptions &Options;
61
Vedant Kumar7101d732016-07-26 22:50:58 +000062 /// \brief Output stream to print JSON to.
63 raw_ostream &OS;
64
65 /// \brief The full CoverageMapping object to export.
Vedant Kumar7cb9f002016-10-12 22:27:49 +000066 const CoverageMapping &Coverage;
Vedant Kumar7101d732016-07-26 22:50:58 +000067
68 /// \brief States that the JSON rendering machine can be in.
69 enum JsonState { None, NonEmptyElement, EmptyElement };
70
71 /// \brief Tracks state of the JSON output.
72 std::stack<JsonState> State;
73
Vedant Kumar7101d732016-07-26 22:50:58 +000074 /// \brief Emit a serialized scalar.
75 void emitSerialized(const int64_t Value) { OS << Value; }
76
77 /// \brief Emit a serialized string.
Vedant Kumar90be9db2016-07-27 04:08:32 +000078 void emitSerialized(const std::string &Value) {
79 OS << "\"";
80 for (char C : Value) {
81 if (C != '\\')
82 OS << C;
83 else
84 OS << "\\\\";
85 }
86 OS << "\"";
87 }
Vedant Kumar7101d732016-07-26 22:50:58 +000088
89 /// \brief Emit a comma if there is a previous element to delimit.
90 void emitComma() {
91 if (State.top() == JsonState::NonEmptyElement) {
92 OS << ",";
93 } else if (State.top() == JsonState::EmptyElement) {
94 State.pop();
95 assert((State.size() >= 1) && "Closed too many JSON elements");
96 State.push(JsonState::NonEmptyElement);
97 }
98 }
99
100 /// \brief Emit a starting dictionary/object character.
101 void emitDictStart() {
102 emitComma();
103 State.push(JsonState::EmptyElement);
104 OS << "{";
105 }
106
107 /// \brief Emit a dictionary/object key but no value.
108 void emitDictKey(const std::string &Key) {
109 emitComma();
Vedant Kumar90be9db2016-07-27 04:08:32 +0000110 emitSerialized(Key);
111 OS << ":";
Vedant Kumar7101d732016-07-26 22:50:58 +0000112 State.pop();
113 assert((State.size() >= 1) && "Closed too many JSON elements");
114
115 // We do not want to emit a comma after this key.
116 State.push(JsonState::EmptyElement);
117 }
118
119 /// \brief Emit a dictionary/object key/value pair.
120 template <typename V>
121 void emitDictElement(const std::string &Key, const V &Value) {
122 emitComma();
123 emitSerialized(Key);
124 OS << ":";
125 emitSerialized(Value);
126 }
127
128 /// \brief Emit a closing dictionary/object character.
129 void emitDictEnd() {
130 State.pop();
131 assert((State.size() >= 1) && "Closed too many JSON elements");
132 OS << "}";
133 }
134
135 /// \brief Emit a starting array character.
136 void emitArrayStart() {
137 emitComma();
138 State.push(JsonState::EmptyElement);
139 OS << "[";
140 }
141
142 /// \brief Emit an array element.
143 template <typename V> void emitArrayElement(const V &Value) {
144 emitComma();
145 emitSerialized(Value);
146 }
147
148 /// \brief emit a closing array character.
149 void emitArrayEnd() {
150 State.pop();
151 assert((State.size() >= 1) && "Closed too many JSON elements");
152 OS << "]";
153 }
154
155 /// \brief Render the CoverageMapping object.
156 void renderRoot() {
157 // Start Root of JSON object.
158 emitDictStart();
159
160 emitDictElement("version", LLVM_COVERAGE_EXPORT_JSON_STR);
161 emitDictElement("type", LLVM_COVERAGE_EXPORT_JSON_TYPE_STR);
162 emitDictKey("data");
163
164 // Start List of Exports.
165 emitArrayStart();
166
167 // Start Export.
168 emitDictStart();
Vedant Kumar7101d732016-07-26 22:50:58 +0000169
170 emitDictKey("files");
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000171
Vedant Kumar7101d732016-07-26 22:50:58 +0000172 FileCoverageSummary Totals = FileCoverageSummary("Totals");
Vedant Kumarbc647982016-09-23 18:57:32 +0000173 std::vector<std::string> SourceFiles;
174 for (StringRef SF : Coverage.getUniqueSourceFiles())
175 SourceFiles.emplace_back(SF);
Vedant Kumar72c3a112017-09-08 18:44:49 +0000176 auto FileReports = CoverageReport::prepareFileReports(Coverage, Totals,
177 SourceFiles, Options);
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000178 renderFiles(SourceFiles, FileReports);
Vedant Kumar7101d732016-07-26 22:50:58 +0000179
180 emitDictKey("functions");
181 renderFunctions(Coverage.getCoveredFunctions());
182
183 emitDictKey("totals");
184 renderSummary(Totals);
185
186 // End Export.
187 emitDictEnd();
188
189 // End List of Exports.
190 emitArrayEnd();
191
192 // End Root of JSON Object.
193 emitDictEnd();
194
195 assert((State.top() == JsonState::None) &&
196 "All Elements In JSON were Closed");
197 }
198
199 /// \brief Render an array of all the given functions.
200 void
201 renderFunctions(const iterator_range<FunctionRecordIterator> &Functions) {
202 // Start List of Functions.
203 emitArrayStart();
204
205 for (const auto &Function : Functions) {
206 // Start Function.
207 emitDictStart();
208
209 emitDictElement("name", Function.Name);
210 emitDictElement("count", Function.ExecutionCount);
211 emitDictKey("regions");
212
213 renderRegions(Function.CountedRegions);
214
215 emitDictKey("filenames");
216
217 // Start Filenames for Function.
218 emitArrayStart();
219
220 for (const auto &FileName : Function.Filenames)
221 emitArrayElement(FileName);
222
223 // End Filenames for Function.
224 emitArrayEnd();
225
226 // End Function.
227 emitDictEnd();
228 }
229
230 // End List of Functions.
231 emitArrayEnd();
232 }
233
234 /// \brief Render an array of all the source files, also pass back a Summary.
Vedant Kumarbc647982016-09-23 18:57:32 +0000235 void renderFiles(ArrayRef<std::string> SourceFiles,
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000236 ArrayRef<FileCoverageSummary> FileReports) {
Vedant Kumar7101d732016-07-26 22:50:58 +0000237 // Start List of Files.
238 emitArrayStart();
Vedant Kumar7101d732016-07-26 22:50:58 +0000239
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000240 for (unsigned I = 0, E = SourceFiles.size(); I < E; ++I) {
241 // Render the file.
242 auto FileCoverage = Coverage.getCoverageForFile(SourceFiles[I]);
243 renderFile(FileCoverage, FileReports[I]);
Vedant Kumar7101d732016-07-26 22:50:58 +0000244 }
245
246 // End List of Files.
247 emitArrayEnd();
248 }
249
250 /// \brief Render a single file.
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000251 void renderFile(const CoverageData &FileCoverage,
252 const FileCoverageSummary &FileReport) {
Vedant Kumar7101d732016-07-26 22:50:58 +0000253 // Start File.
254 emitDictStart();
255
256 emitDictElement("filename", FileCoverage.getFilename());
257 emitDictKey("segments");
258
259 // Start List of Segments.
260 emitArrayStart();
261
262 for (const auto &Segment : FileCoverage)
263 renderSegment(Segment);
264
265 // End List of Segments.
266 emitArrayEnd();
267
268 emitDictKey("expansions");
269
270 // Start List of Expansions.
271 emitArrayStart();
272
273 for (const auto &Expansion : FileCoverage.getExpansions())
274 renderExpansion(Expansion);
275
276 // End List of Expansions.
277 emitArrayEnd();
278
Vedant Kumar7101d732016-07-26 22:50:58 +0000279 emitDictKey("summary");
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000280 renderSummary(FileReport);
Vedant Kumar7101d732016-07-26 22:50:58 +0000281
282 // End File.
283 emitDictEnd();
284 }
285
286 /// \brief Render a CoverageSegment.
287 void renderSegment(const CoverageSegment &Segment) {
288 // Start Segment.
289 emitArrayStart();
290
291 emitArrayElement(Segment.Line);
292 emitArrayElement(Segment.Col);
293 emitArrayElement(Segment.Count);
294 emitArrayElement(Segment.HasCount);
295 emitArrayElement(Segment.IsRegionEntry);
296
297 // End Segment.
298 emitArrayEnd();
299 }
300
301 /// \brief Render an ExpansionRecord.
302 void renderExpansion(const ExpansionRecord &Expansion) {
303 // Start Expansion.
304 emitDictStart();
305
306 // Mark the beginning and end of this expansion in the source file.
307 emitDictKey("source_region");
308 renderRegion(Expansion.Region);
309
310 // Enumerate the coverage information for the expansion.
311 emitDictKey("target_regions");
312 renderRegions(Expansion.Function.CountedRegions);
313
314 emitDictKey("filenames");
315 // Start List of Filenames to map the fileIDs.
316 emitArrayStart();
317 for (const auto &Filename : Expansion.Function.Filenames)
318 emitArrayElement(Filename);
319 // End List of Filenames.
320 emitArrayEnd();
321
322 // End Expansion.
323 emitDictEnd();
324 }
325
326 /// \brief Render a list of CountedRegions.
327 void renderRegions(ArrayRef<CountedRegion> Regions) {
328 // Start List of Regions.
329 emitArrayStart();
330
331 for (const auto &Region : Regions)
332 renderRegion(Region);
333
334 // End List of Regions.
335 emitArrayEnd();
336 }
337
338 /// \brief Render a single CountedRegion.
339 void renderRegion(const CountedRegion &Region) {
340 // Start CountedRegion.
341 emitArrayStart();
342
343 emitArrayElement(Region.LineStart);
344 emitArrayElement(Region.ColumnStart);
345 emitArrayElement(Region.LineEnd);
346 emitArrayElement(Region.ColumnEnd);
347 emitArrayElement(Region.ExecutionCount);
348 emitArrayElement(Region.FileID);
349 emitArrayElement(Region.ExpandedFileID);
350 emitArrayElement(Region.Kind);
351
352 // End CountedRegion.
353 emitArrayEnd();
354 }
355
356 /// \brief Render a FileCoverageSummary.
357 void renderSummary(const FileCoverageSummary &Summary) {
358 // Start Summary for the file.
359 emitDictStart();
360
361 emitDictKey("lines");
362
363 // Start Line Coverage Summary.
364 emitDictStart();
Vedant Kumarc445e652017-09-15 23:00:01 +0000365 emitDictElement("count", Summary.LineCoverage.getNumLines());
366 emitDictElement("covered", Summary.LineCoverage.getCovered());
Vedant Kumar7101d732016-07-26 22:50:58 +0000367 emitDictElement("percent", Summary.LineCoverage.getPercentCovered());
Vedant Kumar7101d732016-07-26 22:50:58 +0000368 // End Line Coverage Summary.
369 emitDictEnd();
370
371 emitDictKey("functions");
372
373 // Start Function Coverage Summary.
374 emitDictStart();
Vedant Kumarc445e652017-09-15 23:00:01 +0000375 emitDictElement("count", Summary.FunctionCoverage.getNumFunctions());
376 emitDictElement("covered", Summary.FunctionCoverage.getExecuted());
Vedant Kumar7101d732016-07-26 22:50:58 +0000377 emitDictElement("percent", Summary.FunctionCoverage.getPercentCovered());
378 // End Function Coverage Summary.
379 emitDictEnd();
380
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000381 emitDictKey("instantiations");
382
383 // Start Instantiation Coverage Summary.
384 emitDictStart();
Vedant Kumarc445e652017-09-15 23:00:01 +0000385 emitDictElement("count", Summary.InstantiationCoverage.getNumFunctions());
386 emitDictElement("covered", Summary.InstantiationCoverage.getExecuted());
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000387 emitDictElement("percent",
388 Summary.InstantiationCoverage.getPercentCovered());
389 // End Function Coverage Summary.
390 emitDictEnd();
391
Vedant Kumar7101d732016-07-26 22:50:58 +0000392 emitDictKey("regions");
393
394 // Start Region Coverage Summary.
395 emitDictStart();
Vedant Kumarc445e652017-09-15 23:00:01 +0000396 emitDictElement("count", Summary.RegionCoverage.getNumRegions());
397 emitDictElement("covered", Summary.RegionCoverage.getCovered());
Vedant Kumarb84e4842017-09-15 23:00:00 +0000398 emitDictElement("notcovered",
Vedant Kumarc445e652017-09-15 23:00:01 +0000399 Summary.RegionCoverage.getNumRegions() -
400 Summary.RegionCoverage.getCovered());
Vedant Kumar7101d732016-07-26 22:50:58 +0000401 emitDictElement("percent", Summary.RegionCoverage.getPercentCovered());
402 // End Region Coverage Summary.
403 emitDictEnd();
404
405 // End Summary for the file.
406 emitDictEnd();
407 }
408
409public:
Vedant Kumar72c3a112017-09-08 18:44:49 +0000410 CoverageExporterJson(const CoverageMapping &CoverageMapping,
411 const CoverageViewOptions &Options, raw_ostream &OS)
412 : Options(Options), OS(OS), Coverage(CoverageMapping) {
Vedant Kumar7101d732016-07-26 22:50:58 +0000413 State.push(JsonState::None);
414 }
415
416 /// \brief Print the CoverageMapping.
417 void print() { renderRoot(); }
418};
419
420/// \brief Export the given CoverageMapping to a JSON Format.
Vedant Kumar5c61c702016-10-25 00:08:33 +0000421void exportCoverageDataToJson(const CoverageMapping &CoverageMapping,
Vedant Kumar72c3a112017-09-08 18:44:49 +0000422 const CoverageViewOptions &Options,
Vedant Kumar7101d732016-07-26 22:50:58 +0000423 raw_ostream &OS) {
Vedant Kumar72c3a112017-09-08 18:44:49 +0000424 auto Exporter = CoverageExporterJson(CoverageMapping, Options, OS);
Vedant Kumar7101d732016-07-26 22:50:58 +0000425
426 Exporter.print();
427}