]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/llvm-cov/CoverageExporterJson.cpp
MFV r338519:
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / llvm-cov / CoverageExporterJson.cpp
1 //===- 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
39 // ------ InstantiationCoverage: dict => Object summarizing inst. coverage
40 // ------ RegionCoverage: dict => Object summarizing region coverage
41 //
42 //===----------------------------------------------------------------------===//
43
44 #include "CoverageReport.h"
45 #include "CoverageSummaryInfo.h"
46 #include "CoverageViewOptions.h"
47 #include "llvm/ProfileData/Coverage/CoverageMapping.h"
48 #include <stack>
49
50 /// \brief The semantic version combined as a string.
51 #define LLVM_COVERAGE_EXPORT_JSON_STR "2.0.0"
52
53 /// \brief Unique type identifier for JSON coverage export.
54 #define LLVM_COVERAGE_EXPORT_JSON_TYPE_STR "llvm.coverage.json.export"
55
56 using namespace llvm;
57 using namespace coverage;
58
59 class CoverageExporterJson {
60   const CoverageViewOptions &Options;
61
62   /// \brief Output stream to print JSON to.
63   raw_ostream &OS;
64
65   /// \brief The full CoverageMapping object to export.
66   const CoverageMapping &Coverage;
67
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
74   /// \brief Emit a serialized scalar.
75   void emitSerialized(const int64_t Value) { OS << Value; }
76
77   /// \brief Emit a serialized string.
78   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   }
88
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();
110     emitSerialized(Key);
111     OS << ":";
112     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();
169
170     emitDictKey("files");
171
172     FileCoverageSummary Totals = FileCoverageSummary("Totals");
173     std::vector<std::string> SourceFiles;
174     for (StringRef SF : Coverage.getUniqueSourceFiles())
175       SourceFiles.emplace_back(SF);
176     auto FileReports = CoverageReport::prepareFileReports(Coverage, Totals,
177                                                           SourceFiles, Options);
178     renderFiles(SourceFiles, FileReports);
179
180     // Skip functions-level information for summary-only export mode.
181     if (!Options.ExportSummaryOnly) {
182       emitDictKey("functions");
183       renderFunctions(Coverage.getCoveredFunctions());
184     }
185
186     emitDictKey("totals");
187     renderSummary(Totals);
188
189     // End Export.
190     emitDictEnd();
191
192     // End List of Exports.
193     emitArrayEnd();
194
195     // End Root of JSON Object.
196     emitDictEnd();
197
198     assert((State.top() == JsonState::None) &&
199            "All Elements In JSON were Closed");
200   }
201
202   /// \brief Render an array of all the given functions.
203   void
204   renderFunctions(const iterator_range<FunctionRecordIterator> &Functions) {
205     // Start List of Functions.
206     emitArrayStart();
207
208     for (const auto &Function : Functions) {
209       // Start Function.
210       emitDictStart();
211
212       emitDictElement("name", Function.Name);
213       emitDictElement("count", Function.ExecutionCount);
214       emitDictKey("regions");
215
216       renderRegions(Function.CountedRegions);
217
218       emitDictKey("filenames");
219
220       // Start Filenames for Function.
221       emitArrayStart();
222
223       for (const auto &FileName : Function.Filenames)
224         emitArrayElement(FileName);
225
226       // End Filenames for Function.
227       emitArrayEnd();
228
229       // End Function.
230       emitDictEnd();
231     }
232
233     // End List of Functions.
234     emitArrayEnd();
235   }
236
237   /// \brief Render an array of all the source files, also pass back a Summary.
238   void renderFiles(ArrayRef<std::string> SourceFiles,
239                    ArrayRef<FileCoverageSummary> FileReports) {
240     // Start List of Files.
241     emitArrayStart();
242
243     for (unsigned I = 0, E = SourceFiles.size(); I < E; ++I) {
244       // Render the file.
245       auto FileCoverage = Coverage.getCoverageForFile(SourceFiles[I]);
246       renderFile(FileCoverage, FileReports[I]);
247     }
248
249     // End List of Files.
250     emitArrayEnd();
251   }
252
253   /// \brief Render a single file.
254   void renderFile(const CoverageData &FileCoverage,
255                   const FileCoverageSummary &FileReport) {
256     // Start File.
257     emitDictStart();
258
259     emitDictElement("filename", FileCoverage.getFilename());
260
261     // Skip segments and expansions for summary-only export mode.
262     if (!Options.ExportSummaryOnly) {
263       emitDictKey("segments");
264
265       // Start List of Segments.
266       emitArrayStart();
267
268       for (const auto &Segment : FileCoverage)
269         renderSegment(Segment);
270
271       // End List of Segments.
272       emitArrayEnd();
273
274       emitDictKey("expansions");
275
276       // Start List of Expansions.
277       emitArrayStart();
278
279       for (const auto &Expansion : FileCoverage.getExpansions())
280         renderExpansion(Expansion);
281
282       // End List of Expansions.
283       emitArrayEnd();
284     }
285
286     emitDictKey("summary");
287     renderSummary(FileReport);
288
289     // End File.
290     emitDictEnd();
291   }
292
293   /// \brief Render a CoverageSegment.
294   void renderSegment(const CoverageSegment &Segment) {
295     // Start Segment.
296     emitArrayStart();
297
298     emitArrayElement(Segment.Line);
299     emitArrayElement(Segment.Col);
300     emitArrayElement(Segment.Count);
301     emitArrayElement(Segment.HasCount);
302     emitArrayElement(Segment.IsRegionEntry);
303
304     // End Segment.
305     emitArrayEnd();
306   }
307
308   /// \brief Render an ExpansionRecord.
309   void renderExpansion(const ExpansionRecord &Expansion) {
310     // Start Expansion.
311     emitDictStart();
312
313     // Mark the beginning and end of this expansion in the source file.
314     emitDictKey("source_region");
315     renderRegion(Expansion.Region);
316
317     // Enumerate the coverage information for the expansion.
318     emitDictKey("target_regions");
319     renderRegions(Expansion.Function.CountedRegions);
320
321     emitDictKey("filenames");
322     // Start List of Filenames to map the fileIDs.
323     emitArrayStart();
324     for (const auto &Filename : Expansion.Function.Filenames)
325       emitArrayElement(Filename);
326     // End List of Filenames.
327     emitArrayEnd();
328
329     // End Expansion.
330     emitDictEnd();
331   }
332
333   /// \brief Render a list of CountedRegions.
334   void renderRegions(ArrayRef<CountedRegion> Regions) {
335     // Start List of Regions.
336     emitArrayStart();
337
338     for (const auto &Region : Regions)
339       renderRegion(Region);
340
341     // End List of Regions.
342     emitArrayEnd();
343   }
344
345   /// \brief Render a single CountedRegion.
346   void renderRegion(const CountedRegion &Region) {
347     // Start CountedRegion.
348     emitArrayStart();
349
350     emitArrayElement(Region.LineStart);
351     emitArrayElement(Region.ColumnStart);
352     emitArrayElement(Region.LineEnd);
353     emitArrayElement(Region.ColumnEnd);
354     emitArrayElement(Region.ExecutionCount);
355     emitArrayElement(Region.FileID);
356     emitArrayElement(Region.ExpandedFileID);
357     emitArrayElement(Region.Kind);
358
359     // End CountedRegion.
360     emitArrayEnd();
361   }
362
363   /// \brief Render a FileCoverageSummary.
364   void renderSummary(const FileCoverageSummary &Summary) {
365     // Start Summary for the file.
366     emitDictStart();
367
368     emitDictKey("lines");
369
370     // Start Line Coverage Summary.
371     emitDictStart();
372     emitDictElement("count", Summary.LineCoverage.getNumLines());
373     emitDictElement("covered", Summary.LineCoverage.getCovered());
374     emitDictElement("percent", Summary.LineCoverage.getPercentCovered());
375     // End Line Coverage Summary.
376     emitDictEnd();
377
378     emitDictKey("functions");
379
380     // Start Function Coverage Summary.
381     emitDictStart();
382     emitDictElement("count", Summary.FunctionCoverage.getNumFunctions());
383     emitDictElement("covered", Summary.FunctionCoverage.getExecuted());
384     emitDictElement("percent", Summary.FunctionCoverage.getPercentCovered());
385     // End Function Coverage Summary.
386     emitDictEnd();
387
388     emitDictKey("instantiations");
389
390     // Start Instantiation Coverage Summary.
391     emitDictStart();
392     emitDictElement("count", Summary.InstantiationCoverage.getNumFunctions());
393     emitDictElement("covered", Summary.InstantiationCoverage.getExecuted());
394     emitDictElement("percent",
395                     Summary.InstantiationCoverage.getPercentCovered());
396     // End Function Coverage Summary.
397     emitDictEnd();
398
399     emitDictKey("regions");
400
401     // Start Region Coverage Summary.
402     emitDictStart();
403     emitDictElement("count", Summary.RegionCoverage.getNumRegions());
404     emitDictElement("covered", Summary.RegionCoverage.getCovered());
405     emitDictElement("notcovered",
406                     Summary.RegionCoverage.getNumRegions() -
407                         Summary.RegionCoverage.getCovered());
408     emitDictElement("percent", Summary.RegionCoverage.getPercentCovered());
409     // End Region Coverage Summary.
410     emitDictEnd();
411
412     // End Summary for the file.
413     emitDictEnd();
414   }
415
416 public:
417   CoverageExporterJson(const CoverageMapping &CoverageMapping,
418                        const CoverageViewOptions &Options, raw_ostream &OS)
419       : Options(Options), OS(OS), Coverage(CoverageMapping) {
420     State.push(JsonState::None);
421   }
422
423   /// \brief Print the CoverageMapping.
424   void print() { renderRoot(); }
425 };
426
427 /// \brief Export the given CoverageMapping to a JSON Format.
428 void exportCoverageDataToJson(const CoverageMapping &CoverageMapping,
429                               const CoverageViewOptions &Options,
430                               raw_ostream &OS) {
431   auto Exporter = CoverageExporterJson(CoverageMapping, Options, OS);
432
433   Exporter.print();
434 }