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