Skip to content

Commit 6052a8a

Browse files
committed
[clang] In DependencyCollector on Windows, ignore case and separators when discarding duplicate dependency file paths.
This patch removes duplicates also encountered in the output of clang-scan-deps when one same header file is encountered with different casing and/or different separators ('/' vs '\'). The case of separators can appear when the same file is included externally by `#include <folder/file.h>` whereas a file from the same folder does `#include "file.h"` Under Windows, clang computes the paths using '/' from the include directive, the `\` from the -I options, and the concatenations use the native `\`, leading to internal paths containing a mix of both separators. Differential Revision: https://reviews.llvm.org/D102339
1 parent 472f856 commit 6052a8a

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

clang/lib/Frontend/DependencyFile.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,18 @@ void DependencyCollector::maybeAddDependency(StringRef Filename,
141141
}
142142

143143
bool DependencyCollector::addDependency(StringRef Filename) {
144-
if (Seen.insert(Filename).second) {
144+
StringRef SearchPath;
145+
#ifdef _WIN32
146+
// Make the search insensitive to case and separators.
147+
llvm::SmallString<256> TmpPath = Filename;
148+
llvm::sys::path::native(TmpPath);
149+
std::transform(TmpPath.begin(), TmpPath.end(), TmpPath.begin(), ::tolower);
150+
SearchPath = TmpPath.str();
151+
#else
152+
SearchPath = Filename;
153+
#endif
154+
155+
if (Seen.insert(SearchPath).second) {
145156
Dependencies.push_back(std::string(Filename));
146157
return true;
147158
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// REQUIRES: system-windows
2+
3+
// RUN: rm -rf %t.dir
4+
// RUN: mkdir -p %t.dir/subdir
5+
// RUN: echo > %t.dir/subdir/x.h
6+
// RUN: cp %s %t.dir/test.c
7+
// RUN: cd %t.dir
8+
9+
// RUN: %clang -MD -MF - %t.dir/test.c -fsyntax-only -I %t.dir/subdir | FileCheck %s
10+
// CHECK: test.o:
11+
// CHECK-NEXT: \test.c
12+
// CHECK-NEXT: \SubDir\X.h
13+
// File x.h must appear only once (case insensitive check).
14+
// CHECK-NOT: {{\\|/}}{{x|X}}.{{h|H}}
15+
16+
// Include x.h several times, with different casing and separators.
17+
// Since all paths are passed to clang as absolute, all dependencies are absolute paths.
18+
// We expect the output dependencies to contain only one line for file x.h
19+
20+
// Test case sensitivity.
21+
#include "SubDir/X.h"
22+
#include "subdir/x.h"
23+
24+
// Test separator sensitivity:
25+
// clang internally concatenates x.h using the Windows native separator.
26+
#include <x.h>
27+

0 commit comments

Comments
 (0)