From c92330c18ce2f7015f0db88e4bfce3d253fa3c57 Mon Sep 17 00:00:00 2001 From: Justin Bogner Date: Wed, 7 May 2014 02:11:23 +0000 Subject: llvm-cov: Handle missing source files as GCOV does 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 | 8 ++- lib/IR/GCOV.cpp | 42 +++++++++---- test/tools/llvm-cov/Inputs/test_missing.cpp.gcov | 77 ++++++++++++++++++++++++ test/tools/llvm-cov/Inputs/test_missing.h.gcov | 6 ++ test/tools/llvm-cov/Inputs/test_missing.output | 8 +++ test/tools/llvm-cov/llvm-cov.test | 6 ++ 6 files changed, 133 insertions(+), 14 deletions(-) create mode 100644 test/tools/llvm-cov/Inputs/test_missing.cpp.gcov create mode 100644 test/tools/llvm-cov/Inputs/test_missing.h.gcov create mode 100644 test/tools/llvm-cov/Inputs/test_missing.output diff --git a/include/llvm/Support/GCOV.h b/include/llvm/Support/GCOV.h index 267693fa49..e06c0fa1dc 100644 --- a/include/llvm/Support/GCOV.h +++ b/include/llvm/Support/GCOV.h @@ -356,8 +356,10 @@ class FileInfo { typedef DenseMap 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; } diff --git a/lib/IR/GCOV.cpp b/lib/IR/GCOV.cpp index 05fe1e07df..7a89723d85 100644 --- a/lib/IR/GCOV.cpp +++ b/lib/IR/GCOV.cpp @@ -432,6 +432,30 @@ static raw_ostream &operator<<(raw_ostream &OS, const formatBranchInfo &FBI) { return OS; } +namespace { +class LineConsumer { + std::unique_ptr 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::const_iterator I = LineInfo.begin(), E = LineInfo.end(); I != E; ++I) { StringRef Filename = I->first(); - std::unique_ptr 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 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 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 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 index 0000000000..1c138e4258 --- /dev/null +++ b/test/tools/llvm-cov/Inputs/test_missing.cpp.gcov @@ -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 index 0000000000..d500e86196 --- /dev/null +++ b/test/tools/llvm-cov/Inputs/test_missing.h.gcov @@ -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 index 0000000000..ada0c36030 --- /dev/null +++ b/test/tools/llvm-cov/Inputs/test_missing.output @@ -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' + diff --git a/test/tools/llvm-cov/llvm-cov.test b/test/tools/llvm-cov/llvm-cov.test index 8f57d9a189..2345f8d51e 100644 --- a/test/tools/llvm-cov/llvm-cov.test +++ b/test/tools/llvm-cov/llvm-cov.test @@ -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 -- cgit v1.2.3