Coverage Report

Created: 2017-09-21 03:39

/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/llvm-cov/CoverageExporterJson.cpp
Line
Count
Source (jump to first uncovered line)
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
8
#define LLVM_COVERAGE_EXPORT_JSON_STR "2.0.0"
52
53
/// \brief Unique type identifier for JSON coverage export.
54
8
#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
1.41k
  void emitSerialized(const int64_t Value) { OS << Value; }
76
77
  /// \brief Emit a serialized string.
78
452
  void emitSerialized(const std::string &Value) {
79
452
    OS << "\"";
80
4.35k
    for (char C : Value) {
81
4.35k
      if (C != '\\')
82
4.35k
        OS << C;
83
4.35k
      else
84
0
        OS << "\\\\";
85
4.35k
    }
86
452
    OS << "\"";
87
452
  }
88
89
  /// \brief Emit a comma if there is a previous element to delimit.
90
1.98k
  void emitComma() {
91
1.98k
    if (
State.top() == JsonState::NonEmptyElement1.98k
) {
92
1.46k
      OS << ",";
93
1.98k
    } else 
if (518
State.top() == JsonState::EmptyElement518
) {
94
510
      State.pop();
95
510
      assert((State.size() >= 1) && "Closed too many JSON elements");
96
510
      State.push(JsonState::NonEmptyElement);
97
510
    }
98
1.98k
  }
99
100
  /// \brief Emit a starting dictionary/object character.
101
116
  void emitDictStart() {
102
116
    emitComma();
103
116
    State.push(JsonState::EmptyElement);
104
116
    OS << "{";
105
116
  }
106
107
  /// \brief Emit a dictionary/object key but no value.
108
145
  void emitDictKey(const std::string &Key) {
109
145
    emitComma();
110
145
    emitSerialized(Key);
111
145
    OS << ":";
112
145
    State.pop();
113
145
    assert((State.size() >= 1) && "Closed too many JSON elements");
114
145
115
145
    // We do not want to emit a comma after this key.
116
145
    State.push(JsonState::EmptyElement);
117
145
  }
118
119
  /// \brief Emit a dictionary/object key/value pair.
120
  template <typename V>
121
254
  void emitDictElement(const std::string &Key, const V &Value) {
122
254
    emitComma();
123
254
    emitSerialized(Key);
124
254
    OS << ":";
125
254
    emitSerialized(Value);
126
254
  }
void CoverageExporterJson::emitDictElement<char [26]>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [26])
Line
Count
Source
121
8
  void emitDictElement(const std::string &Key, const V &Value) {
122
8
    emitComma();
123
8
    emitSerialized(Key);
124
8
    OS << ":";
125
8
    emitSerialized(Value);
126
8
  }
void CoverageExporterJson::emitDictElement<unsigned long>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long const&)
Line
Count
Source
121
144
  void emitDictElement(const std::string &Key, const V &Value) {
122
144
    emitComma();
123
144
    emitSerialized(Key);
124
144
    OS << ":";
125
144
    emitSerialized(Value);
126
144
  }
void CoverageExporterJson::emitDictElement<unsigned long long>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long long const&)
Line
Count
Source
121
11
  void emitDictElement(const std::string &Key, const V &Value) {
122
11
    emitComma();
123
11
    emitSerialized(Key);
124
11
    OS << ":";
125
11
    emitSerialized(Value);
126
11
  }
void CoverageExporterJson::emitDictElement<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
121
11
  void emitDictElement(const std::string &Key, const V &Value) {
122
11
    emitComma();
123
11
    emitSerialized(Key);
124
11
    OS << ":";
125
11
    emitSerialized(Value);
126
11
  }
void CoverageExporterJson::emitDictElement<llvm::StringRef>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, llvm::StringRef const&)
Line
Count
Source
121
8
  void emitDictElement(const std::string &Key, const V &Value) {
122
8
    emitComma();
123
8
    emitSerialized(Key);
124
8
    OS << ":";
125
8
    emitSerialized(Value);
126
8
  }
void CoverageExporterJson::emitDictElement<char [6]>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [6])
Line
Count
Source
121
8
  void emitDictElement(const std::string &Key, const V &Value) {
122
8
    emitComma();
123
8
    emitSerialized(Key);
124
8
    OS << ":";
125
8
    emitSerialized(Value);
126
8
  }
