Coverage Report

Created: 2018-10-23 15:26

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/llvm-cov/CoverageExporterJson.cpp
Line
Count
Source
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
#include "llvm/Support/JSON.h"
47
48
/// The semantic version combined as a string.
49
7
#define LLVM_COVERAGE_EXPORT_JSON_STR "2.0.0"
50
51
/// Unique type identifier for JSON coverage export.
52
7
#define LLVM_COVERAGE_EXPORT_JSON_TYPE_STR "llvm.coverage.json.export"
53
54
using namespace llvm;
55
56
namespace {
57
58
162
json::Array renderSegment(const coverage::CoverageSegment &Segment) {
59
162
  return json::Array({Segment.Line, Segment.Col, int64_t(Segment.Count),
60
162
                      Segment.HasCount, Segment.IsRegionEntry});
61
162
}
62
63
168
json::Array renderRegion(const coverage::CountedRegion &Region) {
64
168
  return json::Array({Region.LineStart, Region.ColumnStart, Region.LineEnd,
65
168
                      Region.ColumnEnd, int64_t(Region.ExecutionCount),
66
168
                      Region.FileID, Region.ExpandedFileID,
67
168
                      int64_t(Region.Kind)});
68
168
}
69
70
31
json::Array renderRegions(ArrayRef<coverage::CountedRegion> Regions) {
71
31
  json::Array RegionArray;
72
31
  for (const auto &Region : Regions)
73
167
    RegionArray.push_back(renderRegion(Region));
74
31
  return RegionArray;
75
31
}
76
77
1
json::Object renderExpansion(const coverage::ExpansionRecord &Expansion) {
78
1
  return json::Object(
79
1
      {{"filenames", json::Array(Expansion.Function.Filenames)},
80
1
       // Mark the beginning and end of this expansion in the source file.
81
1
       {"source_region", renderRegion(Expansion.Region)},
82
1
       // Enumerate the coverage information for the expansion.
83
1
       {"target_regions", renderRegions(Expansion.Function.CountedRegions)}});
84
1
}
85
86
28
json::Object renderSummary(const FileCoverageSummary &Summary) {
87
28
  return json::Object(
88
28
      {{"lines",
89
28
        json::Object({{"count", int64_t(Summary.LineCoverage.getNumLines())},
90
28
                      {"covered", int64_t(Summary.LineCoverage.getCovered())},
91
28
                      {"percent", Summary.LineCoverage.getPercentCovered()}})},
92
28
       {"functions",
93
28
        json::Object(
94
28
            {{"count", int64_t(Summary.FunctionCoverage.getNumFunctions())},
95
28
             {"covered", int64_t(Summary.FunctionCoverage.getExecuted())},
96
28
             {"percent", Summary.FunctionCoverage.getPercentCovered()}})},
97
28
       {"instantiations",
98
28
        json::Object(
99
28
            {{"count",
100
28
              int64_t(Summary.InstantiationCoverage.getNumFunctions())},
101
28
             {"covered", int64_t(Summary.InstantiationCoverage.getExecuted())},
102
28
             {"percent", Summary.InstantiationCoverage.getPercentCovered()}})},
103
28
       {"regions",
104
28
        json::Object(
105
28
            {{"count", int64_t(Summary.RegionCoverage.getNumRegions())},
106
28
             {"covered", int64_t(Summary.RegionCoverage.getCovered())},
107
28
             {"notcovered", int64_t(Summary.RegionCoverage.getNumRegions() -
108
28
                                    Summary.RegionCoverage.getCovered())},
109
28
             {"percent", Summary.RegionCoverage.getPercentCovered()}})}});
110
28
}
111
112
json::Array renderFileExpansions(const coverage::CoverageData &FileCoverage,
113
20
                                 const FileCoverageSummary &FileReport) {
114
20
  json::Array ExpansionArray;
115
20
  for (const auto &Expansion : FileCoverage.getExpansions())
116
1
    ExpansionArray.push_back(renderExpansion(Expansion));
117
20
  return ExpansionArray;
118
20
}
119
120
json::Array renderFileSegments(const coverage::CoverageData &FileCoverage,
121
20
                               const FileCoverageSummary &FileReport) {
122
20
  json::Array SegmentArray;
123
20
  for (const auto &Segment : FileCoverage)
124
162
    SegmentArray.push_back(renderSegment(Segment));
125
20
  return SegmentArray;
126
20
}
127
128
json::Object renderFile(const coverage::CoverageMapping &Coverage,
129
                        const std::string &Filename,
130
                        const FileCoverageSummary &FileReport,
131
21
                        bool ExportSummaryOnly) {
132
21
  json::Object File({{"filename", Filename}});
133
21
  if (!ExportSummaryOnly) {
134
20
    // Calculate and render detailed coverage information for given file.
135
20
    auto FileCoverage = Coverage.getCoverageForFile(Filename);
136
20
    File["segments"] = renderFileSegments(FileCoverage, FileReport);
137
20
    File["expansions"] = renderFileExpansions(FileCoverage, FileReport);
138
20
  }
139
21
  File["summary"] = renderSummary(FileReport);
140
21
  return File;
141
21
}
142
143
json::Array renderFiles(const coverage::CoverageMapping &Coverage,
144
                        ArrayRef<std::string> SourceFiles,
145
                        ArrayRef<FileCoverageSummary> FileReports,
146
7
                        bool ExportSummaryOnly) {
147
7
  json::Array FileArray;
148
28
  for (unsigned I = 0, E = SourceFiles.size(); I < E; 
++I21
)
149
21
    FileArray.push_back(renderFile(Coverage, SourceFiles[I], FileReports[I],
150
21
                                   ExportSummaryOnly));
151
7
  return FileArray;
152
7
}
153
154
json::Array renderFunctions(
155
6
    const iterator_range<coverage::FunctionRecordIterator> &Functions) {
156
6
  json::Array FunctionArray;
157
6
  for (const auto &F : Functions)
158
30
    FunctionArray.push_back(
159
30
        json::Object({{"name", F.Name},
160
30
                      {"count", int64_t(F.ExecutionCount)},
161
30
                      {"regions", renderRegions(F.CountedRegions)},
162
30
                      {"filenames", json::Array(F.Filenames)}}));
163
6
  return FunctionArray;
164
6
}
165
166
} // end anonymous namespace
167
168
6
void CoverageExporterJson::renderRoot(const CoverageFilters &IgnoreFilters) {
169
6
  std::vector<std::string> SourceFiles;
170
21
  for (StringRef SF : Coverage.getUniqueSourceFiles()) {
171
21
    if (!IgnoreFilters.matchesFilename(SF))
172
18
      SourceFiles.emplace_back(SF);
173
21
  }
174
6
  renderRoot(SourceFiles);
175
6
}
176
177
7
void CoverageExporterJson::renderRoot(ArrayRef<std::string> SourceFiles) {
178
7
  FileCoverageSummary Totals = FileCoverageSummary("Totals");
179
7
  auto FileReports = CoverageReport::prepareFileReports(Coverage, Totals,
180
7
                                                        SourceFiles, Options);
181
7
  auto Export =
182
7
      json::Object({{"files", renderFiles(Coverage, SourceFiles, FileReports,
183
7
                                          Options.ExportSummaryOnly)},
184
7
                    {"totals", renderSummary(Totals)}});
185
7
  // Skip functions-level information for summary-only export mode.
186
7
  if (!Options.ExportSummaryOnly)
187
6
    Export["functions"] = renderFunctions(Coverage.getCoveredFunctions());
188
7
189
7
  auto ExportArray = json::Array({std::move(Export)});
190
7
191
7
  OS << json::Object({{"version", LLVM_COVERAGE_EXPORT_JSON_STR},
192
7
                      {"type", LLVM_COVERAGE_EXPORT_JSON_TYPE_STR},
193
7
                      {"data", std::move(ExportArray)}});
194
7
}