llvm-cov: Handle missing source files as GCOV does
authorJustin Bogner <mail@justinbogner.com>
Wed, 7 May 2014 02:11:23 +0000 (02:11 +0000)
committerJustin Bogner <mail@justinbogner.com>
Wed, 7 May 2014 02:11:23 +0000 (02:11 +0000)
If the source files referenced by a gcno file are missing, gcov
outputs a coverage file where every line is simply /*EOF*/.  This also
occurs for lines in the coverage that are past the end of a file that
is found.

This change mimics gcov.

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

include/llvm/Support/GCOV.h
lib/IR/GCOV.cpp
test/tools/llvm-cov/Inputs/test_missing.cpp.gcov [new file with mode: 0644]
test/tools/llvm-cov/Inputs/test_missing.h.gcov [new file with mode: 0644]
test/tools/llvm-cov/Inputs/test_missing.output [new file with mode: 0644]
test/tools/llvm-cov/llvm-cov.test

index 267693fa492f6e8f72e97af69f2ad74d943b3282..e06c0fa1dcf4d510ce6d1b89624452ba6a71f26c 100644 (file)
@@ -356,8 +356,10 @@ class FileInfo {
   typedef DenseMap<uint32_t, BlockVector> BlockLines;
 
   struct LineData {
+    LineData() : LastLine(0) {}
     BlockLines Blocks;
     FunctionLines Functions;
+    uint32_t LastLine;
   };
 
   struct GCOVCoverage {
@@ -379,11 +381,15 @@ public:
     Options(Options), LineInfo(), RunCount(0), ProgramCount(0) {}
 
   void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block) {
+    if (Line > LineInfo[Filename].LastLine)
+      LineInfo[Filename].LastLine = Line;
     LineInfo[Filename].Blocks[Line-1].push_back(Block);
   }
   void addFunctionLine(StringRef Filename, uint32_t Line,
                        const GCOVFunction *Function) {
-    LineInfo[Filename].Functions[Line-1].push_back(Function);
+    if (Line > LineInfo[Filename].LastLine)
+      LineInfo[Filename].LastLine = Line;
+   LineInfo[Filename].Functions[Line-1].push_back(Function);
   }
   void setRunCount(uint32_t Runs) { RunCount = Runs; }
   void setProgramCount(uint32_t Programs) { ProgramCount = Programs; }
index 05fe1e07dfda69be595df2e6a1ff1abd8246ae82..7a89723d85561ce4df776463c417e577b9bb9c54 100644 (file)
@@ -432,6 +432,30 @@ static raw_ostream &operator<<(raw_ostream &OS, const formatBranchInfo &FBI) {
   return OS;
 }
 
+namespace {
+class LineConsumer {
+  std::unique_ptr<MemoryBuffer> Buffer;
+  StringRef Remaining;
+public:
+  LineConsumer(StringRef Filename) {
+    if (error_code EC = MemoryBuffer::getFileOrSTDIN(Filename, Buffer)) {
+      errs() << Filename << ": " << EC.message() << "\n";
+      Remaining = "";
+    } else
+      Remaining = Buffer->getBuffer();
+  }
+  bool empty() { return Remaining.empty(); }
+  void printNext(raw_ostream &OS, uint32_t LineNum) {
+    StringRef Line;
+    if (empty())
+      Line = "/*EOF*/";
+    else
+      std::tie(Line, Remaining) = Remaining.split("\n");
+    OS << format("%5u:", LineNum) << Line << "\n";
+  }
+};
+}
+
 /// Convert a path to a gcov filename. If PreservePaths is true, this
 /// translates "/" to "#", ".." to "^", and drops ".", to match gcov.
 static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths) {
@@ -505,12 +529,7 @@ void FileInfo::print(StringRef MainFilename, StringRef GCNOFile,
   for (StringMap<LineData>::const_iterator I = LineInfo.begin(),
          E = LineInfo.end(); I != E; ++I) {
     StringRef Filename = I->first();
-    std::unique_ptr<MemoryBuffer> Buff;
-    if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) {
-      errs() << Filename << ": " << ec.message() << "\n";
-      return;
-    }
-    StringRef AllLines = Buff->getBuffer();
+    auto AllLines = LineConsumer(Filename);
 
     std::string CoveragePath = getCoveragePath(Filename, MainFilename);
     std::unique_ptr<raw_ostream> S = openCoveragePath(CoveragePath);
@@ -524,7 +543,8 @@ void FileInfo::print(StringRef MainFilename, StringRef GCNOFile,
 
     const LineData &Line = I->second;
     GCOVCoverage FileCoverage(Filename);
-    for (uint32_t LineIndex = 0; !AllLines.empty(); ++LineIndex) {
+    for (uint32_t LineIndex = 0;
+         LineIndex < Line.LastLine || !AllLines.empty(); ++LineIndex) {
       if (Options.BranchInfo) {
         FunctionLines::const_iterator FuncsIt = Line.Functions.find(LineIndex);
         if (FuncsIt != Line.Functions.end())
@@ -535,9 +555,7 @@ void FileInfo::print(StringRef MainFilename, StringRef GCNOFile,
       if (BlocksIt == Line.Blocks.end()) {
         // No basic blocks are on this line. Not an executable line of code.
         OS << "        -:";
-        std::pair<StringRef, StringRef> P = AllLines.split('\n');
-        OS << format("%5u:", LineIndex+1) << P.first << "\n";
-        AllLines = P.second;
+        AllLines.printNext(OS, LineIndex + 1);
       } else {
         const BlockVector &Blocks = BlocksIt->second;
 
@@ -599,9 +617,7 @@ void FileInfo::print(StringRef MainFilename, StringRef GCNOFile,
         }
         ++FileCoverage.LogicalLines;
 
-        std::pair<StringRef, StringRef> P = AllLines.split('\n');
-        OS << format("%5u:", LineIndex+1) << P.first << "\n";
-        AllLines = P.second;
+        AllLines.printNext(OS, LineIndex + 1);
 
         uint32_t BlockNo = 0;
         uint32_t EdgeNo = 0;
diff --git a/test/tools/llvm-cov/Inputs/test_missing.cpp.gcov b/test/tools/llvm-cov/Inputs/test_missing.cpp.gcov
new file mode 100644 (file)
index 0000000..1c138e4
--- /dev/null
@@ -0,0 +1,77 @@
+        -:    0:Source:srcdir/./nested_dir/../test.cpp
+        -:    0:Graph:test_paths.gcno
+        -:    0:Data:test_paths.gcda
+        -:    0:Runs:3
+        -:    0:Programs:1
+        -:    1:/*EOF*/
+        -:    2:/*EOF*/
+        -:    3:/*EOF*/
+        -:    4:/*EOF*/
+        -:    5:/*EOF*/
+        -:    6:/*EOF*/
+        -:    7:/*EOF*/
+        -:    8:/*EOF*/
+        -:    9:/*EOF*/
+12884901888:   10:/*EOF*/
+        -:   11:/*EOF*/
+    #####:   12:/*EOF*/
+        -:   13:/*EOF*/
+        -:   14:/*EOF*/
+    #####:   15:/*EOF*/
+        -:   16:/*EOF*/
+        -:   17:/*EOF*/
+        -:   18:/*EOF*/
+        3:   19:/*EOF*/
+        3:   20:/*EOF*/
+        -:   21:/*EOF*/
+        -:   22:/*EOF*/
+        -:   23:/*EOF*/
+    #####:   24:/*EOF*/
+    #####:   25:/*EOF*/
+        -:   26:/*EOF*/
+        -:   27:/*EOF*/
+       12:   28:/*EOF*/
+       12:   29:/*EOF*/
+       12:   30:/*EOF*/
+        -:   31:/*EOF*/
+        -:   32:/*EOF*/
+       21:   33:/*EOF*/
+       36:   34:/*EOF*/
+       18:   35:/*EOF*/
+        3:   36:/*EOF*/
+        -:   37:/*EOF*/
+        -:   38:/*EOF*/
+        3:   39:/*EOF*/
+        -:   40:/*EOF*/
+        3:   41:/*EOF*/
+        3:   42:/*EOF*/
+        3:   43:/*EOF*/
+        3:   44:/*EOF*/
+        3:   45:/*EOF*/
+        3:   46:/*EOF*/
+    #####:   47:/*EOF*/
+    #####:   48:/*EOF*/
+        -:   49:/*EOF*/
+        -:   50:/*EOF*/
+       66:   51:/*EOF*/
+       30:   52:/*EOF*/
+        -:   53:/*EOF*/
+        6:   54:/*EOF*/
+        6:   55:/*EOF*/
+        -:   56:/*EOF*/
+        -:   57:/*EOF*/
+        3:   58:/*EOF*/
+        3:   59:/*EOF*/
+        -:   60:/*EOF*/
+        9:   61:/*EOF*/
+        9:   62:/*EOF*/
+        -:   63:/*EOF*/
+       12:   64:/*EOF*/
+       12:   65:/*EOF*/
+       30:   66:/*EOF*/
+        -:   67:/*EOF*/
+        3:   68:/*EOF*/
+25769803782:   69:/*EOF*/
+12884901888:   70:/*EOF*/
+        -:   71:/*EOF*/
+        3:   72:/*EOF*/
diff --git a/test/tools/llvm-cov/Inputs/test_missing.h.gcov b/test/tools/llvm-cov/Inputs/test_missing.h.gcov
new file mode 100644 (file)
index 0000000..d500e86
--- /dev/null
@@ -0,0 +1,6 @@
+        -:    0:Source:srcdir/./nested_dir/../test.h
+        -:    0:Graph:test_paths.gcno
+        -:    0:Data:test_paths.gcda
+        -:    0:Runs:3
+        -:    0:Programs:1
+        6:    1:/*EOF*/
diff --git a/test/tools/llvm-cov/Inputs/test_missing.output b/test/tools/llvm-cov/Inputs/test_missing.output
new file mode 100644 (file)
index 0000000..ada0c36
--- /dev/null
@@ -0,0 +1,8 @@
+File 'srcdir/./nested_dir/../test.h'
+Lines executed:100.00% of 1
+srcdir/./nested_dir/../test.h:creating 'test.h.gcov'
+
+File 'srcdir/./nested_dir/../test.cpp'
+Lines executed:84.21% of 38
+srcdir/./nested_dir/../test.cpp:creating 'test.cpp.gcov'
+
index 8f57d9a189312533a204d991a461f5ebd284cefe..2345f8d51e804507a6d27a96ad1ac3d32aa8f89c 100644 (file)
@@ -34,6 +34,12 @@ RUN: diff -aub test_objdir.h.gcov test.h.gcov
 # With gcov output disabled
 RUN: llvm-cov -n test.c | diff -u test_no_output.output -
 
+# Missing source files. This test is fragile, as it depends on being
+# run before we copy some sources into place in the next test.
+RUN: llvm-cov test_paths.cpp 2>/dev/null | diff -u test_missing.output -
+RUN: diff -aub test_missing.cpp.gcov test.cpp.gcov
+RUN: diff -aub test_missing.h.gcov test.h.gcov
+
 # Preserve paths. This mangles the output filenames.
 RUN: mkdir -p %t/srcdir/nested_dir
 RUN: cp test.cpp test.h %t/srcdir