void CoverageExporterJson::emitDictElement<double>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, double const&)
Line
Count
Source
121
64
  void emitDictElement(const std::string &Key, const V &Value) {
122
64
    emitComma();
123
64
    emitSerialized(Key);
124
64
    OS << ":";
125
64
    emitSerialized(Value);
126
64
  }
127
128
  /// \brief Emit a closing dictionary/object character.
129
116
  void emitDictEnd() {
130
116
    State.pop();
131
116
    assert((State.size() >= 1) && "Closed too many JSON elements");
132
116
    OS << "}";
133
116
  }
134
135
  /// \brief Emit a starting array character.
136
256
  void emitArrayStart() {
137
256
    emitComma();
138
256
    State.push(JsonState::EmptyElement);
139
256
    OS << "[";
140
256
  }
141
142
  /// \brief Emit an array element.
143
1.20k
  template <typename V> void emitArrayElement(const V &Value) {
144
1.20k
    emitComma();
145
1.20k
    emitSerialized(Value);
146
1.20k
  }
void CoverageExporterJson::emitArrayElement<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
143
18
  template <typename V> void emitArrayElement(const V &Value) {
144
18
    emitComma();
145
18
    emitSerialized(Value);
146
18
  }
void CoverageExporterJson::emitArrayElement<llvm::coverage::CounterMappingRegion::RegionKind>(llvm::coverage::CounterMappingRegion::RegionKind const&)
Line
Count
Source
143
77
  template <typename V> void emitArrayElement(const V &Value) {
144
77
    emitComma();
145
77
    emitSerialized(Value);
146
77
  }
void CoverageExporterJson::emitArrayElement<bool>(bool const&)
Line
Count
Source
143
230
  template <typename V> void emitArrayElement(const V &Value) {
144
230
    emitComma();
145
230
    emitSerialized(Value);
146
230
  }
void CoverageExporterJson::emitArrayElement<unsigned long long>(unsigned long long const&)
Line
Count
Source
143
192
  template <typename V> void emitArrayElement(const V &Value) {
144
192
    emitComma();
145
192
    emitSerialized(Value);
146
192
  }
void CoverageExporterJson::emitArrayElement<unsigned int>(unsigned int const&)
Line
Count
Source
143
692
  template <typename V> void emitArrayElement(const V &Value) {
144
692
    emitComma();
145
692
    emitSerialized(Value);
146
692
  }
147
148
  /// \brief emit a closing array character.
149
256
  void emitArrayEnd() {
150
256
    State.pop();
151
256
    assert((State.size() >= 1) && "Closed too many JSON elements");
152
256
    OS << "]";
153
256
  }
154
155
  /// \brief Render the CoverageMapping object.
156
8
  void renderRoot() {
157
8
    // Start Root of JSON object.
158
8
    emitDictStart();
159
8
160
8
    emitDictElement("version", LLVM_COVERAGE_EXPORT_JSON_STR);
161
8
    emitDictElement("type", LLVM_COVERAGE_EXPORT_JSON_TYPE_STR);
162
8
    emitDictKey("data");
163
8
164
8
    // Start List of Exports.
165
8
    emitArrayStart();
166
8
167
8
    // Start Export.
168
8
    emitDictStart();
169
8
170
8
    emitDictKey("files");
171
8
172
8
    FileCoverageSummary Totals = FileCoverageSummary("Totals");
173
8
    std::vector<std::string> SourceFiles;
174
8
    for (StringRef SF : Coverage.getUniqueSourceFiles())
175
8
      SourceFiles.emplace_back(SF);
176
8
    auto FileReports = CoverageReport::prepareFileReports(Coverage, Totals,
177
8
                                                          SourceFiles, Options);
178
8
    renderFiles(SourceFiles, FileReports);
179
8
180
8
    emitDictKey("functions");
181
8
    renderFunctions(Coverage.getCoveredFunctions());
182
8
183
8
    emitDictKey("totals");
184
8
    renderSummary(Totals);
185
8
186
8
    // End Export.
187
8
    emitDictEnd();
188
8
189
8
    // End List of Exports.
190
8
    emitArrayEnd();
191
8
192
8
    // End Root of JSON Object.
193
8
    emitDictEnd();
194
8
195
8
    assert((State.top() == JsonState::None) &&
196
8
           "All Elements In JSON were Closed");
197
8
  }
198
199
  /// \brief Render an array of all the given functions.
200
  void
