Example #1
0
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;
}
Example #2
0
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();
  }
Example #5
0
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;
}
Example #6
0
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));
  }
}
Example #7
0
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++];
}