1 //===- CoverageExporterLcov.cpp - Code coverage export --------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements export of code coverage data to lcov trace file format. 10 // 11 //===----------------------------------------------------------------------===// 12 13 //===----------------------------------------------------------------------===// 14 // 15 // The trace file code coverage export follows the following format (see also 16 // https://linux.die.net/man/1/geninfo). Each quoted string appears on its own 17 // line; the indentation shown here is only for documentation purposes. 18 // 19 // - for each source file: 20 // - "SF:<absolute path to source file>" 21 // - for each function: 22 // - "FN:<line number of function start>,<function name>" 23 // - for each function: 24 // - "FNDA:<execution count>,<function name>" 25 // - "FNF:<number of functions found>" 26 // - "FNH:<number of functions hit>" 27 // - for each instrumented line: 28 // - "DA:<line number>,<execution count>[,<checksum>] 29 // - "LH:<number of lines with non-zero execution count>" 30 // - "LF:<nubmer of instrumented lines>" 31 // - "end_of_record" 32 // 33 // If the user is exporting summary information only, then the FN, FNDA, and DA 34 // lines will not be present. 35 // 36 //===----------------------------------------------------------------------===// 37 38 #include "CoverageExporterLcov.h" 39 #include "CoverageReport.h" 40 41 using namespace llvm; 42 43 namespace { 44 45 void renderFunctionSummary(raw_ostream &OS, 46 const FileCoverageSummary &Summary) { 47 OS << "FNF:" << Summary.FunctionCoverage.getNumFunctions() << '\n' 48 << "FNH:" << Summary.FunctionCoverage.getExecuted() << '\n'; 49 } 50 51 void renderFunctions( 52 raw_ostream &OS, 53 const iterator_range<coverage::FunctionRecordIterator> &Functions) { 54 for (const auto &F : Functions) { 55 auto StartLine = F.CountedRegions.front().LineStart; 56 OS << "FN:" << StartLine << ',' << F.Name << '\n'; 57 } 58 for (const auto &F : Functions) 59 OS << "FNDA:" << F.ExecutionCount << ',' << F.Name << '\n'; 60 } 61 62 void renderLineExecutionCounts(raw_ostream &OS, 63 const coverage::CoverageData &FileCoverage) { 64 coverage::LineCoverageIterator LCI{FileCoverage, 1}; 65 coverage::LineCoverageIterator LCIEnd = LCI.getEnd(); 66 for (; LCI != LCIEnd; ++LCI) { 67 const coverage::LineCoverageStats &LCS = *LCI; 68 if (LCS.isMapped()) { 69 OS << "DA:" << LCS.getLine() << ',' << LCS.getExecutionCount() << '\n'; 70 } 71 } 72 } 73 74 void renderLineSummary(raw_ostream &OS, const FileCoverageSummary &Summary) { 75 OS << "LF:" << Summary.LineCoverage.getNumLines() << '\n' 76 << "LH:" << Summary.LineCoverage.getCovered() << '\n'; 77 } 78 79 void renderFile(raw_ostream &OS, const coverage::CoverageMapping &Coverage, 80 const std::string &Filename, 81 const FileCoverageSummary &FileReport, bool ExportSummaryOnly, 82 bool SkipFunctions) { 83 OS << "SF:" << Filename << '\n'; 84 85 if (!ExportSummaryOnly && !SkipFunctions) { 86 renderFunctions(OS, Coverage.getCoveredFunctions(Filename)); 87 } 88 renderFunctionSummary(OS, FileReport); 89 90 if (!ExportSummaryOnly) { 91 // Calculate and render detailed coverage information for given file. 92 auto FileCoverage = Coverage.getCoverageForFile(Filename); 93 renderLineExecutionCounts(OS, FileCoverage); 94 } 95 renderLineSummary(OS, FileReport); 96 97 OS << "end_of_record\n"; 98 } 99 100 void renderFiles(raw_ostream &OS, const coverage::CoverageMapping &Coverage, 101 ArrayRef<std::string> SourceFiles, 102 ArrayRef<FileCoverageSummary> FileReports, 103 bool ExportSummaryOnly, bool SkipFunctions) { 104 for (unsigned I = 0, E = SourceFiles.size(); I < E; ++I) 105 renderFile(OS, Coverage, SourceFiles[I], FileReports[I], ExportSummaryOnly, 106 SkipFunctions); 107 } 108 109 } // end anonymous namespace 110 111 void CoverageExporterLcov::renderRoot(const CoverageFilters &IgnoreFilters) { 112 std::vector<std::string> SourceFiles; 113 for (StringRef SF : Coverage.getUniqueSourceFiles()) { 114 if (!IgnoreFilters.matchesFilename(SF)) 115 SourceFiles.emplace_back(SF); 116 } 117 renderRoot(SourceFiles); 118 } 119 120 void CoverageExporterLcov::renderRoot(ArrayRef<std::string> SourceFiles) { 121 FileCoverageSummary Totals = FileCoverageSummary("Totals"); 122 auto FileReports = CoverageReport::prepareFileReports(Coverage, Totals, 123 SourceFiles, Options); 124 renderFiles(OS, Coverage, SourceFiles, FileReports, Options.ExportSummaryOnly, 125 Options.SkipFunctions); 126 } 127