std::unique_ptr<SourceCoverageView> CodeCoverageTool::createSourceFileView(StringRef SourceFile, CoverageMapping &Coverage) { auto SourceBuffer = getSourceFile(SourceFile); if (!SourceBuffer) return nullptr; auto FileCoverage = Coverage.getCoverageForFile(SourceFile); if (FileCoverage.empty()) return nullptr; auto Expansions = FileCoverage.getExpansions(); auto View = llvm::make_unique<SourceCoverageView>( SourceBuffer.get(), ViewOpts, std::move(FileCoverage)); attachExpansionSubViews(*View, Expansions, Coverage); for (auto Function : Coverage.getInstantiations(SourceFile)) { auto SubViewCoverage = Coverage.getCoverageForFunction(*Function); auto SubViewExpansions = SubViewCoverage.getExpansions(); auto SubView = llvm::make_unique<SourceCoverageView>( SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage)); attachExpansionSubViews(*SubView, SubViewExpansions, Coverage); if (SubView) { unsigned FileID = Function->CountedRegions.front().FileID; unsigned Line = 0; for (const auto &CR : Function->CountedRegions) if (CR.FileID == FileID) Line = std::max(CR.LineEnd, Line); View->addInstantiation(Function->Name, Line, std::move(SubView)); } } return View; }
void CodeCoverageTool::removeUnmappedInputs(const CoverageMapping &Coverage) { std::vector<StringRef> CoveredFiles = Coverage.getUniqueSourceFiles(); auto UncoveredFilesIt = SourceFiles.end(); if (!CompareFilenamesOnly) { // The user may have specified source files which aren't in the coverage // mapping. Filter these files away. UncoveredFilesIt = std::remove_if( SourceFiles.begin(), SourceFiles.end(), [&](const std::string &SF) { return !std::binary_search(CoveredFiles.begin(), CoveredFiles.end(), SF); }); } else { for (auto &SF : SourceFiles) { StringRef SFBase = sys::path::filename(SF); for (const auto &CF : CoveredFiles) { if (SFBase == sys::path::filename(CF)) { RemappedFilenames[CF] = SF; SF = CF; break; } } } UncoveredFilesIt = std::remove_if( SourceFiles.begin(), SourceFiles.end(), [&](const std::string &SF) { return !RemappedFilenames.count(SF); }); } SourceFiles.erase(UncoveredFilesIt, SourceFiles.end()); }
/// \brief Render the CoverageMapping object. void renderRoot() { // Start Root of JSON object. emitDictStart(); emitDictElement("version", LLVM_COVERAGE_EXPORT_JSON_STR); emitDictElement("type", LLVM_COVERAGE_EXPORT_JSON_TYPE_STR); emitDictKey("data"); // Start List of Exports. emitArrayStart(); // Start Export. emitDictStart(); emitDictElement("object", getObjectFilename()); emitDictKey("files"); FileCoverageSummary Totals = FileCoverageSummary("Totals"); std::vector<std::string> SourceFiles; for (StringRef SF : Coverage.getUniqueSourceFiles()) SourceFiles.emplace_back(SF); auto FileReports = CoverageReport::prepareFileReports(Coverage, Totals, SourceFiles); renderFiles(SourceFiles, FileReports); emitDictKey("functions"); renderFunctions(Coverage.getCoveredFunctions()); emitDictKey("totals"); renderSummary(Totals); // End Export. emitDictEnd(); // End List of Exports. emitArrayEnd(); // End Root of JSON Object. emitDictEnd(); assert((State.top() == JsonState::None) && "All Elements In JSON were Closed"); }
/// \brief Render an array of all the source files, also pass back a Summary. void renderFiles(ArrayRef<std::string> SourceFiles, ArrayRef<FileCoverageSummary> FileReports) { // Start List of Files. emitArrayStart(); for (unsigned I = 0, E = SourceFiles.size(); I < E; ++I) { // Render the file. auto FileCoverage = Coverage.getCoverageForFile(SourceFiles[I]); renderFile(FileCoverage, FileReports[I]); } // End List of Files. emitArrayEnd(); }
std::unique_ptr<SourceCoverageView> CodeCoverageTool::createFunctionView(const FunctionRecord &Function, CoverageMapping &Coverage) { auto FunctionCoverage = Coverage.getCoverageForFunction(Function); if (FunctionCoverage.empty()) return nullptr; auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename()); if (!SourceBuffer) return nullptr; auto Expansions = FunctionCoverage.getExpansions(); auto View = llvm::make_unique<SourceCoverageView>( SourceBuffer.get(), ViewOpts, std::move(FunctionCoverage)); attachExpansionSubViews(*View, Expansions, Coverage); return View; }
void CodeCoverageTool::attachExpansionSubViews( SourceCoverageView &View, ArrayRef<ExpansionRecord> Expansions, const CoverageMapping &Coverage) { if (!ViewOpts.ShowExpandedRegions) return; for (const auto &Expansion : Expansions) { auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion); if (ExpansionCoverage.empty()) continue; auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename()); if (!SourceBuffer) continue; auto SubViewExpansions = ExpansionCoverage.getExpansions(); auto SubView = SourceCoverageView::create(Expansion.Function.Name, SourceBuffer.get(), ViewOpts, std::move(ExpansionCoverage)); attachExpansionSubViews(*SubView, SubViewExpansions, Coverage); View.addExpansion(Expansion.Region, std::move(SubView)); } }
void CodeCoverageTool::demangleSymbols(const CoverageMapping &Coverage) { if (!ViewOpts.hasDemangler()) return; // Pass function names to the demangler in a temporary file. int InputFD; SmallString<256> InputPath; std::error_code EC = sys::fs::createTemporaryFile("demangle-in", "list", InputFD, InputPath); if (EC) { error(InputPath, EC.message()); return; } tool_output_file InputTOF{InputPath, InputFD}; unsigned NumSymbols = 0; for (const auto &Function : Coverage.getCoveredFunctions()) { InputTOF.os() << Function.Name << '\n'; ++NumSymbols; } InputTOF.os().close(); // Use another temporary file to store the demangler's output. int OutputFD; SmallString<256> OutputPath; EC = sys::fs::createTemporaryFile("demangle-out", "list", OutputFD, OutputPath); if (EC) { error(OutputPath, EC.message()); return; } tool_output_file OutputTOF{OutputPath, OutputFD}; OutputTOF.os().close(); // Invoke the demangler. std::vector<const char *> ArgsV; for (const std::string &Arg : ViewOpts.DemanglerOpts) ArgsV.push_back(Arg.c_str()); ArgsV.push_back(nullptr); StringRef InputPathRef = InputPath.str(); StringRef OutputPathRef = OutputPath.str(); StringRef StderrRef; const StringRef *Redirects[] = {&InputPathRef, &OutputPathRef, &StderrRef}; std::string ErrMsg; int RC = sys::ExecuteAndWait(ViewOpts.DemanglerOpts[0], ArgsV.data(), /*env=*/nullptr, Redirects, /*secondsToWait=*/0, /*memoryLimit=*/0, &ErrMsg); if (RC) { error(ErrMsg, ViewOpts.DemanglerOpts[0]); return; } // Parse the demangler's output. auto BufOrError = MemoryBuffer::getFile(OutputPath); if (!BufOrError) { error(OutputPath, BufOrError.getError().message()); return; } std::unique_ptr<MemoryBuffer> DemanglerBuf = std::move(*BufOrError); SmallVector<StringRef, 8> Symbols; StringRef DemanglerData = DemanglerBuf->getBuffer(); DemanglerData.split(Symbols, '\n', /*MaxSplit=*/NumSymbols, /*KeepEmpty=*/false); if (Symbols.size() != NumSymbols) { error("Demangler did not provide expected number of symbols"); return; } // Cache the demangled names. unsigned I = 0; for (const auto &Function : Coverage.getCoveredFunctions()) DemangledNames[Function.Name] = Symbols[I++]; }