Coverage Report

Created: 2018-01-17 21:32

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