diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -207,7 +207,11 @@ std::string RecordCommandLine; llvm::SmallVector, 0> DebugPrefixMap; - std::map CoveragePrefixMap; + + /// Prefix replacement map for source-based code coverage. + /// It should be traversed in reverse order because prefix replacements are + /// applied in reverse order when multiple options are provided. + llvm::SmallVector, 0> CoveragePrefixMap; /// The ABI to use for passing floating point arguments. std::string FloatABI; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3223,7 +3223,8 @@ def fcoverage_prefix_map_EQ : Joined<["-"], "fcoverage-prefix-map=">, Group, Flags<[CC1Option]>, - HelpText<"remap file source paths in coverage mapping">; + MetaVarName<"=">, + HelpText<"remap file source paths to in coverage mapping. If there are multiple options, prefix replacement is applied in reverse order starting from the last one">; def ffile_prefix_map_EQ : Joined<["-"], "ffile-prefix-map=">, Group, HelpText<"remap file source paths in debug info, predefined preprocessor " diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1648,8 +1648,13 @@ std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) { llvm::SmallString<256> Path(Filename); llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true); - for (const auto &Entry : CGM.getCodeGenOpts().CoveragePrefixMap) { - if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second)) + + /// Traverse coverage prefix map in reverse order because prefix replacements + /// are applied in reverse order starting from the last one when multiple + /// prefix replacement options are provided. + for (const auto &[From, To] : + llvm::reverse(CGM.getCodeGenOpts().CoveragePrefixMap)) { + if (llvm::sys::path::replace_path_prefix(Path, From, To)) break; } return Path.str().str(); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1701,8 +1701,7 @@ for (const auto &Arg : Args.getAllArgValues(OPT_fcoverage_prefix_map_EQ)) { auto Split = StringRef(Arg).split('='); - Opts.CoveragePrefixMap.insert( - {std::string(Split.first), std::string(Split.second)}); + Opts.CoveragePrefixMap.emplace_back(Split.first, Split.second); } const llvm::Triple::ArchType DebugEntryValueArchs[] = { diff --git a/clang/test/Profile/coverage-prefix-map.c b/clang/test/Profile/coverage-prefix-map.c --- a/clang/test/Profile/coverage-prefix-map.c +++ b/clang/test/Profile/coverage-prefix-map.c @@ -19,3 +19,13 @@ // RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name coverage-prefix-map.c %t/root/nested/coverage-prefix-map.c -fcoverage-compilation-dir=/custom -fcoverage-prefix-map=/custom=/nonsense -o - | FileCheck --check-prefix=COVERAGE-COMPILATION-DIR %s // COVERAGE-COMPILATION-DIR: @__llvm_coverage_mapping = {{.*"\\02.*}}nonsense + +// Test that last -fcoverage-prefix-map option (-fcoverage-prefix-map==newpath) is applied. +// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name coverage-prefix-map.c %t/root/nested/coverage-prefix-map.c -fcoverage-prefix-map=%/t/root=. -fcoverage-prefix-map==newpath -o - | FileCheck --check-prefix=COVERAGE-PREFIX-MAP-ORDER %s +// COVERAGE-PREFIX-MAP-ORDER: @__llvm_coverage_mapping = {{.*"\\02.*newpath.*root.*nested.*coverage-prefix-map\.c}} + +// Test that last -fcoverage-prefix-map option (-fcoverage-prefix-map=%/t/root=.) is applied. +// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name coverage-prefix-map.c %t/root/nested/coverage-prefix-map.c -fcoverage-prefix-map==newpath -fcoverage-prefix-map=%/t/root=. -o - | FileCheck --check-prefix=COVERAGE-PREFIX-MAP-REORDER %s +// COVERAGE-PREFIX-MAP-REORDER: @__llvm_coverage_mapping = +// COVERAGE-PREFIX-MAP-REORDER-NOT: newpath +// COVERAGE-PREFIX-MAP-REORDER-SAME: nested{{.*coverage-prefix-map\.c}}