Coverage Report

Created: 2018-08-19 14:04

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/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 "CoverageExporterJson.h"
45
#include "CoverageReport.h"
46
47
/// The semantic version combined as a string.
48
13
#define LLVM_COVERAGE_EXPORT_JSON_STR "2.0.0"
49
50
/// Unique type identifier for JSON coverage export.
51
13
#define LLVM_COVERAGE_EXPORT_JSON_TYPE_STR "llvm.coverage.json.export"
52
53
using namespace llvm;
54
55
CoverageExporterJson::CoverageExporterJson(
56
    const coverage::CoverageMapping &CoverageMapping,
57
    const CoverageViewOptions &Options, raw_ostream &OS)
58
13
    : CoverageExporter(CoverageMapping, Options, OS) {
59
13
  State.push(JsonState::None);
60
13
}
61
62
3.61k
void CoverageExporterJson::emitSerialized(const int64_t Value) { OS << Value; }
63
64
1.16k
void CoverageExporterJson::emitSerialized(const std::string &Value) {
65
1.16k
  OS << "\"";
66
10.4k
  for (char C : Value) {
67
10.4k
    if (C != '\\')
68
10.4k
      OS << C;
69
0
    else
70
0
      OS << "\\\\";
71
10.4k
  }
72
1.16k
  OS << "\"";
73
1.16k
}
74
75
5.06k
void CoverageExporterJson::emitComma() {
76
5.06k
  if (State.top() == JsonState::NonEmptyElement) {
77
3.76k
    OS << ",";
78
3.76k
  } else 
if (1.30k
State.top() == JsonState::EmptyElement1.30k
) {
79
1.28k
    State.pop();
80
1.28k
    assert((State.size() >= 1) && "Closed too many JSON elements");
81
1.28k
    State.push(JsonState::NonEmptyElement);
82
1.28k
  }
83
5.06k
}
84
85
293
void CoverageExporterJson::emitDictStart() {
86
293
  emitComma();
87
293
  State.push(JsonState::EmptyElement);
88
293
  OS << "{";
89
293
}
90
91
371
void CoverageExporterJson::emitDictKey(const std::string &Key) {
92
371
  emitComma();
93
371
  emitSerialized(Key);
94
371
  OS << ":";
95
371
  State.pop();
96
371
  assert((State.size() >= 1) && "Closed too many JSON elements");
97
371
98
371
  // We do not want to emit a comma after this key.
99
371
  State.push(JsonState::EmptyElement);
100
371
}
101
102
293
void CoverageExporterJson::emitDictEnd() {
103
293
  State.pop();
104
293
  assert((State.size() >= 1) && "Closed too many JSON elements");
105
293
  OS << "}";
106
293
}
107
108
648
void CoverageExporterJson::emitArrayStart() {
109
648
  emitComma();
110
648
  State.push(JsonState::EmptyElement);
111
648
  OS << "[";
112
648
}
113
114
648
void CoverageExporterJson::emitArrayEnd() {
115
648
  State.pop();
116
648
  assert((State.size() >= 1) && "Closed too many JSON elements");
117
648
  OS << "]";
118
648
}
119
120
void CoverageExporterJson::renderRoot(
121
12
    const CoverageFilters &IgnoreFilenameFilters) {
122
12
  std::vector<std::string> SourceFiles;
123
27
  for (StringRef SF : Coverage.getUniqueSourceFiles()) {
124
27
    if (!IgnoreFilenameFilters.matchesFilename(SF))
125
24
      SourceFiles.emplace_back(SF);
126
27
  }
127
12
  renderRoot(SourceFiles);
128
12
}
129
130
void CoverageExporterJson::renderRoot(
131
13
    const std::vector<std::string> &SourceFiles) {
132
13
  // Start Root of JSON object.
133
13
  emitDictStart();
134
13
135
13
  emitDictElement("version", LLVM_COVERAGE_EXPORT_JSON_STR);
136
13
  emitDictElement("type", LLVM_COVERAGE_EXPORT_JSON_TYPE_STR);
137
13
  emitDictKey("data");
138
13
139
13
  // Start List of Exports.
140
13
  emitArrayStart();
141
13
142
13
  // Start Export.
143
13
  emitDictStart();
144
13
145
13
  emitDictKey("files");
146
13
147
13
  FileCoverageSummary Totals = FileCoverageSummary("Totals");
148
13
  auto FileReports = CoverageReport::prepareFileReports(Coverage, Totals,
149
13
                                                        SourceFiles, Options);
150
13
  renderFiles(SourceFiles, FileReports);
151
13
152
13
  // Skip functions-level information for summary-only export mode.
153
13
  if (!Options.ExportSummaryOnly) {
154
12
    emitDictKey("functions");
155
12
    renderFunctions(Coverage.getCoveredFunctions());
156
12
  }
157
13
158
13
  emitDictKey("totals");
159
13
  renderSummary(Totals);
160
13
161
13
  // End Export.
162
13
  emitDictEnd();
163
13
164
13
  // End List of Exports.
165
13
  emitArrayEnd();
166
13
167
13
  // End Root of JSON Object.
168
13
  emitDictEnd();
169
13
170
13
  assert((State.top() == JsonState::None) &&
171
13
         "All Elements In JSON were Closed");
172
13
}
173
174
void CoverageExporterJson::renderFunctions(
175
12
    const iterator_range<coverage::FunctionRecordIterator> &Functions) {
176
12
  // Start List of Functions.
177
12
  emitArrayStart();
178
12
179
39
  for (const auto &Function : Functions) {
180
39
    // Start Function.
181
39
    emitDictStart();
182
39
183
39
    emitDictElement("name", Function.Name);
184
39
    emitDictElement("count", Function.ExecutionCount);
185
39
    emitDictKey("regions");
186
39
187
39
    renderRegions(Function.CountedRegions);
188
39
189
39
    emitDictKey("filenames");
190
39
191
39
    // Start Filenames for Function.
192
39
    emitArrayStart();
193
39
194
39
    for (const auto &FileName : Function.Filenames)
195
42
      emitArrayElement(FileName);
196
39
197
39
    // End Filenames for Function.
198
39
    emitArrayEnd();
199
39
200
39
    // End Function.
201
39
    emitDictEnd();
202
39
  }
203
12
204
12
  // End List of Functions.
205
12
  emitArrayEnd();
206
12
}
207
208
void CoverageExporterJson::renderFiles(
209
    ArrayRef<std::string> SourceFiles,
210
13
    ArrayRef<FileCoverageSummary> FileReports) {
211
13
  // Start List of Files.
212
13
  emitArrayStart();
213
13
214
40
  for (unsigned I = 0, E = SourceFiles.size(); I < E; 
++I27
) {
215
27
    renderFile(SourceFiles[I], FileReports[I]);
216
27
  }
217
13
218
13
  // End List of Files.
219
13
  emitArrayEnd();
220
13
}
221
222
void CoverageExporterJson::renderFile(const std::string &Filename,
223
27
                                      const FileCoverageSummary &FileReport) {
224
27
  // Start File.
225
27
  emitDictStart();
226
27
227
27
  emitDictElement("filename", Filename);
228
27
229
27
  if (!Options.ExportSummaryOnly) {
230
26
    // Calculate and render detailed coverage information for given file.
231
26
    auto FileCoverage = Coverage.getCoverageForFile(Filename);
232
26
    renderFileCoverage(FileCoverage, FileReport);
233
26
  }
234
27
235
27
  emitDictKey("summary");
236
27
  renderSummary(FileReport);
237
27
238
27
  // End File.
239
27
  emitDictEnd();
240
27
}
241
242
243
void CoverageExporterJson::renderFileCoverage(
244
    const coverage::CoverageData &FileCoverage,
245
26
    const FileCoverageSummary &FileReport) {
246
26
  emitDictKey("segments");
247
26
248
26
  // Start List of Segments.
249
26
  emitArrayStart();
250
26
251
26
  for (const auto &Segment : FileCoverage)
252
256
    renderSegment(Segment);
253
26
254
26
  // End List of Segments.
255
26
  emitArrayEnd();
256
26
257
26
  emitDictKey("expansions");
258
26
259
26
  // Start List of Expansions.
260
26
  emitArrayStart();
261
26
262
26
  for (const auto &Expansion : FileCoverage.getExpansions())
263
1
    renderExpansion(Expansion);
264
26
265
26
  // End List of Expansions.
266
26
  emitArrayEnd();
267
26
}
268
269
void CoverageExporterJson::renderSegment(
270
256
    const coverage::CoverageSegment &Segment) {
271
256
  // Start Segment.
272
256
  emitArrayStart();
273
256
274
256
  emitArrayElement(Segment.Line);
275
256
  emitArrayElement(Segment.Col);
276
256
  emitArrayElement(Segment.Count);
277
256
  emitArrayElement(Segment.HasCount);
278
256
  emitArrayElement(Segment.IsRegionEntry);
279
256
280
256
  // End Segment.
281
256
  emitArrayEnd();
282
256
}
283
284
void CoverageExporterJson::renderExpansion(
285
1
    const coverage::ExpansionRecord &Expansion) {
286
1
  // Start Expansion.
287
1
  emitDictStart();
288
1
289
1
  // Mark the beginning and end of this expansion in the source file.
290
1
  emitDictKey("source_region");
291
1
  renderRegion(Expansion.Region);
292
1
293
1
  // Enumerate the coverage information for the expansion.
294
1
  emitDictKey("target_regions");
295
1
  renderRegions(Expansion.Function.CountedRegions);
296
1
297
1
  emitDictKey("filenames");
298
1
  // Start List of Filenames to map the fileIDs.
299
1
  emitArrayStart();
300
1
  for (const auto &Filename : Expansion.Function.Filenames)
301
4
    emitArrayElement(Filename);
302
1
  // End List of Filenames.
303
1
  emitArrayEnd();
304
1
305
1
  // End Expansion.
306
1
  emitDictEnd();
307
1
}
308
309
void CoverageExporterJson::renderRegions(
310
40
    ArrayRef<coverage::CountedRegion> Regions) {
311
40
  // Start List of Regions.
312
40
  emitArrayStart();
313
40
314
40
  for (const auto &Region : Regions)
315
221
    renderRegion(Region);
316
40
317
40
  // End List of Regions.
318
40
  emitArrayEnd();
319
40
}
320
321
222
void CoverageExporterJson::renderRegion(const coverage::CountedRegion &Region) {
322
222
  // Start CountedRegion.
323
222
  emitArrayStart();
324
222
325
222
  emitArrayElement(Region.LineStart);
326
222
  emitArrayElement(Region.ColumnStart);
327
222
  emitArrayElement(Region.LineEnd);
328
222
  emitArrayElement(Region.ColumnEnd);
329
222
  emitArrayElement(Region.ExecutionCount);
330
222
  emitArrayElement(Region.FileID);
331
222
  emitArrayElement(Region.ExpandedFileID);
332
222
  emitArrayElement(Region.Kind);
333
222
334
222
  // End CountedRegion.
335
222
  emitArrayEnd();
336
222
}
337
338
40
void CoverageExporterJson::renderSummary(const FileCoverageSummary &Summary) {
339
40
  // Start Summary for the file.
340
40
  emitDictStart();
341
40
342
40
  emitDictKey("lines");
343
40
344
40
  // Start Line Coverage Summary.
345
40
  emitDictStart();
346
40
  emitDictElement("count", Summary.LineCoverage.getNumLines());
347
40
  emitDictElement("covered", Summary.LineCoverage.getCovered());
348
40
  emitDictElement("percent", Summary.LineCoverage.getPercentCovered());
349
40
  // End Line Coverage Summary.
350
40
  emitDictEnd();
351
40
352
40
  emitDictKey("functions");
353
40
354
40
  // Start Function Coverage Summary.
355
40
  emitDictStart();
356
40
  emitDictElement("count", Summary.FunctionCoverage.getNumFunctions());
357
40
  emitDictElement("covered", Summary.FunctionCoverage.getExecuted());
358
40
  emitDictElement("percent", Summary.FunctionCoverage.getPercentCovered());
359
40
  // End Function Coverage Summary.
360
40
  emitDictEnd();
361
40
362
40
  emitDictKey("instantiations");
363
40
364
40
  // Start Instantiation Coverage Summary.
365
40
  emitDictStart();
366
40
  emitDictElement("count", Summary.InstantiationCoverage.getNumFunctions());
367
40
  emitDictElement("covered", Summary.InstantiationCoverage.getExecuted());
368
40
  emitDictElement("percent", Summary.InstantiationCoverage.getPercentCovered());
369
40
  // End Function Coverage Summary.
370
40
  emitDictEnd();
371
40
372
40
  emitDictKey("regions");
373
40
374
40
  // Start Region Coverage Summary.
375
40
  emitDictStart();
376
40
  emitDictElement("count", Summary.RegionCoverage.getNumRegions());
377
40
  emitDictElement("covered", Summary.RegionCoverage.getCovered());
378
40
  emitDictElement("notcovered", Summary.RegionCoverage.getNumRegions() -
379
40
                                    Summary.RegionCoverage.getCovered());
380
40
  emitDictElement("percent", Summary.RegionCoverage.getPercentCovered());
381
40
  // End Region Coverage Summary.
382
40
  emitDictEnd();
383
40
384
40
  // End Summary for the file.
385
40
  emitDictEnd();
386
40
}