[llvm-cov] Strip redundant path components from filenames (fix PR31982)
Instead of stripping the longest common prefix off of the filenames in a
report, strip out the longest chain of redundant path components. This
fixes the case in PR31982, where there are two files with the same
prefix, and stripping out the LCP makes things less intelligible.
llvm-svn: 296029
diff --git a/llvm/test/tools/llvm-cov/Inputs/multiple-files2.covmapping b/llvm/test/tools/llvm-cov/Inputs/multiple-files2.covmapping
new file mode 100644
index 0000000..770817a
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/multiple-files2.covmapping
Binary files differ
diff --git a/llvm/test/tools/llvm-cov/multiple-files.test b/llvm/test/tools/llvm-cov/multiple-files.test
index 0b3fb85..d0dbdd8 100644
--- a/llvm/test/tools/llvm-cov/multiple-files.test
+++ b/llvm/test/tools/llvm-cov/multiple-files.test
@@ -1,9 +1,15 @@
// RUN: llvm-profdata merge %S/Inputs/multiple-files.proftext -o %t.profdata
-// RUN: llvm-cov report %S/Inputs/multiple-files.covmapping -instr-profile %t.profdata | FileCheck %s
+// RUN: llvm-cov report %S/Inputs/multiple-files.covmapping -instr-profile %t.profdata | FileCheck %s -check-prefix=MANY_COMPONENTS
+// RUN: llvm-cov report %S/Inputs/multiple-files2.covmapping -instr-profile %t.profdata | FileCheck %s -check-prefix=ONE_COMPONENT
-// CHECK: Filename
-// CHECK-NEXT: ---
-// CHECK-NEXT: {{^}}a{{[/\\]}}f2.c
-// CHECK-NEXT: {{^}}b{{[/\\]}}c{{[/\\]}}f4.c
-// CHECK-NEXT: {{^}}b{{[/\\]}}f3.c
-// CHECK-NEXT: {{^}}f1.c
+// MANY_COMPONENTS: Filename
+// MANY_COMPONENTS-NEXT: ---
+// MANY_COMPONENTS-NEXT: {{^}}a{{[/\\]}}f2.c
+// MANY_COMPONENTS-NEXT: {{^}}b{{[/\\]}}c{{[/\\]}}f4.c
+// MANY_COMPONENTS-NEXT: {{^}}b{{[/\\]}}f3.c
+// MANY_COMPONENTS-NEXT: {{^}}f1.c
+
+// ONE_COMPONENT: Filename
+// ONE_COMPONENT-NEXT: ---
+// ONE_COMPONENT-NEXT: {{^}}cov.c
+// ONE_COMPONENT-NEXT: {{^}}cov.h
diff --git a/llvm/tools/llvm-cov/CoverageReport.cpp b/llvm/tools/llvm-cov/CoverageReport.cpp
index 78333d0..6ae64ba 100644
--- a/llvm/tools/llvm-cov/CoverageReport.cpp
+++ b/llvm/tools/llvm-cov/CoverageReport.cpp
@@ -118,19 +118,51 @@
: raw_ostream::RED;
}
-/// \brief Determine the length of the longest common prefix of the strings in
-/// \p Strings.
-unsigned getLongestCommonPrefixLen(ArrayRef<std::string> Strings) {
- unsigned LCP = Strings[0].size();
- for (unsigned I = 1, E = Strings.size(); LCP > 0 && I < E; ++I) {
- unsigned Cursor;
- StringRef S = Strings[I];
- for (Cursor = 0; Cursor < LCP && Cursor < S.size(); ++Cursor)
- if (Strings[0][Cursor] != S[Cursor])
+/// \brief Get the number of redundant path components in each path in \p Paths.
+unsigned getNumRedundantPathComponents(ArrayRef<std::string> Paths) {
+ // To start, set the number of redundant path components to the maximum
+ // possible value.
+ SmallVector<StringRef, 8> FirstPathComponents{sys::path::begin(Paths[0]),
+ sys::path::end(Paths[0])};
+ unsigned NumRedundant = FirstPathComponents.size();
+
+ for (unsigned I = 1, E = Paths.size(); NumRedundant > 0 && I < E; ++I) {
+ StringRef Path = Paths[I];
+ for (const auto &Component :
+ enumerate(make_range(sys::path::begin(Path), sys::path::end(Path)))) {
+ // Do not increase the number of redundant components: that would remove
+ // useful parts of already-visited paths.
+ if (Component.Index >= NumRedundant)
break;
- LCP = std::min(LCP, Cursor);
+
+ // Lower the number of redundant components when there's a mismatch
+ // between the first path, and the path under consideration.
+ if (FirstPathComponents[Component.Index] != Component.Value) {
+ NumRedundant = Component.Index;
+ break;
+ }
+ }
}
- return LCP;
+
+ return NumRedundant;
+}
+
+/// \brief Determine the length of the longest redundant prefix of the paths in
+/// \p Paths.
+unsigned getRedundantPrefixLen(ArrayRef<std::string> Paths) {
+ // If there's at most one path, no path components are redundant.
+ if (Paths.size() <= 1)
+ return 0;
+
+ unsigned PrefixLen = 0;
+ unsigned NumRedundant = getNumRedundantPathComponents(Paths);
+ auto Component = sys::path::begin(Paths[0]);
+ for (unsigned I = 0; I < NumRedundant; ++I) {
+ auto LastComponent = Component;
+ ++Component;
+ PrefixLen += Component - LastComponent;
+ }
+ return PrefixLen;
}
} // end anonymous namespace
@@ -280,9 +312,7 @@
FileCoverageSummary &Totals,
ArrayRef<std::string> Files) {
std::vector<FileCoverageSummary> FileReports;
- unsigned LCP = 0;
- if (Files.size() > 1)
- LCP = getLongestCommonPrefixLen(Files);
+ unsigned LCP = getRedundantPrefixLen(Files);
for (StringRef Filename : Files) {
FileCoverageSummary Summary(Filename.drop_front(LCP));