diff options
Diffstat (limited to 'llvm/tools/llvm-cov/CodeCoverage.cpp')
| -rw-r--r-- | llvm/tools/llvm-cov/CodeCoverage.cpp | 121 |
1 files changed, 77 insertions, 44 deletions
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp index 8afae2294eb..e5878df6c15 100644 --- a/llvm/tools/llvm-cov/CodeCoverage.cpp +++ b/llvm/tools/llvm-cov/CodeCoverage.cpp @@ -94,6 +94,10 @@ private: /// \brief Load the coverage mapping data. Return nullptr if an error occurred. std::unique_ptr<CoverageMapping> load(); + /// \brief Create a mapping from files in the Coverage data to local copies + /// (path-equivalence). + void remapPathNames(const CoverageMapping &Coverage); + /// \brief Remove input source files which aren't mapped by \p Coverage. void removeUnmappedInputs(const CoverageMapping &Coverage); @@ -125,13 +129,14 @@ private: /// A list of input source files. std::vector<std::string> SourceFiles; - /// Whether or not we're in -filename-equivalence mode. - bool CompareFilenamesOnly; - - /// In -filename-equivalence mode, this maps absolute paths from the - /// coverage mapping data to input source files. + /// In -path-equivalence mode, this maps the absolute paths from the coverage + /// mapping data to the input source files. StringMap<std::string> RemappedFilenames; + /// The coverage data path to be remapped from, and the source path to be + /// remapped to, when using -path-equivalence. + Optional<std::pair<std::string, std::string>> PathRemapping; + /// The architecture the coverage mapping data targets. std::vector<StringRef> CoverageArches; @@ -171,24 +176,20 @@ void CodeCoverageTool::warning(const Twine &Message, StringRef Whence) { } void CodeCoverageTool::addCollectedPath(const std::string &Path) { - if (CompareFilenamesOnly) { - SourceFiles.emplace_back(Path); - } else { - SmallString<128> EffectivePath(Path); - if (std::error_code EC = sys::fs::make_absolute(EffectivePath)) { - error(EC.message(), Path); - return; - } - sys::path::remove_dots(EffectivePath, /*remove_dot_dots=*/true); - SourceFiles.emplace_back(EffectivePath.str()); + SmallString<128> EffectivePath(Path); + if (std::error_code EC = sys::fs::make_absolute(EffectivePath)) { + error(EC.message(), Path); + return; } + sys::path::remove_dots(EffectivePath, /*remove_dot_dots=*/true); + SourceFiles.emplace_back(EffectivePath.str()); } 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 (CompareFilenamesOnly) + if (PathRemapping) addCollectedPath(Path); else error("Missing source file", Path); @@ -348,6 +349,8 @@ std::unique_ptr<CoverageMapping> CodeCoverageTool::load() { if (Mismatched) warning(utostr(Mismatched) + " functions have mismatched data"); + remapPathNames(*Coverage); + if (!SourceFiles.empty()) removeUnmappedInputs(*Coverage); @@ -356,33 +359,58 @@ std::unique_ptr<CoverageMapping> CodeCoverageTool::load() { return Coverage; } +void CodeCoverageTool::remapPathNames(const CoverageMapping &Coverage) { + if (!PathRemapping) + return; + + // Convert remapping paths to native paths with trailing seperators. + auto nativeWithTrailing = [](StringRef Path) -> std::string { + if (Path.empty()) + return ""; + SmallString<128> NativePath; + sys::path::native(Path, NativePath); + if (!sys::path::is_separator(NativePath.back())) + 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); + if (NativeFilename.startswith(RemapFrom)) { + RemappedFilenames[Filename] = + RemapTo + NativeFilename.substr(RemapFrom.size()).str(); + } + } + + // Convert input files from local paths to coverage data file paths. + StringMap<std::string> InvRemappedFilenames; + for (const auto &RemappedFilename : RemappedFilenames) + InvRemappedFilenames[RemappedFilename.getValue()] = RemappedFilename.getKey(); + + for (std::string &Filename : SourceFiles) { + SmallString<128> NativeFilename; + sys::path::native(Filename, NativeFilename); + auto CovFileName = InvRemappedFilenames.find(NativeFilename); + if (CovFileName != InvRemappedFilenames.end()) + Filename = CovFileName->second; + } +} + void CodeCoverageTool::removeUnmappedInputs(const CoverageMapping &Coverage) { std::vector<StringRef> CoveredFiles = Coverage.getUniqueSourceFiles(); auto UncoveredFilesIt = SourceFiles.end(); - if (!CompareFilenamesOnly) { - // The user may have specified source files which aren't in the coverage - // mapping. Filter these files away. - UncoveredFilesIt = std::remove_if( - SourceFiles.begin(), SourceFiles.end(), [&](const std::string &SF) { - return !std::binary_search(CoveredFiles.begin(), CoveredFiles.end(), - SF); - }); - } else { - for (auto &SF : SourceFiles) { - StringRef SFBase = sys::path::filename(SF); - for (const auto &CF : CoveredFiles) { - if (SFBase == sys::path::filename(CF)) { - RemappedFilenames[CF] = SF; - SF = CF; - break; - } - } - } - UncoveredFilesIt = std::remove_if( - SourceFiles.begin(), SourceFiles.end(), - [&](const std::string &SF) { return !RemappedFilenames.count(SF); }); - } + // The user may have specified source files which aren't in the coverage + // mapping. Filter these files away. + UncoveredFilesIt = std::remove_if( + SourceFiles.begin(), SourceFiles.end(), [&](const std::string &SF) { + return !std::binary_search(CoveredFiles.begin(), CoveredFiles.end(), + SF); + }); SourceFiles.erase(UncoveredFilesIt, SourceFiles.end()); } @@ -521,10 +549,10 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { "HTML output")), cl::init(CoverageViewOptions::OutputFormat::Text)); - cl::opt<bool> FilenameEquivalence( - "filename-equivalence", cl::Optional, - cl::desc("Treat source files as equivalent to paths in the coverage data " - "when the file names match, even if the full paths do not")); + cl::opt<std::string> PathRemap( + "path-equivalence", cl::Optional, + cl::desc("<from>,<to> Map coverage data paths to local source file " + "paths")); cl::OptionCategory FilteringCategory("Function filtering options"); @@ -573,7 +601,6 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { auto commandLineParser = [&, this](int argc, const char **argv) -> int { cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); ViewOpts.Debug = DebugDump; - CompareFilenamesOnly = FilenameEquivalence; if (!CovFilename.empty()) ObjectFilenames.emplace_back(CovFilename); @@ -598,6 +625,12 @@ 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. + auto EquivPair = StringRef(PathRemap).split(','); + if (!(EquivPair.first.empty() && EquivPair.second.empty())) + PathRemapping = EquivPair; + // If a demangler is supplied, check if it exists and register it. if (DemanglerOpts.size()) { auto DemanglerPathOrErr = sys::findProgramByName(DemanglerOpts[0]); |