201
8
  renderFunctions(const iterator_range<FunctionRecordIterator> &Functions) {
202
8
    // Start List of Functions.
203
8
    emitArrayStart();
204
8
205
11
    for (const auto &Function : Functions) {
206
11
      // Start Function.
207
11
      emitDictStart();
208
11
209
11
      emitDictElement("name", Function.Name);
210
11
      emitDictElement("count", Function.ExecutionCount);
211
11
      emitDictKey("regions");
212
11
213
11
      renderRegions(Function.CountedRegions);
214
11
215
11
      emitDictKey("filenames");
216
11
217
11
      // Start Filenames for Function.
218
11
      emitArrayStart();
219
11
220
11
      for (const auto &FileName : Function.Filenames)
221
14
        emitArrayElement(FileName);
222
11
223
11
      // End Filenames for Function.
224
11
      emitArrayEnd();
225
11
226
11
      // End Function.
227
11
      emitDictEnd();
228
11
    }
229
8
230
8
    // End List of Functions.
231
8
    emitArrayEnd();
232
8
  }
233
234
  /// \brief Render an array of all the source files, also pass back a Summary.
235
  void renderFiles(ArrayRef<std::string> SourceFiles,
236
8
                   ArrayRef<FileCoverageSummary> FileReports) {
237
8
    // Start List of Files.
238
8
    emitArrayStart();
239
8
240
16
    for (unsigned I = 0, E = SourceFiles.size(); 
I < E16
;
++I8
) {
241
8
      // Render the file.
242
8
      auto FileCoverage = Coverage.getCoverageForFile(SourceFiles[I]);
243
8
      renderFile(FileCoverage, FileReports[I]);
244
8
    }
245
8
246
8
    // End List of Files.
247
8
    emitArrayEnd();
248
8
  }
249
250
  /// \brief Render a single file.
251
  void renderFile(const CoverageData &FileCoverage,
252
8
                  const FileCoverageSummary &FileReport) {
253
8
    // Start File.
254
8
    emitDictStart();
255
8
256
8
    emitDictElement("filename", FileCoverage.getFilename());
257
8
    emitDictKey("segments");
258
8
259
8
    // Start List of Segments.
260
8
    emitArrayStart();
261
8
262
8
    for (const auto &Segment : FileCoverage)
263
115
      renderSegment(Segment);
264
8
265
8
    // End List of Segments.
266
8
    emitArrayEnd();
267
8
268
8
    emitDictKey("expansions");
269
8
270
8
    // Start List of Expansions.
271
8
    emitArrayStart();
272
8
273
8
    for (const auto &Expansion : FileCoverage.getExpansions())
274
1
      renderExpansion(Expansion);
275
8
276
8
    // End List of Expansions.
277
8
    emitArrayEnd();
278
8
279
8
    emitDictKey("summary");
280
8
    renderSummary(FileReport);
281
8
282
8
    // End File.
283
8
    emitDictEnd();
284
8
  }
285
286
  /// \brief Render a CoverageSegment.
287
115
  void renderSegment(const CoverageSegment &Segment) {
288
115
    // Start Segment.
289
115
    emitArrayStart();
290
115
291
115
    emitArrayElement(Segment.Line);
292
115
    emitArrayElement(Segment.Col);
293
115
    emitArrayElement(Segment.Count);
294
115
    emitArrayElement(Segment.HasCount);
295
115
    emitArrayElement(Segment.IsRegionEntry);
296
115
297
115
    // End Segment.
298
115
    emitArrayEnd();
299
115
  }
300
301
  /// \brief Render an ExpansionRecord.
302
1
  void renderExpansion(const ExpansionRecord &Expansion) {
303
1
    // Start Expansion.
304
1
    emitDictStart();
305
1
306
1
    // Mark the beginning and end of this expansion in the source file.
307
1
    emitDictKey("source_region");
308
1
    renderRegion(Expansion.Region);
309
1
310
1
    // Enumerate the coverage information for the expansion.
311
1
    emitDictKey("target_regions");
312
1
    renderRegions(Expansion.Function.CountedRegions);
313
1
314
1
    emitDictKey("filenames");
315
1
    // Start List of Filenames to map the fileIDs.
316
1
    emitArrayStart();
317
1
    for (const auto &Filename : Expansion.Function.Filenames)
318
4
      emitArrayElement(Filename);
319
1
    // End List of Filenames.
320
1
    emitArrayEnd();
321
1
322
1
    // End Expansion.
323
1
    emitDictEnd();
324
1
  }
325
326
  /// \brief Render a list of CountedRegions.
