//===- CoverageExporterLcov.cpp - Code coverage export --------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements export of code coverage data to lcov trace file format. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // // The trace file code coverage export follows the following format (see also // https://linux.die.net/man/1/geninfo). Each quoted string appears on its own // line; the indentation shown here is only for documentation purposes. // // - for each source file: // - "SF:" // - for each function: // - "FN:," // - for each function: // - "FNDA:," // - "FNF:" // - "FNH:" // - for each instrumented line: // - "DA:,[,] // - "LH:" // - "LF:" // - "end_of_record" // // If the user is exporting summary information only, then the FN, FNDA, and DA // lines will not be present. // //===----------------------------------------------------------------------===// #include "CoverageExporterLcov.h" #include "CoverageReport.h" using namespace llvm; namespace { void renderFunctionSummary(raw_ostream &OS, const FileCoverageSummary &Summary) { OS << "FNF:" << Summary.FunctionCoverage.getNumFunctions() << '\n' << "FNH:" << Summary.FunctionCoverage.getExecuted() << '\n'; } void renderFunctions( raw_ostream &OS, const iterator_range &Functions) { for (const auto &F : Functions) { auto StartLine = F.CountedRegions.front().LineStart; OS << "FN:" << StartLine << ',' << F.Name << '\n'; } for (const auto &F : Functions) OS << "FNDA:" << F.ExecutionCount << ',' << F.Name << '\n'; } void renderLineExecutionCounts(raw_ostream &OS, const coverage::CoverageData &FileCoverage) { coverage::LineCoverageIterator LCI{FileCoverage, 1}; coverage::LineCoverageIterator LCIEnd = LCI.getEnd(); for (; LCI != LCIEnd; ++LCI) { const coverage::LineCoverageStats &LCS = *LCI; if (LCS.isMapped()) { OS << "DA:" << LCS.getLine() << ',' << LCS.getExecutionCount() << '\n'; } } } void renderLineSummary(raw_ostream &OS, const FileCoverageSummary &Summary) { OS << "LF:" << Summary.LineCoverage.getNumLines() << '\n' << "LH:" << Summary.LineCoverage.getCovered() << '\n'; } void renderFile(raw_ostream &OS, const coverage::CoverageMapping &Coverage, const std::string &Filename, const FileCoverageSummary &FileReport, bool ExportSummaryOnly, bool SkipFunctions) { OS << "SF:" << Filename << '\n'; if (!ExportSummaryOnly && !SkipFunctions) { renderFunctions(OS, Coverage.getCoveredFunctions(Filename)); } renderFunctionSummary(OS, FileReport); if (!ExportSummaryOnly) { // Calculate and render detailed coverage information for given file. auto FileCoverage = Coverage.getCoverageForFile(Filename); renderLineExecutionCounts(OS, FileCoverage); } renderLineSummary(OS, FileReport); OS << "end_of_record\n"; } void renderFiles(raw_ostream &OS, const coverage::CoverageMapping &Coverage, ArrayRef SourceFiles, ArrayRef FileReports, bool ExportSummaryOnly, bool SkipFunctions) { for (unsigned I = 0, E = SourceFiles.size(); I < E; ++I) renderFile(OS, Coverage, SourceFiles[I], FileReports[I], ExportSummaryOnly, SkipFunctions); } } // end anonymous namespace void CoverageExporterLcov::renderRoot(const CoverageFilters &IgnoreFilters) { std::vector SourceFiles; for (StringRef SF : Coverage.getUniqueSourceFiles()) { if (!IgnoreFilters.matchesFilename(SF)) SourceFiles.emplace_back(SF); } renderRoot(SourceFiles); } void CoverageExporterLcov::renderRoot(ArrayRef SourceFiles) { FileCoverageSummary Totals = FileCoverageSummary("Totals"); auto FileReports = CoverageReport::prepareFileReports(Coverage, Totals, SourceFiles, Options); renderFiles(OS, Coverage, SourceFiles, FileReports, Options.ExportSummaryOnly, Options.SkipFunctions); }