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