327
12
  void renderRegions(ArrayRef<CountedRegion> Regions) {
328
12
    // Start List of Regions.
329
12
    emitArrayStart();
330
12
331
12
    for (const auto &Region : Regions)
332
76
      renderRegion(Region);
333
12
334
12
    // End List of Regions.
335
12
    emitArrayEnd();
336
12
  }
337
338
  /// \brief Render a single CountedRegion.
339
77
  void renderRegion(const CountedRegion &Region) {
340
77
    // Start CountedRegion.
341
77
    emitArrayStart();
342
77
343
77
    emitArrayElement(Region.LineStart);
344
77
    emitArrayElement(Region.ColumnStart);
345
77
    emitArrayElement(Region.LineEnd);
346
77
    emitArrayElement(Region.ColumnEnd);
347
77
    emitArrayElement(Region.ExecutionCount);
348
77
    emitArrayElement(Region.FileID);
349
77
    emitArrayElement(Region.ExpandedFileID);
350
77
    emitArrayElement(Region.Kind);
351
77
352
77
    // End CountedRegion.
353
77
    emitArrayEnd();
354
77
  }
355
356
  /// \brief Render a FileCoverageSummary.
357
16
  void renderSummary(const FileCoverageSummary &Summary) {
358
16
    // Start Summary for the file.
359
16
    emitDictStart();
360
16
361
16
    emitDictKey("lines");
362
16
363
16
    // Start Line Coverage Summary.
364
16
    emitDictStart();
365
16
    emitDictElement("count", Summary.LineCoverage.getNumLines());
366
16
    emitDictElement("covered", Summary.LineCoverage.getCovered());
367
16
    emitDictElement("percent", Summary.LineCoverage.getPercentCovered());
368
16
    // End Line Coverage Summary.
369
16
    emitDictEnd();
370
16
371
16
    emitDictKey("functions");
372
16
373
16
    // Start Function Coverage Summary.
374
16
    emitDictStart();
375
16
    emitDictElement("count", Summary.FunctionCoverage.getNumFunctions());
376
16
    emitDictElement("covered", Summary.FunctionCoverage.getExecuted());
377
16
    emitDictElement("percent", Summary.FunctionCoverage.getPercentCovered());
378
16
    // End Function Coverage Summary.
379
16
    emitDictEnd();
380
16
381
16
    emitDictKey("instantiations");
382
16
383
16
    // Start Instantiation Coverage Summary.
384
16
    emitDictStart();
385
16
    emitDictElement("count", Summary.InstantiationCoverage.getNumFunctions());
386
16
    emitDictElement("covered", Summary.InstantiationCoverage.getExecuted());
387
16
    emitDictElement("percent",
388
16
                    Summary.InstantiationCoverage.getPercentCovered());
389
16
    // End Function Coverage Summary.
390
16
    emitDictEnd();
391
16
392
16
    emitDictKey("regions");
393
16
394
16
    // Start Region Coverage Summary.
395
16
    emitDictStart();
396
16
    emitDictElement("count", Summary.RegionCoverage.getNumRegions());
397
16
    emitDictElement("covered", Summary.RegionCoverage.getCovered());
398
16
    emitDictElement("notcovered",
399
16
                    Summary.RegionCoverage.getNumRegions() -
400
16
                        Summary.RegionCoverage.getCovered());
401
16
    emitDictElement("percent", Summary.RegionCoverage.getPercentCovered());
402
16
    // End Region Coverage Summary.
403
16
    emitDictEnd();
404
16
405
16
    // End Summary for the file.
406
16
    emitDictEnd();
407
16
  }
408
409
public:
410
  CoverageExporterJson(const CoverageMapping &CoverageMapping,
411
                       const CoverageViewOptions &Options, raw_ostream &OS)
412
8
      : Options(Options), OS(OS), Coverage(CoverageMapping) {
413
8
    State.push(JsonState::None);
414
8
  }
415
416
  /// \brief Print the CoverageMapping.
417
8
  void print() { renderRoot(); }
418
};
419
420
/// \brief Export the given CoverageMapping to a JSON Format.
421
void exportCoverageDataToJson(const CoverageMapping &CoverageMapping,
422
                              const CoverageViewOptions &Options,
423
8
                              raw_ostream &OS) {
424
8
  auto Exporter = CoverageExporterJson(CoverageMapping, Options, OS);
425
8
426
8
  Exporter.print();
427
8
}