[llvm-cov gcov] Add -r (--relative-only) && -s (--source-prefix)

gcov 4.7 introduced the two options.
https://sourceware.org/pipermail/gcc-patches/2011-November/328782.html

-r only dumps files with relative paths or absolute paths with the prefix
specified by -s. The two options are useful filtering out system header files.
This commit is contained in:
Fangrui Song 2020-09-13 14:54:20 -07:00
parent cb3e1dd6c3
commit b2c32c90ba
6 changed files with 79 additions and 7 deletions

View File

@ -48,10 +48,11 @@ enum GCOVVersion { V304, V407, V408, V800, V900 };
/// A struct for passing gcov options between functions. /// A struct for passing gcov options between functions.
struct Options { struct Options {
Options(bool A, bool B, bool C, bool F, bool P, bool U, bool I, bool L, Options(bool A, bool B, bool C, bool F, bool P, bool U, bool I, bool L,
bool N, bool T, bool X) bool N, bool R, bool T, bool X, std::string SourcePrefix)
: AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F), : AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F),
PreservePaths(P), UncondBranch(U), Intermediate(I), LongFileNames(L), PreservePaths(P), UncondBranch(U), Intermediate(I), LongFileNames(L),
NoOutput(N), UseStdout(T), HashFilenames(X) {} NoOutput(N), RelativeOnly(R), UseStdout(T), HashFilenames(X),
SourcePrefix(std::move(SourcePrefix)) {}
bool AllBlocks; bool AllBlocks;
bool BranchInfo; bool BranchInfo;
@ -62,8 +63,10 @@ struct Options {
bool Intermediate; bool Intermediate;
bool LongFileNames; bool LongFileNames;
bool NoOutput; bool NoOutput;
bool RelativeOnly;
bool UseStdout; bool UseStdout;
bool HashFilenames; bool HashFilenames;
std::string SourcePrefix;
}; };
} // end namespace GCOV } // end namespace GCOV
@ -341,9 +344,11 @@ struct GCOVCoverage {
struct SourceInfo { struct SourceInfo {
StringRef filename; StringRef filename;
SmallString<0> displayName;
std::string name; std::string name;
std::vector<GCOVFunction *> functions; std::vector<GCOVFunction *> functions;
GCOVCoverage coverage; GCOVCoverage coverage;
bool ignored = false;
SourceInfo(StringRef filename) : filename(filename) {} SourceInfo(StringRef filename) : filename(filename) {}
}; };

View File

@ -261,8 +261,24 @@ LLVM_DUMP_METHOD void GCOVFile::dump() const { print(dbgs()); }
/// reading .gcno and .gcda files. /// reading .gcno and .gcda files.
void GCOVFile::collectLineCounts(FileInfo &fi) { void GCOVFile::collectLineCounts(FileInfo &fi) {
assert(fi.sources.empty()); assert(fi.sources.empty());
for (StringRef filename : filenames) for (StringRef filename : filenames) {
fi.sources.emplace_back(filename); fi.sources.emplace_back(filename);
SourceInfo &si = fi.sources.back();
si.displayName = si.filename;
if (!fi.Options.SourcePrefix.empty() &&
sys::path::replace_path_prefix(si.displayName, fi.Options.SourcePrefix,
"") &&
!si.displayName.empty()) {
// TODO replace_path_prefix may strip the prefix even if the remaining
// part does not start with a separator.
if (sys::path::is_separator(si.displayName[0]))
si.displayName.erase(si.displayName.begin());
else
si.displayName = si.filename;
}
if (fi.Options.RelativeOnly && sys::path::is_absolute(si.displayName))
si.ignored = true;
}
for (GCOVFunction &f : *this) { for (GCOVFunction &f : *this) {
f.collectLineCounts(fi); f.collectLineCounts(fi);
fi.sources[f.srcIdx].functions.push_back(&f); fi.sources[f.srcIdx].functions.push_back(&f);
@ -664,6 +680,10 @@ void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename,
llvm::sort(Filenames); llvm::sort(Filenames);
for (StringRef Filename : Filenames) { for (StringRef Filename : Filenames) {
SourceInfo &source = sources[file.filenameToIdx.find(Filename)->second];
if (source.ignored)
continue;
auto AllLines = auto AllLines =
Options.Intermediate ? LineConsumer() : LineConsumer(Filename); Options.Intermediate ? LineConsumer() : LineConsumer(Filename);
std::string CoveragePath = getCoveragePath(Filename, MainFilename); std::string CoveragePath = getCoveragePath(Filename, MainFilename);
@ -675,7 +695,7 @@ void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename,
raw_ostream &CovOS = raw_ostream &CovOS =
!Options.NoOutput && Options.UseStdout ? llvm::outs() : *CovStream; !Options.NoOutput && Options.UseStdout ? llvm::outs() : *CovStream;
CovOS << " -: 0:Source:" << Filename << "\n"; CovOS << " -: 0:Source:" << source.displayName << "\n";
CovOS << " -: 0:Graph:" << GCNOFile << "\n"; CovOS << " -: 0:Graph:" << GCNOFile << "\n";
CovOS << " -: 0:Data:" << GCDAFile << "\n"; CovOS << " -: 0:Data:" << GCDAFile << "\n";
CovOS << " -: 0:Runs:" << RunCount << "\n"; CovOS << " -: 0:Runs:" << RunCount << "\n";
@ -683,7 +703,7 @@ void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename,
CovOS << " -: 0:Programs:" << ProgramCount << "\n"; CovOS << " -: 0:Programs:" << ProgramCount << "\n";
const LineData &Line = LineInfo[Filename]; const LineData &Line = LineInfo[Filename];
GCOVCoverage FileCoverage(Filename); GCOVCoverage FileCoverage(source.displayName);
for (uint32_t LineIndex = 0; LineIndex < Line.LastLine || !AllLines.empty(); for (uint32_t LineIndex = 0; LineIndex < Line.LastLine || !AllLines.empty();
++LineIndex) { ++LineIndex) {
if (Options.BranchInfo) { if (Options.BranchInfo) {
@ -767,7 +787,6 @@ void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename,
} }
} }
} }
SourceInfo &source = sources[file.filenameToIdx.find(Filename)->second];
source.name = CoveragePath; source.name = CoveragePath;
source.coverage = FileCoverage; source.coverage = FileCoverage;
} }
@ -928,6 +947,8 @@ void FileInfo::printFuncCoverage(raw_ostream &OS) const {
// printFileCoverage - Print per-file coverage info. // printFileCoverage - Print per-file coverage info.
void FileInfo::printFileCoverage(raw_ostream &OS) const { void FileInfo::printFileCoverage(raw_ostream &OS) const {
for (const SourceInfo &source : sources) { for (const SourceInfo &source : sources) {
if (source.ignored)
continue;
const GCOVCoverage &Coverage = source.coverage; const GCOVCoverage &Coverage = source.coverage;
OS << "File '" << Coverage.Name << "'\n"; OS << "File '" << Coverage.Name << "'\n";
printCoverage(OS, Coverage); printCoverage(OS, Coverage);

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,37 @@
# Test -r (--relative-only) and -s (--source-prefix).
RUN: rm -rf %t && mkdir %t && cd %t
RUN: cp %S/Inputs/abs-path.gcno %S/Inputs/abs-path.gcda .
RUN: llvm-cov gcov abs-path.gcda | FileCheck %s
RUN: rm abs-path.c.gcov a.h.gcov
CHECK: File '/tmp/c/abs-path.c'
CHECK: File '/tmp/h/a.h'
# If there is no source file with a relative path, nothing is dumped.
RUN: llvm-cov gcov -r abs-path.gcda 2>&1 | count 0
RUN: llvm-cov gcov -r -s /t abs-path.gcda 2>&1 | count 0
RUN: not ls abs-path.c.gcov 2> /dev/null
# -s strips a prefix from filenames and can change filtering of -r.
RUN: llvm-cov gcov -r -s /tmp abs-path.gcda | FileCheck %s --check-prefix=STRIP1 --match-full-lines --strict-whitespace
RUN: FileCheck %s --check-prefix=STRIP1_C < abs-path.c.gcov
RUN: FileCheck %s --check-prefix=STRIP1_H < a.h.gcov
# Test full option names.
RUN: llvm-cov gcov --relative-only --source-prefix=/tmp abs-path.gcda | FileCheck %s --check-prefix=STRIP1 --match-full-lines --strict-whitespace
STRIP1:File 'c/abs-path.c'
STRIP1-NEXT:Lines executed:100.00% of 1
STRIP1-NEXT:Creating 'abs-path.c.gcov'
STRIP1-EMPTY:
STRIP1-NEXT:File 'h/a.h'
STRIP1-NEXT:Lines executed:0.00% of 1
STRIP1-NEXT:Creating 'a.h.gcov'
STRIP1_C: 0:Source:c/abs-path.c
STRIP1_H: 0:Source:h/a.h
RUN: llvm-cov gcov -r -s /tmp/h abs-path.gcda | FileCheck %s --check-prefix=STRIP2
STRIP2-NOT: File
STRIP2: File 'a.h'

View File

@ -131,6 +131,14 @@ int gcovMain(int argc, const char *argv[]) {
cl::desc("Preserve path components")); cl::desc("Preserve path components"));
cl::alias PreservePathsA("preserve-paths", cl::aliasopt(PreservePaths)); cl::alias PreservePathsA("preserve-paths", cl::aliasopt(PreservePaths));
cl::opt<bool> RelativeOnly(
"r", cl::Grouping,
cl::desc("Only dump files with relative paths or absolute paths with the "
"prefix specified by -s"));
cl::alias RelativeOnlyA("relative-only", cl::aliasopt(RelativeOnly));
cl::opt<std::string> SourcePrefix("s", cl::desc("Source prefix to elide"));
cl::alias SourcePrefixA("source-prefix", cl::aliasopt(SourcePrefix));
cl::opt<bool> UseStdout("t", cl::Grouping, cl::init(false), cl::opt<bool> UseStdout("t", cl::Grouping, cl::init(false),
cl::desc("Print to stdout")); cl::desc("Print to stdout"));
cl::alias UseStdoutA("stdout", cl::aliasopt(UseStdout)); cl::alias UseStdoutA("stdout", cl::aliasopt(UseStdout));
@ -157,7 +165,8 @@ int gcovMain(int argc, const char *argv[]) {
GCOV::Options Options(AllBlocks, BranchProb, BranchCount, FuncSummary, GCOV::Options Options(AllBlocks, BranchProb, BranchCount, FuncSummary,
PreservePaths, UncondBranch, Intermediate, LongNames, PreservePaths, UncondBranch, Intermediate, LongNames,
NoOutput, UseStdout, HashFilenames); NoOutput, RelativeOnly, UseStdout, HashFilenames,
SourcePrefix);
for (const auto &SourceFile : SourceFiles) for (const auto &SourceFile : SourceFiles)
reportCoverage(SourceFile, ObjectDir, InputGCNO, InputGCDA, DumpGCOV, reportCoverage(SourceFile, ObjectDir, InputGCNO, InputGCDA, DumpGCOV,