aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-cov/CodeCoverage.cpp
diff options
context:
space:
mode:
authorFabian Meumertzheim <fabian@meumertzhe.im>2025-06-13 17:49:30 +0200
committerGitHub <noreply@github.com>2025-06-13 08:49:30 -0700
commitdc9e300f12f3b9c8160dbfb0bc32252ad99c3ba7 (patch)
tree572d6e6735fe5cc098b449b9674cfaf5a0439852 /llvm/tools/llvm-cov/CodeCoverage.cpp
parentca5040990ed17fa444d30c22fffcfa7ddc72612f (diff)
downloadllvm-dc9e300f12f3b9c8160dbfb0bc32252ad99c3ba7.zip
llvm-dc9e300f12f3b9c8160dbfb0bc32252ad99c3ba7.tar.gz
llvm-dc9e300f12f3b9c8160dbfb0bc32252ad99c3ba7.tar.bz2
[llvm-cov] Add support for baseline coverage (#117910)
When no profile is provided, but the new --empty-profile option is specifed, the export/report/show commands now emit coverage data equivalent to that obtained from a profile with all zero counters ("baseline coverage"). This is useful for build systems (e.g. Bazel) that can track coverage information for each build target, even those that are never linked into tests and thus don't have runtime coverage data recorded. By merging in baseline coverage, lines in files that aren't linked into tests are correctly reported as uncovered.
Diffstat (limited to 'llvm/tools/llvm-cov/CodeCoverage.cpp')
-rw-r--r--llvm/tools/llvm-cov/CodeCoverage.cpp78
1 files changed, 50 insertions, 28 deletions
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index 1f2484c..6c66858 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -153,7 +153,7 @@ private:
bool HadSourceFiles = false;
/// The path to the indexed profile.
- std::string PGOFilename;
+ std::optional<std::string> PGOFilename;
/// A list of input source files.
std::vector<std::string> SourceFiles;
@@ -455,10 +455,12 @@ static bool modifiedTimeGT(StringRef LHS, StringRef RHS) {
}
std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
- for (StringRef ObjectFilename : ObjectFilenames)
- if (modifiedTimeGT(ObjectFilename, PGOFilename))
- warning("profile data may be out of date - object is newer",
- ObjectFilename);
+ if (PGOFilename) {
+ for (StringRef ObjectFilename : ObjectFilenames)
+ if (modifiedTimeGT(ObjectFilename, PGOFilename.value()))
+ warning("profile data may be out of date - object is newer",
+ ObjectFilename);
+ }
auto FS = vfs::getRealFileSystem();
auto CoverageOrErr = CoverageMapping::load(
ObjectFilenames, PGOFilename, *FS, CoverageArches,
@@ -668,11 +670,16 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
"dump-collected-paths", cl::Optional, cl::Hidden,
cl::desc("Show the collected paths to source files"));
- cl::opt<std::string, true> PGOFilename(
- "instr-profile", cl::Required, cl::location(this->PGOFilename),
+ cl::opt<std::string> PGOFilename(
+ "instr-profile", cl::Optional,
cl::desc(
"File with the profile data obtained after an instrumented run"));
+ cl::opt<bool> EmptyProfile(
+ "empty-profile", cl::Optional,
+ cl::desc("Use a synthetic profile with no data to generate "
+ "baseline coverage"));
+
cl::list<std::string> Arches(
"arch", cl::desc("architectures of the coverage mapping binaries"));
@@ -805,6 +812,15 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
}
this->CheckBinaryIDs = CheckBinaryIDs;
+ if (!PGOFilename.empty() == EmptyProfile) {
+ error(
+ "exactly one of -instr-profile and -empty-profile must be specified");
+ return 1;
+ }
+ if (!PGOFilename.empty()) {
+ this->PGOFilename = std::make_optional(PGOFilename.getValue());
+ }
+
if (!CovFilename.empty())
ObjectFilenames.emplace_back(CovFilename);
for (const std::string &Filename : CovFilenames)
@@ -1116,20 +1132,22 @@ int CodeCoverageTool::doShow(int argc, const char **argv,
}
}
- sys::fs::file_status Status;
- if (std::error_code EC = sys::fs::status(PGOFilename, Status)) {
- error("could not read profile data!" + EC.message(), PGOFilename);
- return 1;
- }
+ if (PGOFilename) {
+ sys::fs::file_status Status;
+ if (std::error_code EC = sys::fs::status(PGOFilename.value(), Status)) {
+ error("could not read profile data!" + EC.message(), PGOFilename.value());
+ return 1;
+ }
- if (ShowCreatedTime) {
- auto ModifiedTime = Status.getLastModificationTime();
- std::string ModifiedTimeStr = to_string(ModifiedTime);
- size_t found = ModifiedTimeStr.rfind(':');
- ViewOpts.CreatedTimeStr =
- (found != std::string::npos)
- ? "Created: " + ModifiedTimeStr.substr(0, found)
- : "Created: " + ModifiedTimeStr;
+ if (ShowCreatedTime) {
+ auto ModifiedTime = Status.getLastModificationTime();
+ std::string ModifiedTimeStr = to_string(ModifiedTime);
+ size_t found = ModifiedTimeStr.rfind(':');
+ ViewOpts.CreatedTimeStr =
+ (found != std::string::npos)
+ ? "Created: " + ModifiedTimeStr.substr(0, found)
+ : "Created: " + ModifiedTimeStr;
+ }
}
auto Coverage = load();
@@ -1238,10 +1256,12 @@ int CodeCoverageTool::doReport(int argc, const char **argv,
return 1;
}
- sys::fs::file_status Status;
- if (std::error_code EC = sys::fs::status(PGOFilename, Status)) {
- error("could not read profile data!" + EC.message(), PGOFilename);
- return 1;
+ if (PGOFilename) {
+ sys::fs::file_status Status;
+ if (std::error_code EC = sys::fs::status(PGOFilename.value(), Status)) {
+ error("could not read profile data!" + EC.message(), PGOFilename.value());
+ return 1;
+ }
}
auto Coverage = load();
@@ -1303,10 +1323,12 @@ int CodeCoverageTool::doExport(int argc, const char **argv,
return 1;
}
- sys::fs::file_status Status;
- if (std::error_code EC = sys::fs::status(PGOFilename, Status)) {
- error("could not read profile data!" + EC.message(), PGOFilename);
- return 1;
+ if (PGOFilename) {
+ sys::fs::file_status Status;
+ if (std::error_code EC = sys::fs::status(PGOFilename.value(), Status)) {
+ error("could not read profile data!" + EC.message(), PGOFilename.value());
+ return 1;
+ }
}
auto Coverage = load();