blob: ef50bba2123852d50eefb1b79cedcee591593181 [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 Kumar7101d732016-07-26 22:50:58 +000060 /// \brief Output stream to print JSON to.
61 raw_ostream &OS;
62
63 /// \brief The full CoverageMapping object to export.
Vedant Kumar7cb9f002016-10-12 22:27:49 +000064 const CoverageMapping &Coverage;
Vedant Kumar7101d732016-07-26 22:50:58 +000065
66 /// \brief States that the JSON rendering machine can be in.
67 enum JsonState { None, NonEmptyElement, EmptyElement };
68
69 /// \brief Tracks state of the JSON output.
70 std::stack<JsonState> State;
71
Vedant Kumar7101d732016-07-26 22:50:58 +000072 /// \brief Emit a serialized scalar.
73 void emitSerialized(const int64_t Value) { OS << Value; }
74
75 /// \brief Emit a serialized string.
Vedant Kumar90be9db2016-07-27 04:08:32 +000076 void emitSerialized(const std::string &Value) {
77 OS << "\"";
78 for (char C : Value) {
79 if (C != '\\')
80 OS << C;
81 else
82 OS << "\\\\";
83 }
84 OS << "\"";
85 }
Vedant Kumar7101d732016-07-26 22:50:58 +000086
87 /// \brief Emit a comma if there is a previous element to delimit.
88 void emitComma() {
89 if (State.top() == JsonState::NonEmptyElement) {
90 OS << ",";
91 } else if (State.top() == JsonState::EmptyElement) {
92 State.pop();
93 assert((State.size() >= 1) && "Closed too many JSON elements");
94 State.push(JsonState::NonEmptyElement);
95 }
96 }
97
98 /// \brief Emit a starting dictionary/object character.
99 void emitDictStart() {
100 emitComma();
101 State.push(JsonState::EmptyElement);
102 OS << "{";
103 }
104
105 /// \brief Emit a dictionary/object key but no value.
106 void emitDictKey(const std::string &Key) {
107 emitComma();
Vedant Kumar90be9db2016-07-27 04:08:32 +0000108 emitSerialized(Key);
109 OS << ":";
Vedant Kumar7101d732016-07-26 22:50:58 +0000110 State.pop();
111 assert((State.size() >= 1) && "Closed too many JSON elements");
112
113 // We do not want to emit a comma after this key.
114 State.push(JsonState::EmptyElement);
115 }
116
117 /// \brief Emit a dictionary/object key/value pair.
118 template <typename V>
119 void emitDictElement(const std::string &Key, const V &Value) {
120 emitComma();
121 emitSerialized(Key);
122 OS << ":";
123 emitSerialized(Value);
124 }
125
126 /// \brief Emit a closing dictionary/object character.
127 void emitDictEnd() {
128 State.pop();
129 assert((State.size() >= 1) && "Closed too many JSON elements");
130 OS << "}";
131 }
132
133 /// \brief Emit a starting array character.
134 void emitArrayStart() {
135 emitComma();
136 State.push(JsonState::EmptyElement);
137 OS << "[";
138 }
139
140 /// \brief Emit an array element.
141 template <typename V> void emitArrayElement(const V &Value) {
142 emitComma();
143 emitSerialized(Value);
144 }
145
146 /// \brief emit a closing array character.
147 void emitArrayEnd() {
148 State.pop();
149 assert((State.size() >= 1) && "Closed too many JSON elements");
150 OS << "]";
151 }
152
153 /// \brief Render the CoverageMapping object.
154 void renderRoot() {
155 // Start Root of JSON object.
156 emitDictStart();
157
158 emitDictElement("version", LLVM_COVERAGE_EXPORT_JSON_STR);
159 emitDictElement("type", LLVM_COVERAGE_EXPORT_JSON_TYPE_STR);
160 emitDictKey("data");
161
162 // Start List of Exports.
163 emitArrayStart();
164
165 // Start Export.
166 emitDictStart();
Vedant Kumar7101d732016-07-26 22:50:58 +0000167
168 emitDictKey("files");
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000169
Vedant Kumar7101d732016-07-26 22:50:58 +0000170 FileCoverageSummary Totals = FileCoverageSummary("Totals");
Vedant Kumarbc647982016-09-23 18:57:32 +0000171 std::vector<std::string> SourceFiles;
172 for (StringRef SF : Coverage.getUniqueSourceFiles())
173 SourceFiles.emplace_back(SF);
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000174 auto FileReports =
175 CoverageReport::prepareFileReports(Coverage, Totals, SourceFiles);
176 renderFiles(SourceFiles, FileReports);
Vedant Kumar7101d732016-07-26 22:50:58 +0000177
178 emitDictKey("functions");
179 renderFunctions(Coverage.getCoveredFunctions());
180
181 emitDictKey("totals");
182 renderSummary(Totals);
183
184 // End Export.
185 emitDictEnd();
186
187 // End List of Exports.
188 emitArrayEnd();
189
190 // End Root of JSON Object.
191 emitDictEnd();
192
193 assert((State.top() == JsonState::None) &&
194 "All Elements In JSON were Closed");
195 }
196
197 /// \brief Render an array of all the given functions.
198 void
199 renderFunctions(const iterator_range<FunctionRecordIterator> &Functions) {
200 // Start List of Functions.
201 emitArrayStart();
202
203 for (const auto &Function : Functions) {
204 // Start Function.
205 emitDictStart();
206
207 emitDictElement("name", Function.Name);
208 emitDictElement("count", Function.ExecutionCount);
209 emitDictKey("regions");
210
211 renderRegions(Function.CountedRegions);
212
213 emitDictKey("filenames");
214
215 // Start Filenames for Function.
216 emitArrayStart();
217
218 for (const auto &FileName : Function.Filenames)
219 emitArrayElement(FileName);
220
221 // End Filenames for Function.
222 emitArrayEnd();
223
224 // End Function.
225 emitDictEnd();
226 }
227
228 // End List of Functions.
229 emitArrayEnd();
230 }
231
232 /// \brief Render an array of all the source files, also pass back a Summary.
Vedant Kumarbc647982016-09-23 18:57:32 +0000233 void renderFiles(ArrayRef<std::string> SourceFiles,
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000234 ArrayRef<FileCoverageSummary> FileReports) {
Vedant Kumar7101d732016-07-26 22:50:58 +0000235 // Start List of Files.
236 emitArrayStart();
Vedant Kumar7101d732016-07-26 22:50:58 +0000237
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000238 for (unsigned I = 0, E = SourceFiles.size(); I < E; ++I) {
239 // Render the file.
240 auto FileCoverage = Coverage.getCoverageForFile(SourceFiles[I]);
241 renderFile(FileCoverage, FileReports[I]);
Vedant Kumar7101d732016-07-26 22:50:58 +0000242 }
243
244 // End List of Files.
245 emitArrayEnd();
246 }
247
248 /// \brief Render a single file.
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000249 void renderFile(const CoverageData &FileCoverage,
250 const FileCoverageSummary &FileReport) {
Vedant Kumar7101d732016-07-26 22:50:58 +0000251 // Start File.
252 emitDictStart();
253
254 emitDictElement("filename", FileCoverage.getFilename());
255 emitDictKey("segments");
256
257 // Start List of Segments.
258 emitArrayStart();
259
260 for (const auto &Segment : FileCoverage)
261 renderSegment(Segment);
262
263 // End List of Segments.
264 emitArrayEnd();
265
266 emitDictKey("expansions");
267
268 // Start List of Expansions.
269 emitArrayStart();
270
271 for (const auto &Expansion : FileCoverage.getExpansions())
272 renderExpansion(Expansion);
273
274 // End List of Expansions.
275 emitArrayEnd();
276
Vedant Kumar7101d732016-07-26 22:50:58 +0000277 emitDictKey("summary");
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000278 renderSummary(FileReport);
Vedant Kumar7101d732016-07-26 22:50:58 +0000279
280 // End File.
281 emitDictEnd();
282 }
283
284 /// \brief Render a CoverageSegment.
285 void renderSegment(const CoverageSegment &Segment) {
286 // Start Segment.
287 emitArrayStart();
288
289 emitArrayElement(Segment.Line);
290 emitArrayElement(Segment.Col);
291 emitArrayElement(Segment.Count);
292 emitArrayElement(Segment.HasCount);
293 emitArrayElement(Segment.IsRegionEntry);
294
295 // End Segment.
296 emitArrayEnd();
297 }
298
299 /// \brief Render an ExpansionRecord.
300 void renderExpansion(const ExpansionRecord &Expansion) {
301 // Start Expansion.
302 emitDictStart();
303
304 // Mark the beginning and end of this expansion in the source file.
305 emitDictKey("source_region");
306 renderRegion(Expansion.Region);
307
308 // Enumerate the coverage information for the expansion.
309 emitDictKey("target_regions");
310 renderRegions(Expansion.Function.CountedRegions);
311
312 emitDictKey("filenames");
313 // Start List of Filenames to map the fileIDs.
314 emitArrayStart();
315 for (const auto &Filename : Expansion.Function.Filenames)
316 emitArrayElement(Filename);
317 // End List of Filenames.
318 emitArrayEnd();
319
320 // End Expansion.
321 emitDictEnd();
322 }
323
324 /// \brief Render a list of CountedRegions.
325 void renderRegions(ArrayRef<CountedRegion> Regions) {
326 // Start List of Regions.
327 emitArrayStart();
328
329 for (const auto &Region : Regions)
330 renderRegion(Region);
331
332 // End List of Regions.
333 emitArrayEnd();
334 }
335
336 /// \brief Render a single CountedRegion.
337 void renderRegion(const CountedRegion &Region) {
338 // Start CountedRegion.
339 emitArrayStart();
340
341 emitArrayElement(Region.LineStart);
342 emitArrayElement(Region.ColumnStart);
343 emitArrayElement(Region.LineEnd);
344 emitArrayElement(Region.ColumnEnd);
345 emitArrayElement(Region.ExecutionCount);
346 emitArrayElement(Region.FileID);
347 emitArrayElement(Region.ExpandedFileID);
348 emitArrayElement(Region.Kind);
349
350 // End CountedRegion.
351 emitArrayEnd();
352 }
353
354 /// \brief Render a FileCoverageSummary.
355 void renderSummary(const FileCoverageSummary &Summary) {
356 // Start Summary for the file.
357 emitDictStart();
358
359 emitDictKey("lines");
360
361 // Start Line Coverage Summary.
362 emitDictStart();
363 emitDictElement("count", Summary.LineCoverage.NumLines);
364 emitDictElement("covered", Summary.LineCoverage.Covered);
365 emitDictElement("percent", Summary.LineCoverage.getPercentCovered());
Vedant Kumar7101d732016-07-26 22:50:58 +0000366 // End Line Coverage Summary.
367 emitDictEnd();
368
369 emitDictKey("functions");
370
371 // Start Function Coverage Summary.
372 emitDictStart();
373 emitDictElement("count", Summary.FunctionCoverage.NumFunctions);
374 emitDictElement("covered", Summary.FunctionCoverage.Executed);
375 emitDictElement("percent", Summary.FunctionCoverage.getPercentCovered());
376 // End Function Coverage Summary.
377 emitDictEnd();
378
Vedant Kumar3c46abb2016-09-19 00:38:29 +0000379 emitDictKey("instantiations");
380
381 // Start Instantiation Coverage Summary.
382 emitDictStart();
383 emitDictElement("count", Summary.InstantiationCoverage.NumFunctions);
384 emitDictElement("covered", Summary.InstantiationCoverage.Executed);
385 emitDictElement("percent",
386 Summary.InstantiationCoverage.getPercentCovered());
387 // End Function Coverage Summary.
388 emitDictEnd();
389
Vedant Kumar7101d732016-07-26 22:50:58 +0000390 emitDictKey("regions");
391
392 // Start Region Coverage Summary.
393 emitDictStart();
394 emitDictElement("count", Summary.RegionCoverage.NumRegions);
395 emitDictElement("covered", Summary.RegionCoverage.Covered);
396 emitDictElement("notcovered", Summary.RegionCoverage.NotCovered);
397 emitDictElement("percent", Summary.RegionCoverage.getPercentCovered());
398 // End Region Coverage Summary.
399 emitDictEnd();
400
401 // End Summary for the file.
402 emitDictEnd();
403 }
404
405public:
Vedant Kumar5c61c702016-10-25 00:08:33 +0000406 CoverageExporterJson(const CoverageMapping &CoverageMapping, raw_ostream &OS)
407 : OS(OS), Coverage(CoverageMapping) {
Vedant Kumar7101d732016-07-26 22:50:58 +0000408 State.push(JsonState::None);
409 }
410
411 /// \brief Print the CoverageMapping.
412 void print() { renderRoot(); }
413};
414
415/// \brief Export the given CoverageMapping to a JSON Format.
Vedant Kumar5c61c702016-10-25 00:08:33 +0000416void exportCoverageDataToJson(const CoverageMapping &CoverageMapping,
Vedant Kumar7101d732016-07-26 22:50:58 +0000417 raw_ostream &OS) {
Vedant Kumar5c61c702016-10-25 00:08:33 +0000418 auto Exporter = CoverageExporterJson(CoverageMapping, OS);
Vedant Kumar7101d732016-07-26 22:50:58 +0000419
420 Exporter.print();
421}