diff --git a/llvm/test/tools/llvm-cov/sources-specified.test b/llvm/test/tools/llvm-cov/sources-specified.test --- a/llvm/test/tools/llvm-cov/sources-specified.test +++ b/llvm/test/tools/llvm-cov/sources-specified.test @@ -32,7 +32,6 @@ SHOW: {{.*}}sources_specified{{.*}} SHOW: {{.*}}sources_specified{{.*}} - # Test "export" command. Use a temp .json file as output is a single line. RUN: llvm-cov export -instr-profile %S/Inputs/sources_specified/main.profdata \ RUN: -path-equivalence=/tmp,%S/Inputs \ diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp --- a/llvm/tools/llvm-cov/CodeCoverage.cpp +++ b/llvm/tools/llvm-cov/CodeCoverage.cpp @@ -42,6 +42,7 @@ #include #include #include +#include using namespace llvm; using namespace coverage; @@ -80,6 +81,13 @@ /// directory, recursively collect all of the paths within the directory. void collectPaths(const std::string &Path); + /// Check if the two given two files are the same file. + bool isEquivalentFile(StringRef FilePath1, StringRef FilePath2); + + /// Retrieve a file status with a cache. + Optional + CodeCoverageTool::getFileStatus(StringRef FilePath); + /// Return a memory buffer for the given source file. ErrorOr getSourceFile(StringRef SourceFile); @@ -153,6 +161,10 @@ /// remapped to, when using -path-equivalence. Optional> PathRemapping; + // File status cache used when finding the same file. + std::unordered_map> + FileStatusCache; + /// The architecture the coverage mapping data targets. std::vector CoverageArches; @@ -239,6 +251,29 @@ } } +Optional +CodeCoverageTool::getFileStatus(StringRef FilePath) { + auto It = FileStatusCache.find(FilePath.str()); + if (It != FileStatusCache.end()) + return It->second; + + Optional result; + sys::fs::file_status status; + if (!sys::fs::status(FilePath, status)) + result = status; + + FileStatusCache.emplace(std::string(FilePath), result); + return result; +} + +bool CodeCoverageTool::isEquivalentFile(StringRef FilePath1, + StringRef FilePath2) { + auto file_status1 = getFileStatus(FilePath1); + auto file_status2 = getFileStatus(FilePath1); + return file_status1.hasValue() && file_status2.hasValue() && + sys::fs::equivalent(file_status1.getValue(), file_status2.getValue()); +} + ErrorOr CodeCoverageTool::getSourceFile(StringRef SourceFile) { // If we've remapped filenames, look up the real location for this file. @@ -248,9 +283,11 @@ if (Loc != RemappedFilenames.end()) SourceFile = Loc->second; } + for (const auto &Files : LoadedSourceFiles) - if (sys::fs::equivalent(SourceFile, Files.first)) + if (isEquivalentFile(SourceFile, Files.first)) return *Files.second; + auto Buffer = MemoryBuffer::getFile(SourceFile); if (auto EC = Buffer.getError()) { error(EC.message(), SourceFile);