[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.
struct Options {
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),
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 BranchInfo;
@ -62,8 +63,10 @@ struct Options {
bool Intermediate;
bool LongFileNames;
bool NoOutput;
bool RelativeOnly;
bool UseStdout;
bool HashFilenames;
std::string SourcePrefix;
};
} // end namespace GCOV
@ -341,9 +344,11 @@ struct GCOVCoverage {
struct SourceInfo {
StringRef filename;
SmallString<0> displayName;
std::string name;
std::vector<GCOVFunction *> functions;
GCOVCoverage coverage;
bool ignored = false;
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.
void GCOVFile::collectLineCounts(FileInfo &fi) {
assert(fi.sources.empty());
for (StringRef filename : filenames)
for (StringRef filename : filenames) {
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) {
f.collectLineCounts(fi);
fi.sources[f.srcIdx].functions.push_back(&f);
@ -664,6 +680,10 @@ void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename,
llvm::sort(Filenames);
for (StringRef Filename : Filenames) {
SourceInfo &source = sources[file.filenameToIdx.find(Filename)->second];
if (source.ignored)
continue;
auto AllLines =
Options.Intermediate ? LineConsumer() : LineConsumer(Filename);
std::string CoveragePath = getCoveragePath(Filename, MainFilename);
@ -675,7 +695,7 @@ void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename,
raw_ostream &CovOS =
!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:Data:" << GCDAFile << "\n";
CovOS << " -: 0:Runs:" << RunCount << "\n";
@ -683,7 +703,7 @@ void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename,
CovOS << " -: 0:Programs:" << ProgramCount << "\n";
const LineData &Line = LineInfo[Filename];
GCOVCoverage FileCoverage(Filename);
GCOVCoverage FileCoverage(source.displayName);
for (uint32_t LineIndex = 0; LineIndex < Line.LastLine || !AllLines.empty();
++LineIndex) {
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.coverage = FileCoverage;
}
@ -928,6 +947,8 @@ void FileInfo::printFuncCoverage(raw_ostream &OS) const {
// printFileCoverage - Print per-file coverage info.
void FileInfo::printFileCoverage(raw_ostream &OS) const {
for (const SourceInfo &source : sources) {
if (source.ignored)
continue;
const GCOVCoverage &Coverage = source.coverage;
OS << "File '" << Coverage.Name << "'\n";
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::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::desc("Print to stdout"));
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,
PreservePaths, UncondBranch, Intermediate, LongNames,
NoOutput, UseStdout, HashFilenames);
NoOutput, RelativeOnly, UseStdout, HashFilenames,
SourcePrefix);
for (const auto &SourceFile : SourceFiles)
reportCoverage(SourceFile, ObjectDir, InputGCNO, InputGCDA, DumpGCOV,