llvm-cov: Simplify coverage reports, fixing PR22575 in the process
authorJustin Bogner <mail@justinbogner.com>
Sat, 14 Feb 2015 02:01:24 +0000 (02:01 +0000)
committerJustin Bogner <mail@justinbogner.com>
Sat, 14 Feb 2015 02:01:24 +0000 (02:01 +0000)
PR22575 occurred because we were unsafely storing references into a
std::vector. If the vector moved because it grew, we'd be left
iterating through garbage memory. This avoids the issue by simplifying
the logic to gather coverage information as we go, rather than storing
it and iterating over it.

I'm relying on the existing tests showing that this is semantically
NFC, since it's difficult to hit the issue this fixes without
relatively large covered programs.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@229215 91177308-0d34-0410-b5e6-96231b3b80d8

tools/llvm-cov/CMakeLists.txt
tools/llvm-cov/CodeCoverage.cpp
tools/llvm-cov/CoverageReport.cpp
tools/llvm-cov/CoverageReport.h
tools/llvm-cov/CoverageSummary.cpp [deleted file]
tools/llvm-cov/CoverageSummary.h [deleted file]
tools/llvm-cov/CoverageSummaryInfo.cpp
tools/llvm-cov/CoverageSummaryInfo.h

index b2d2b897ec95b5f92d443be4aa06a056980a1b51..193218a6639f22d1b0ce1a0f13e7396577d3b573 100644 (file)
@@ -6,7 +6,6 @@ add_llvm_tool(llvm-cov
   CodeCoverage.cpp
   CoverageFilters.cpp
   CoverageReport.cpp
   CodeCoverage.cpp
   CoverageFilters.cpp
   CoverageReport.cpp
-  CoverageSummary.cpp
   CoverageSummaryInfo.cpp
   SourceCoverageView.cpp
   TestingSupport.cpp
   CoverageSummaryInfo.cpp
   SourceCoverageView.cpp
   TestingSupport.cpp
index 98a044f115d6aa412caae137454cc4f9a628c45c..feaa3fcd857213a5b412ba2e749be78417989442 100644 (file)
@@ -16,7 +16,6 @@
 #include "RenderingSupport.h"
 #include "CoverageFilters.h"
 #include "CoverageReport.h"
 #include "RenderingSupport.h"
 #include "CoverageFilters.h"
 #include "CoverageReport.h"
-#include "CoverageSummary.h"
 #include "CoverageViewOptions.h"
 #include "SourceCoverageView.h"
 #include "llvm/ADT/SmallString.h"
 #include "CoverageViewOptions.h"
 #include "SourceCoverageView.h"
 #include "llvm/ADT/SmallString.h"
@@ -459,9 +458,7 @@ int CodeCoverageTool::report(int argc, const char **argv,
   if (!Coverage)
     return 1;
 
   if (!Coverage)
     return 1;
 
-  CoverageSummary Summarizer;
-  Summarizer.createSummaries(*Coverage);
-  CoverageReport Report(ViewOpts, Summarizer);
+  CoverageReport Report(ViewOpts, std::move(Coverage));
   if (SourceFiles.empty() && Filters.empty()) {
     Report.renderFileReports(llvm::outs());
     return 0;
   if (SourceFiles.empty() && Filters.empty()) {
     Report.renderFileReports(llvm::outs());
     return 0;
index 6ae6ba55eb9cb7964f8b9096d566c41d5907bae6..db0754268c30b1fc360259023c17a1678256ddd5 100644 (file)
@@ -12,7 +12,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "CoverageReport.h"
 //===----------------------------------------------------------------------===//
 
 #include "CoverageReport.h"
-#include "CoverageSummary.h"
 #include "RenderingSupport.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Format.h"
 #include "RenderingSupport.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Format.h"
@@ -158,12 +157,12 @@ void CoverageReport::render(const FunctionCoverageSummary &Function,
 
 void CoverageReport::renderFunctionReports(raw_ostream &OS) {
   bool isFirst = true;
 
 void CoverageReport::renderFunctionReports(raw_ostream &OS) {
   bool isFirst = true;
-  for (const auto &File : Summary.getFileSummaries()) {
+  for (StringRef Filename : Coverage->getUniqueSourceFiles()) {
     if (isFirst)
       isFirst = false;
     else
       OS << "\n";
     if (isFirst)
       isFirst = false;
     else
       OS << "\n";
-    OS << "File '" << File.Name << "':\n";
+    OS << "File '" << Filename << "':\n";
     OS << column("Name", FunctionReportColumns[0])
        << column("Regions", FunctionReportColumns[1], Column::RightAlignment)
        << column("Miss", FunctionReportColumns[2], Column::RightAlignment)
     OS << column("Name", FunctionReportColumns[0])
        << column("Regions", FunctionReportColumns[1], Column::RightAlignment)
        << column("Miss", FunctionReportColumns[2], Column::RightAlignment)
@@ -174,13 +173,19 @@ void CoverageReport::renderFunctionReports(raw_ostream &OS) {
     OS << "\n";
     renderDivider(FunctionReportColumns, OS);
     OS << "\n";
     OS << "\n";
     renderDivider(FunctionReportColumns, OS);
     OS << "\n";
-    for (const auto &Function : File.FunctionSummaries)
+    FunctionCoverageSummary Totals("TOTAL");
+    for (const auto &F : Coverage->getCoveredFunctions(Filename)) {
+      FunctionCoverageSummary Function = FunctionCoverageSummary::get(F);
+      ++Totals.ExecutionCount;
+      Totals.RegionCoverage += Function.RegionCoverage;
+      Totals.LineCoverage += Function.LineCoverage;
       render(Function, OS);
       render(Function, OS);
-    renderDivider(FunctionReportColumns, OS);
-    OS << "\n";
-    render(FunctionCoverageSummary("TOTAL", /*ExecutionCount=*/0,
-                                   File.RegionCoverage, File.LineCoverage),
-           OS);
+    }
+    if (Totals.ExecutionCount) {
+      renderDivider(FunctionReportColumns, OS);
+      OS << "\n";
+      render(Totals, OS);
+    }
   }
 }
 
   }
 }
 
@@ -194,9 +199,17 @@ void CoverageReport::renderFileReports(raw_ostream &OS) {
      << "\n";
   renderDivider(FileReportColumns, OS);
   OS << "\n";
      << "\n";
   renderDivider(FileReportColumns, OS);
   OS << "\n";
-  for (const auto &File : Summary.getFileSummaries())
-    render(File, OS);
+  FileCoverageSummary Totals("TOTAL");
+  for (StringRef Filename : Coverage->getUniqueSourceFiles()) {
+    FileCoverageSummary Summary(Filename);
+    for (const auto &F : Coverage->getCoveredFunctions(Filename)) {
+      FunctionCoverageSummary Function = FunctionCoverageSummary::get(F);
+      Summary.addFunction(Function);
+      Totals.addFunction(Function);
+    }
+    render(Summary, OS);
+  }
   renderDivider(FileReportColumns, OS);
   OS << "\n";
   renderDivider(FileReportColumns, OS);
   OS << "\n";
-  render(Summary.getCombinedFileSummaries(), OS);
+  render(Totals, OS);
 }
 }
index d18611740ae6b1ad2d1a0116dea6499fa422f64e..78e49d9b7140a86be51184ef233ea6217653c903 100644 (file)
@@ -14,7 +14,7 @@
 #ifndef LLVM_COV_COVERAGEREPORT_H
 #define LLVM_COV_COVERAGEREPORT_H
 
 #ifndef LLVM_COV_COVERAGEREPORT_H
 #define LLVM_COV_COVERAGEREPORT_H
 
-#include "CoverageSummary.h"
+#include "CoverageSummaryInfo.h"
 #include "CoverageViewOptions.h"
 
 namespace llvm {
 #include "CoverageViewOptions.h"
 
 namespace llvm {
@@ -22,14 +22,15 @@ namespace llvm {
 /// \brief Displays the code coverage report.
 class CoverageReport {
   const CoverageViewOptions &Options;
 /// \brief Displays the code coverage report.
 class CoverageReport {
   const CoverageViewOptions &Options;
-  CoverageSummary &Summary;
+  std::unique_ptr<coverage::CoverageMapping> Coverage;
 
   void render(const FileCoverageSummary &File, raw_ostream &OS);
   void render(const FunctionCoverageSummary &Function, raw_ostream &OS);
 
 public:
 
   void render(const FileCoverageSummary &File, raw_ostream &OS);
   void render(const FunctionCoverageSummary &Function, raw_ostream &OS);
 
 public:
-  CoverageReport(const CoverageViewOptions &Options, CoverageSummary &Summary)
-      : Options(Options), Summary(Summary) {}
+  CoverageReport(const CoverageViewOptions &Options,
+                 std::unique_ptr<coverage::CoverageMapping> Coverage)
+      : Options(Options), Coverage(std::move(Coverage)) {}
 
   void renderFunctionReports(raw_ostream &OS);
 
 
   void renderFunctionReports(raw_ostream &OS);
 
diff --git a/tools/llvm-cov/CoverageSummary.cpp b/tools/llvm-cov/CoverageSummary.cpp
deleted file mode 100644 (file)
index 059c8c8..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-//===- CoverageSummary.cpp - Code coverage summary ------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This class implements data management and rendering for the code coverage
-// summaries of all files and functions.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CoverageSummary.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Format.h"
-
-using namespace llvm;
-
-unsigned CoverageSummary::getFileID(StringRef Filename) {
-  for (unsigned I = 0, E = Filenames.size(); I < E; ++I) {
-    if (sys::fs::equivalent(Filenames[I], Filename))
-      return I;
-  }
-  Filenames.push_back(Filename);
-  return Filenames.size() - 1;
-}
-
-void
-CoverageSummary::createSummaries(const coverage::CoverageMapping &Coverage) {
-  for (StringRef Filename : Coverage.getUniqueSourceFiles()) {
-    size_t PrevSize = FunctionSummaries.size();
-    for (const auto &F : Coverage.getCoveredFunctions(Filename))
-      FunctionSummaries.push_back(FunctionCoverageSummary::get(F));
-    size_t Count = FunctionSummaries.size() - PrevSize;
-    if (Count == 0)
-      continue;
-    FileSummaries.push_back(FileCoverageSummary::get(
-        Filename, makeArrayRef(FunctionSummaries.data() + PrevSize, Count)));
-  }
-}
-
-FileCoverageSummary CoverageSummary::getCombinedFileSummaries() {
-  size_t NumRegions = 0, CoveredRegions = 0;
-  size_t NumLines = 0, NonCodeLines = 0, CoveredLines = 0;
-  size_t NumFunctionsExecuted = 0, NumFunctions = 0;
-  for (const auto &File : FileSummaries) {
-    NumRegions += File.RegionCoverage.NumRegions;
-    CoveredRegions += File.RegionCoverage.Covered;
-
-    NumLines += File.LineCoverage.NumLines;
-    NonCodeLines += File.LineCoverage.NonCodeLines;
-    CoveredLines += File.LineCoverage.Covered;
-
-    NumFunctionsExecuted += File.FunctionCoverage.Executed;
-    NumFunctions += File.FunctionCoverage.NumFunctions;
-  }
-  return FileCoverageSummary(
-      "TOTAL", RegionCoverageInfo(CoveredRegions, NumRegions),
-      LineCoverageInfo(CoveredLines, NonCodeLines, NumLines),
-      FunctionCoverageInfo(NumFunctionsExecuted, NumFunctions),
-      None);
-}
diff --git a/tools/llvm-cov/CoverageSummary.h b/tools/llvm-cov/CoverageSummary.h
deleted file mode 100644 (file)
index 9dbebde..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-//===- CoverageSummary.h - Code coverage summary --------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This class implements data management and rendering for the code coverage
-// summaries of all files and functions.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_COV_COVERAGESUMMARY_H
-#define LLVM_COV_COVERAGESUMMARY_H
-
-#include "CoverageSummaryInfo.h"
-#include <vector>
-
-namespace llvm {
-
-/// \brief Manager for the function and file code coverage summaries.
-class CoverageSummary {
-  std::vector<StringRef> Filenames;
-  std::vector<FunctionCoverageSummary> FunctionSummaries;
-  std::vector<std::pair<unsigned, unsigned>> FunctionSummariesFileIDs;
-  std::vector<FileCoverageSummary> FileSummaries;
-
-  unsigned getFileID(StringRef Filename);
-
-public:
-  void createSummaries(const coverage::CoverageMapping &Coverage);
-
-  ArrayRef<FileCoverageSummary> getFileSummaries() { return FileSummaries; }
-
-  FileCoverageSummary getCombinedFileSummaries();
-
-  void render(const FunctionCoverageSummary &Summary, raw_ostream &OS);
-
-  void render(raw_ostream &OS);
-};
-}
-
-#endif // LLVM_COV_COVERAGESUMMARY_H
index dd78ace86050c6cfb0b0262c18bc7506af5f59cc..de8975097e4929a3b47dcaaa240a4e831b9210fe 100644 (file)
@@ -69,28 +69,3 @@ FunctionCoverageSummary::get(const coverage::FunctionRecord &Function) {
       RegionCoverageInfo(CoveredRegions, NumCodeRegions),
       LineCoverageInfo(CoveredLines, 0, NumLines));
 }
       RegionCoverageInfo(CoveredRegions, NumCodeRegions),
       LineCoverageInfo(CoveredLines, 0, NumLines));
 }
-
-FileCoverageSummary
-FileCoverageSummary::get(StringRef Name,
-                         ArrayRef<FunctionCoverageSummary> FunctionSummaries) {
-  size_t NumRegions = 0, CoveredRegions = 0;
-  size_t NumLines = 0, NonCodeLines = 0, CoveredLines = 0;
-  size_t NumFunctionsExecuted = 0;
-  for (const auto &Func : FunctionSummaries) {
-    CoveredRegions += Func.RegionCoverage.Covered;
-    NumRegions += Func.RegionCoverage.NumRegions;
-
-    CoveredLines += Func.LineCoverage.Covered;
-    NonCodeLines += Func.LineCoverage.NonCodeLines;
-    NumLines += Func.LineCoverage.NumLines;
-
-    if (Func.ExecutionCount != 0)
-      ++NumFunctionsExecuted;
-  }
-
-  return FileCoverageSummary(
-      Name, RegionCoverageInfo(CoveredRegions, NumRegions),
-      LineCoverageInfo(CoveredLines, NonCodeLines, NumLines),
-      FunctionCoverageInfo(NumFunctionsExecuted, FunctionSummaries.size()),
-      FunctionSummaries);
-}
index 0036032ab399816d32346ba4727820f1b400cedf..c393b00d32a43ee157b5d6e2bb7f296931a6de2f 100644 (file)
@@ -31,10 +31,19 @@ struct RegionCoverageInfo {
   /// \brief The total number of regions in a function/file.
   size_t NumRegions;
 
   /// \brief The total number of regions in a function/file.
   size_t NumRegions;
 
+  RegionCoverageInfo() : Covered(0), NotCovered(0), NumRegions(0) {}
+
   RegionCoverageInfo(size_t Covered, size_t NumRegions)
       : Covered(Covered), NotCovered(NumRegions - Covered),
         NumRegions(NumRegions) {}
 
   RegionCoverageInfo(size_t Covered, size_t NumRegions)
       : Covered(Covered), NotCovered(NumRegions - Covered),
         NumRegions(NumRegions) {}
 
+  RegionCoverageInfo &operator+=(const RegionCoverageInfo &RHS) {
+    Covered += RHS.Covered;
+    NotCovered += RHS.NotCovered;
+    NumRegions += RHS.NumRegions;
+    return *this;
+  }
+
   bool isFullyCovered() const { return Covered == NumRegions; }
 
   double getPercentCovered() const {
   bool isFullyCovered() const { return Covered == NumRegions; }
 
   double getPercentCovered() const {
@@ -56,10 +65,21 @@ struct LineCoverageInfo {
   /// \brief The total number of lines in a function/file.
   size_t NumLines;
 
   /// \brief The total number of lines in a function/file.
   size_t NumLines;
 
+  LineCoverageInfo()
+      : Covered(0), NotCovered(0), NonCodeLines(0), NumLines(0) {}
+
   LineCoverageInfo(size_t Covered, size_t NumNonCodeLines, size_t NumLines)
       : Covered(Covered), NotCovered(NumLines - NumNonCodeLines - Covered),
         NonCodeLines(NumNonCodeLines), NumLines(NumLines) {}
 
   LineCoverageInfo(size_t Covered, size_t NumNonCodeLines, size_t NumLines)
       : Covered(Covered), NotCovered(NumLines - NumNonCodeLines - Covered),
         NonCodeLines(NumNonCodeLines), NumLines(NumLines) {}
 
+  LineCoverageInfo &operator+=(const LineCoverageInfo &RHS) {
+    Covered += RHS.Covered;
+    NotCovered += RHS.NotCovered;
+    NonCodeLines += RHS.NonCodeLines;
+    NumLines += RHS.NumLines;
+    return *this;
+  }
+
   bool isFullyCovered() const { return Covered == (NumLines - NonCodeLines); }
 
   double getPercentCovered() const {
   bool isFullyCovered() const { return Covered == (NumLines - NonCodeLines); }
 
   double getPercentCovered() const {
@@ -75,9 +95,17 @@ struct FunctionCoverageInfo {
   /// \brief The total number of functions in this file.
   size_t NumFunctions;
 
   /// \brief The total number of functions in this file.
   size_t NumFunctions;
 
+  FunctionCoverageInfo() : Executed(0), NumFunctions(0) {}
+
   FunctionCoverageInfo(size_t Executed, size_t NumFunctions)
       : Executed(Executed), NumFunctions(NumFunctions) {}
 
   FunctionCoverageInfo(size_t Executed, size_t NumFunctions)
       : Executed(Executed), NumFunctions(NumFunctions) {}
 
+  void addFunction(bool Covered) {
+    if (Covered)
+      ++Executed;
+    ++NumFunctions;
+  }
+
   bool isFullyCovered() const { return Executed == NumFunctions; }
 
   double getPercentCovered() const {
   bool isFullyCovered() const { return Executed == NumFunctions; }
 
   double getPercentCovered() const {
@@ -92,6 +120,8 @@ struct FunctionCoverageSummary {
   RegionCoverageInfo RegionCoverage;
   LineCoverageInfo LineCoverage;
 
   RegionCoverageInfo RegionCoverage;
   LineCoverageInfo LineCoverage;
 
+  FunctionCoverageSummary(StringRef Name) : Name(Name), ExecutionCount(0) {}
+
   FunctionCoverageSummary(StringRef Name, uint64_t ExecutionCount,
                           const RegionCoverageInfo &RegionCoverage,
                           const LineCoverageInfo &LineCoverage)
   FunctionCoverageSummary(StringRef Name, uint64_t ExecutionCount,
                           const RegionCoverageInfo &RegionCoverage,
                           const LineCoverageInfo &LineCoverage)
@@ -111,21 +141,14 @@ struct FileCoverageSummary {
   RegionCoverageInfo RegionCoverage;
   LineCoverageInfo LineCoverage;
   FunctionCoverageInfo FunctionCoverage;
   RegionCoverageInfo RegionCoverage;
   LineCoverageInfo LineCoverage;
   FunctionCoverageInfo FunctionCoverage;
-  /// \brief The summary of every function
-  /// in this file.
-  ArrayRef<FunctionCoverageSummary> FunctionSummaries;
-
-  FileCoverageSummary(StringRef Name, const RegionCoverageInfo &RegionCoverage,
-                      const LineCoverageInfo &LineCoverage,
-                      const FunctionCoverageInfo &FunctionCoverage,
-                      ArrayRef<FunctionCoverageSummary> FunctionSummaries)
-      : Name(Name), RegionCoverage(RegionCoverage), LineCoverage(LineCoverage),
-        FunctionCoverage(FunctionCoverage),
-        FunctionSummaries(FunctionSummaries) {}
-
-  /// \brief Compute the code coverage summary for a file.
-  static FileCoverageSummary
-  get(StringRef Name, ArrayRef<FunctionCoverageSummary> FunctionSummaries);
+
+  FileCoverageSummary(StringRef Name) : Name(Name) {}
+
+  void addFunction(const FunctionCoverageSummary &Function) {
+    RegionCoverage += Function.RegionCoverage;
+    LineCoverage += Function.LineCoverage;
+    FunctionCoverage.addFunction(/*Covered=*/Function.ExecutionCount > 0);
+  }
 };
 
 } // namespace llvm
 };
 
 } // namespace llvm