From 5042e1e56d39a02517abecbe00e72eea698d309a Mon Sep 17 00:00:00 2001 From: Tomas Camin Date: Wed, 23 Aug 2023 15:25:39 -0700 Subject: [PATCH] [llvm-cov] Allow multiple remaps in --path-equivalence Previously the --path-equivalence parameter would allow to specify a single remap pair (coverage data path - local source file path). This patch changes this allowing to pass as many remaps as needed. Reviewed By: keith Differential Revision: https://reviews.llvm.org/D154223 --- llvm/docs/CommandGuide/llvm-cov.rst | 6 +- .../multiple-path_equivalence.covmapping | Bin 0 -> 412 bytes .../Inputs/multiple-path_equivalence.proftext | 19 ++++++ .../llvm-cov/multiple-path_equivalence.test | 32 +++++++++ llvm/test/tools/llvm-cov/path_equivalence.c | 3 + llvm/tools/llvm-cov/CodeCoverage.cpp | 61 +++++++++++------- 6 files changed, 95 insertions(+), 26 deletions(-) create mode 100644 llvm/test/tools/llvm-cov/Inputs/multiple-path_equivalence.covmapping create mode 100644 llvm/test/tools/llvm-cov/Inputs/multiple-path_equivalence.proftext create mode 100644 llvm/test/tools/llvm-cov/multiple-path_equivalence.test diff --git a/llvm/docs/CommandGuide/llvm-cov.rst b/llvm/docs/CommandGuide/llvm-cov.rst index 44bb135371512a..792f9629dbfbd0 100644 --- a/llvm/docs/CommandGuide/llvm-cov.rst +++ b/llvm/docs/CommandGuide/llvm-cov.rst @@ -340,7 +340,11 @@ OPTIONS Map the paths in the coverage data to local source file paths. This allows you to generate the coverage data on one machine, and then use llvm-cov on a - different machine where you have the same files on a different path. + different machine where you have the same files on a different path. Multiple + `-path-equivalence` arguments can be passed to specify different mappings. Each + argument consists of a source path `` and its corresponding local path ``. + The mappings are applied in the order they are specified. If multiple mappings can + be applied to a single path, the first mapping encountered is used. .. option:: -coverage-watermark=, diff --git a/llvm/test/tools/llvm-cov/Inputs/multiple-path_equivalence.covmapping b/llvm/test/tools/llvm-cov/Inputs/multiple-path_equivalence.covmapping new file mode 100644 index 0000000000000000000000000000000000000000..3e229a8c301a75845283d105bb406d0825c453ce GIT binary patch literal 412 zcmd1FDa%dHFUu`SEiOq(EJ+l5alElXfQcc^5QvR{*cgaSSQv5>GxHdLfDwpAfS3o$ z-YeOhdpqf%3@4Be1B^oYCAkIqKx0#j64O)l(+u^Jf%+I38MzsFp^8A}hygJd5QEre z>E9NdESXS>VvY!^If?pdM(8G?n&1 | FileCheck %s + +// CHECK-DAG: {{/|\\}}tmp{{/|\\}}coverage{{/|\\}}main.c: +// CHECK-DAG: {{/|\\}}tmp{{/|\\}}coverage{{/|\\}}f1.c: +// CHECK-DAG: {{/|\\}}tmp{{/|\\}}coverage{{/|\\}}a{{/|\\}}f2.c: +// CHECK-DAG: {{/|\\}}tmp{{/|\\}}coverage{{/|\\}}b{{/|\\}}f3.c: +// CHECK-DAG: {{/|\\}}tmp{{/|\\}}coverage{{/|\\}}b{{/|\\}}c{{/|\\}}f4.c: +// CHECK-NOT: isn't covered. + +# Make sure remapping follows the specified order by proving paths in an overriding order (f4 comes after f3) +// RUN: llvm-cov show %S/Inputs/multiple-path_equivalence.covmapping -instr-profile=%t.profdata -path-equivalence=/tmp/coverage/a,%/T -path-equivalence=/tmp/coverage/b,%/T -path-equivalence=/tmp/coverage/b/c,%/T -path-equivalence=/tmp/coverage,%/T 2>&1 | FileCheck %s -check-prefix=OVERRIDING_ORDER + +// OVERRIDING_ORDER-DAG: {{/|\\}}tmp{{/|\\}}coverage{{/|\\}}main.c: +// OVERRIDING_ORDER-DAG: {{/|\\}}tmp{{/|\\}}coverage{{/|\\}}f1.c: +// OVERRIDING_ORDER-DAG: {{/|\\}}tmp{{/|\\}}coverage{{/|\\}}a{{/|\\}}f2.c: +// OVERRIDING_ORDER-DAG: {{/|\\}}tmp{{/|\\}}coverage{{/|\\}}b{{/|\\}}f3.c: +// OVERRIDING_ORDER-DAG: warning: The file '{{/|\\}}tmp{{/|\\}}coverage{{/|\\}}b{{/|\\}}c{{/|\\}}f4.c' isn't covered. + +// RUN: not llvm-cov show %S/Inputs/multiple-path_equivalence.covmapping -instr-profile=%t.profdata -path-equivalence=/tmp/coverage/a,%/T -path-equivalence=/tmp/coverage/b, -path-equivalence=/tmp/coverage/b/c,%/T -path-equivalence=/tmp/coverage,%/T 2>&1 | FileCheck %s -check-prefix=EMPTY_PATH +// EMPTY_PATH: must be in format 'from,to' \ No newline at end of file diff --git a/llvm/test/tools/llvm-cov/path_equivalence.c b/llvm/test/tools/llvm-cov/path_equivalence.c index 26a35b78d2d743..38422ce5600842 100644 --- a/llvm/test/tools/llvm-cov/path_equivalence.c +++ b/llvm/test/tools/llvm-cov/path_equivalence.c @@ -5,3 +5,6 @@ int main() {} // CHECK: [[@LINE]]| 1|int main() {} // RUN: not llvm-cov show --instr-profile=/dev/null -path-equivalence=foo /dev/null 2>&1 | FileCheck --check-prefix=INVALID %s // INVALID: error: -path-equivalence: invalid argument 'foo', must be in format 'from,to' + +// RUN: not llvm-cov show --instr-profile=/dev/null -path-equivalence=,foo /dev/null 2>&1 | FileCheck --check-prefix=EMPTY_PATH %s +// EMPTY_PATH: error: -path-equivalence: invalid argument ',foo', must be in format 'from,to' diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp index 02448dcd31a161..3992dfa8932c35 100644 --- a/llvm/tools/llvm-cov/CodeCoverage.cpp +++ b/llvm/tools/llvm-cov/CodeCoverage.cpp @@ -162,7 +162,8 @@ class CodeCoverageTool { /// The coverage data path to be remapped from, and the source path to be /// remapped to, when using -path-equivalence. - std::optional> PathRemapping; + std::optional>> + PathRemappings; /// File status cache used when finding the same file. StringMap> FileStatusCache; @@ -228,7 +229,7 @@ void CodeCoverageTool::collectPaths(const std::string &Path) { llvm::sys::fs::file_status Status; llvm::sys::fs::status(Path, Status); if (!llvm::sys::fs::exists(Status)) { - if (PathRemapping) + if (PathRemappings) addCollectedPath(Path); else warning("Source file doesn't exist, proceeded by ignoring it.", Path); @@ -474,7 +475,7 @@ std::unique_ptr CodeCoverageTool::load() { } void CodeCoverageTool::remapPathNames(const CoverageMapping &Coverage) { - if (!PathRemapping) + if (!PathRemappings) return; // Convert remapping paths to native paths with trailing seperators. @@ -488,17 +489,23 @@ void CodeCoverageTool::remapPathNames(const CoverageMapping &Coverage) { NativePath += sys::path::get_separator(); return NativePath.c_str(); }; - std::string RemapFrom = nativeWithTrailing(PathRemapping->first); - std::string RemapTo = nativeWithTrailing(PathRemapping->second); - // Create a mapping from coverage data file paths to local paths. - for (StringRef Filename : Coverage.getUniqueSourceFiles()) { - SmallString<128> NativeFilename; - sys::path::native(Filename, NativeFilename); - sys::path::remove_dots(NativeFilename, true); - if (NativeFilename.startswith(RemapFrom)) { - RemappedFilenames[Filename] = - RemapTo + NativeFilename.substr(RemapFrom.size()).str(); + for (std::pair &PathRemapping : *PathRemappings) { + std::string RemapFrom = nativeWithTrailing(PathRemapping.first); + std::string RemapTo = nativeWithTrailing(PathRemapping.second); + + // Create a mapping from coverage data file paths to local paths. + for (StringRef Filename : Coverage.getUniqueSourceFiles()) { + if (RemappedFilenames.count(Filename) == 1) + continue; + + SmallString<128> NativeFilename; + sys::path::native(Filename, NativeFilename); + sys::path::remove_dots(NativeFilename, true); + if (NativeFilename.startswith(RemapFrom)) { + RemappedFilenames[Filename] = + RemapTo + NativeFilename.substr(RemapFrom.size()).str(); + } } } @@ -674,7 +681,7 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { "lcov tracefile output")), cl::init(CoverageViewOptions::OutputFormat::Text)); - cl::opt PathRemap( + cl::list PathRemaps( "path-equivalence", cl::Optional, cl::desc(", Map coverage data paths to local source file " "paths")); @@ -812,19 +819,23 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { break; } - // If path-equivalence was given and is a comma seperated pair then set - // PathRemapping. - if (!PathRemap.empty()) { - auto EquivPair = StringRef(PathRemap).split(','); - if (EquivPair.first.empty() || EquivPair.second.empty()) { - error("invalid argument '" + PathRemap + - "', must be in format 'from,to'", - "-path-equivalence"); - return 1; + if (!PathRemaps.empty()) { + std::vector> Remappings; + + for (const std::string &PathRemap : PathRemaps) { + auto EquivPair = StringRef(PathRemap).split(','); + if (EquivPair.first.empty() || EquivPair.second.empty()) { + error("invalid argument '" + PathRemap + + "', must be in format 'from,to'", + "-path-equivalence"); + return 1; + } + + Remappings.push_back( + {std::string(EquivPair.first), std::string(EquivPair.second)}); } - PathRemapping = {std::string(EquivPair.first), - std::string(EquivPair.second)}; + PathRemappings = Remappings; } // If a demangler is supplied, check if it exists and register it.