aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Driver/Options.td5
-rw-r--r--clang/include/clang/Driver/ToolChain.h6
-rw-r--r--clang/lib/Driver/Job.cpp17
-rw-r--r--clang/lib/Driver/ToolChain.cpp40
-rw-r--r--clang/lib/Driver/ToolChains/Darwin.cpp21
-rw-r--r--clang/lib/Driver/ToolChains/Darwin.h4
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp4
-rw-r--r--clang/lib/Lex/InitHeaderSearch.cpp19
-rw-r--r--clang/test/Driver/Inputs/DriverKit19.0.sdk/System/DriverKit/System/Library/SubFrameworks/.keep0
-rw-r--r--clang/test/Driver/Inputs/MacOSX15.1.sdk/Library/Frameworks/.keep0
-rw-r--r--clang/test/Driver/Inputs/MacOSX15.1.sdk/System/Library/Frameworks/.keep0
-rw-r--r--clang/test/Driver/Inputs/MacOSX15.1.sdk/System/Library/SubFrameworks/.keep0
-rw-r--r--clang/test/Driver/darwin-framework-search-paths.c23
-rw-r--r--clang/test/Driver/darwin-subframeworks.c18
-rw-r--r--clang/test/Driver/driverkit-path.c16
-rw-r--r--clang/test/Preprocessor/cuda-macos-includes.cu13
-rw-r--r--clang/unittests/Frontend/CMakeLists.txt1
-rw-r--r--clang/unittests/Frontend/SearchPathTest.cpp157
18 files changed, 270 insertions, 74 deletions
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index a3bbf4c..24f0bd8a 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -8452,6 +8452,11 @@ def objc_isystem : Separate<["-"], "objc-isystem">,
def objcxx_isystem : Separate<["-"], "objcxx-isystem">,
MetaVarName<"<directory>">,
HelpText<"Add directory to the ObjC++ SYSTEM include search path">;
+def internal_iframework : Separate<["-"], "internal-iframework">,
+ MetaVarName<"<directory>">,
+ HelpText<"Add directory to the internal system framework search path; these "
+ "are assumed to not be user-provided and are used to model system "
+ "and standard frameworks' paths.">;
def internal_isystem : Separate<["-"], "internal-isystem">,
MetaVarName<"<directory>">,
HelpText<"Add directory to the internal system include search path; these "
diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h
index d005967..58edf2b 100644
--- a/clang/include/clang/Driver/ToolChain.h
+++ b/clang/include/clang/Driver/ToolChain.h
@@ -226,6 +226,9 @@ protected:
/// \name Utilities for implementing subclasses.
///@{
+ static void addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ const Twine &Path);
static void addSystemInclude(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
const Twine &Path);
@@ -236,6 +239,9 @@ protected:
addExternCSystemIncludeIfExists(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
const Twine &Path);
+ static void addSystemFrameworkIncludes(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ ArrayRef<StringRef> Paths);
static void addSystemIncludes(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
ArrayRef<StringRef> Paths);
diff --git a/clang/lib/Driver/Job.cpp b/clang/lib/Driver/Job.cpp
index 4619b8c..f676b12 100644
--- a/clang/lib/Driver/Job.cpp
+++ b/clang/lib/Driver/Job.cpp
@@ -67,14 +67,15 @@ static bool skipArgs(const char *Flag, bool HaveCrashVFS, int &SkipNum,
return true;
// Some include flags shouldn't be skipped if we have a crash VFS
- IsInclude = llvm::StringSwitch<bool>(Flag)
- .Cases("-include", "-header-include-file", true)
- .Cases("-idirafter", "-internal-isystem", "-iwithprefix", true)
- .Cases("-internal-externc-isystem", "-iprefix", true)
- .Cases("-iwithprefixbefore", "-isystem", "-iquote", true)
- .Cases("-isysroot", "-I", "-F", "-resource-dir", true)
- .Cases("-iframework", "-include-pch", true)
- .Default(false);
+ IsInclude =
+ llvm::StringSwitch<bool>(Flag)
+ .Cases("-include", "-header-include-file", true)
+ .Cases("-idirafter", "-internal-isystem", "-iwithprefix", true)
+ .Cases("-internal-externc-isystem", "-iprefix", true)
+ .Cases("-iwithprefixbefore", "-isystem", "-iquote", true)
+ .Cases("-isysroot", "-I", "-F", "-resource-dir", true)
+ .Cases("-internal-iframework", "-iframework", "-include-pch", true)
+ .Default(false);
if (IsInclude)
return !HaveCrashVFS;
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 5cd5755..3c52abb 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -1366,10 +1366,17 @@ ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{
return *cxxStdlibType;
}
+/// Utility function to add a system framework directory to CC1 arguments.
+void ToolChain::addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ const Twine &Path) {
+ CC1Args.push_back("-internal-iframework");
+ CC1Args.push_back(DriverArgs.MakeArgString(Path));
+}
+
/// Utility function to add a system include directory to CC1 arguments.
-/*static*/ void ToolChain::addSystemInclude(const ArgList &DriverArgs,
- ArgStringList &CC1Args,
- const Twine &Path) {
+void ToolChain::addSystemInclude(const ArgList &DriverArgs,
+ ArgStringList &CC1Args, const Twine &Path) {
CC1Args.push_back("-internal-isystem");
CC1Args.push_back(DriverArgs.MakeArgString(Path));
}
@@ -1382,9 +1389,9 @@ ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{
/// "C" semantics. These semantics are *ignored* by and large today, but its
/// important to preserve the preprocessor changes resulting from the
/// classification.
-/*static*/ void ToolChain::addExternCSystemInclude(const ArgList &DriverArgs,
- ArgStringList &CC1Args,
- const Twine &Path) {
+void ToolChain::addExternCSystemInclude(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ const Twine &Path) {
CC1Args.push_back("-internal-externc-isystem");
CC1Args.push_back(DriverArgs.MakeArgString(Path));
}
@@ -1396,19 +1403,28 @@ void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs,
addExternCSystemInclude(DriverArgs, CC1Args, Path);
}
+/// Utility function to add a list of system framework directories to CC1.
+void ToolChain::addSystemFrameworkIncludes(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ ArrayRef<StringRef> Paths) {
+ for (const auto &Path : Paths) {
+ CC1Args.push_back("-internal-iframework");
+ CC1Args.push_back(DriverArgs.MakeArgString(Path));
+ }
+}
+
/// Utility function to add a list of system include directories to CC1.
-/*static*/ void ToolChain::addSystemIncludes(const ArgList &DriverArgs,
- ArgStringList &CC1Args,
- ArrayRef<StringRef> Paths) {
+void ToolChain::addSystemIncludes(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ ArrayRef<StringRef> Paths) {
for (const auto &Path : Paths) {
CC1Args.push_back("-internal-isystem");
CC1Args.push_back(DriverArgs.MakeArgString(Path));
}
}
-/*static*/ std::string ToolChain::concat(StringRef Path, const Twine &A,
- const Twine &B, const Twine &C,
- const Twine &D) {
+std::string ToolChain::concat(StringRef Path, const Twine &A, const Twine &B,
+ const Twine &C, const Twine &D) {
SmallString<128> Result(Path);
llvm::sys::path::append(Result, llvm::sys::path::Style::posix, A, B, C, D);
return std::string(Result);
diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp
index 4735dc3..76fa2d1 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -2577,6 +2577,27 @@ void AppleMachO::AddClangSystemIncludeArgs(
}
}
+void DarwinClang::AddClangSystemIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ AppleMachO::AddClangSystemIncludeArgs(DriverArgs, CC1Args);
+
+ if (DriverArgs.hasArg(options::OPT_nostdinc) ||
+ DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ llvm::SmallString<128> Sysroot = GetEffectiveSysroot(DriverArgs);
+
+ // Add <sysroot>/System/Library/Frameworks
+ // Add <sysroot>/System/Library/SubFrameworks
+ // Add <sysroot>/Library/Frameworks
+ SmallString<128> P1(Sysroot), P2(Sysroot), P3(Sysroot);
+ llvm::sys::path::append(P1, "System", "Library", "Frameworks");
+ llvm::sys::path::append(P2, "System", "Library", "SubFrameworks");
+ llvm::sys::path::append(P3, "Library", "Frameworks");
+ addSystemFrameworkIncludes(DriverArgs, CC1Args, {P1, P2, P3});
+}
+
bool DarwinClang::AddGnuCPlusPlusIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
llvm::SmallString<128> Base,
diff --git a/clang/lib/Driver/ToolChains/Darwin.h b/clang/lib/Driver/ToolChains/Darwin.h
index 76523d6..b38bfe6 100644
--- a/clang/lib/Driver/ToolChains/Darwin.h
+++ b/clang/lib/Driver/ToolChains/Darwin.h
@@ -647,6 +647,10 @@ public:
/// @name Apple ToolChain Implementation
/// {
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
RuntimeLibType GetRuntimeLibType(const llvm::opt::ArgList &Args) const override;
void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args,
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index a0b8bbf..3945129 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3373,6 +3373,8 @@ static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts,
: OPT_internal_externc_isystem;
GenerateArg(Consumer, Opt, It->Path);
}
+ for (; It < End && Matches(*It, {frontend::System}, true, true); ++It)
+ GenerateArg(Consumer, OPT_internal_iframework, It->Path);
assert(It == End && "Unhandled HeaderSearchOption::Entry.");
@@ -3505,6 +3507,8 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args,
Group = frontend::ExternCSystem;
Opts.AddPath(A->getValue(), Group, false, true);
}
+ for (const auto *A : Args.filtered(OPT_internal_iframework))
+ Opts.AddPath(A->getValue(), frontend::System, true, true);
// Add the path prefixes which are implicitly treated as being system headers.
for (const auto *A :
diff --git a/clang/lib/Lex/InitHeaderSearch.cpp b/clang/lib/Lex/InitHeaderSearch.cpp
index bb2a213..df45c967 100644
--- a/clang/lib/Lex/InitHeaderSearch.cpp
+++ b/clang/lib/Lex/InitHeaderSearch.cpp
@@ -321,6 +321,9 @@ bool InitHeaderSearch::ShouldAddDefaultIncludePaths(
break;
}
+ if (triple.isOSDarwin())
+ return false;
+
return true; // Everything else uses AddDefaultIncludePaths().
}
@@ -335,22 +338,6 @@ void InitHeaderSearch::AddDefaultIncludePaths(
if (!ShouldAddDefaultIncludePaths(triple))
return;
- // NOTE: some additional header search logic is handled in the driver for
- // Darwin.
- if (triple.isOSDarwin()) {
- if (HSOpts.UseStandardSystemIncludes) {
- // Add the default framework include paths on Darwin.
- if (triple.isDriverKit()) {
- AddPath("/System/DriverKit/System/Library/Frameworks", System, true);
- } else {
- AddPath("/System/Library/Frameworks", System, true);
- AddPath("/System/Library/SubFrameworks", System, true);
- AddPath("/Library/Frameworks", System, true);
- }
- }
- return;
- }
-
if (Lang.CPlusPlus && !Lang.AsmPreprocessor &&
HSOpts.UseStandardCXXIncludes && HSOpts.UseStandardSystemIncludes) {
if (HSOpts.UseLibcxx) {
diff --git a/clang/test/Driver/Inputs/DriverKit19.0.sdk/System/DriverKit/System/Library/SubFrameworks/.keep b/clang/test/Driver/Inputs/DriverKit19.0.sdk/System/DriverKit/System/Library/SubFrameworks/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/clang/test/Driver/Inputs/DriverKit19.0.sdk/System/DriverKit/System/Library/SubFrameworks/.keep
diff --git a/clang/test/Driver/Inputs/MacOSX15.1.sdk/Library/Frameworks/.keep b/clang/test/Driver/Inputs/MacOSX15.1.sdk/Library/Frameworks/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/clang/test/Driver/Inputs/MacOSX15.1.sdk/Library/Frameworks/.keep
diff --git a/clang/test/Driver/Inputs/MacOSX15.1.sdk/System/Library/Frameworks/.keep b/clang/test/Driver/Inputs/MacOSX15.1.sdk/System/Library/Frameworks/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/clang/test/Driver/Inputs/MacOSX15.1.sdk/System/Library/Frameworks/.keep
diff --git a/clang/test/Driver/Inputs/MacOSX15.1.sdk/System/Library/SubFrameworks/.keep b/clang/test/Driver/Inputs/MacOSX15.1.sdk/System/Library/SubFrameworks/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/clang/test/Driver/Inputs/MacOSX15.1.sdk/System/Library/SubFrameworks/.keep
diff --git a/clang/test/Driver/darwin-framework-search-paths.c b/clang/test/Driver/darwin-framework-search-paths.c
new file mode 100644
index 0000000..1cb4dc42
--- /dev/null
+++ b/clang/test/Driver/darwin-framework-search-paths.c
@@ -0,0 +1,23 @@
+// UNSUPPORTED: system-windows
+// Windows is unsupported because we use the Unix path separator `/` in the test.
+
+// RUN: %clang %s -target arm64-apple-macosx15.1 -isysroot %S/Inputs/MacOSX15.1.sdk -c %s -### 2>&1 \
+// RUN: | FileCheck -DSDKROOT=%S/Inputs/MacOSX15.1.sdk %s
+//
+// CHECK: "-cc1"
+// CHECK: "-resource-dir" "[[RESOURCE_DIR:[^"]*]]"
+// CHECK-SAME: "-internal-iframework" "[[SDKROOT]]/System/Library/Frameworks"
+// CHECK-SAME: "-internal-iframework" "[[SDKROOT]]/System/Library/SubFrameworks"
+// CHECK-SAME: "-internal-iframework" "[[SDKROOT]]/Library/Frameworks"
+
+// Verify that -nostdlibinc and -nostdinc removes the default search paths.
+//
+// RUN: %clang %s -target arm64-apple-macosx15.1 -isysroot %S/Inputs/MacOSX15.1.sdk -nostdinc -c %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NOSTD -DSDKROOT=%S/Inputs/MacOSX15.1.sdk %s
+//
+// RUN: %clang %s -target arm64-apple-macosx15.1 -isysroot %S/Inputs/MacOSX15.1.sdk -nostdlibinc -c %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NOSTD -DSDKROOT=%S/Inputs/MacOSX15.1.sdk %s
+//
+// CHECK-NOSTD: "-cc1"
+// CHECK-NOSTD: "-resource-dir" "[[RESOURCE_DIR:[^"]*]]"
+// CHECK-NOSTD-NOT: "-internal-iframework"
diff --git a/clang/test/Driver/darwin-subframeworks.c b/clang/test/Driver/darwin-subframeworks.c
deleted file mode 100644
index 1a7a095..0000000
--- a/clang/test/Driver/darwin-subframeworks.c
+++ /dev/null
@@ -1,18 +0,0 @@
-// UNSUPPORTED: system-windows
-// Windows is unsupported because we use the Unix path separator `\`.
-
-// Add default directories before running clang to check default
-// search paths.
-// RUN: rm -rf %t && mkdir -p %t
-// RUN: cp -R %S/Inputs/MacOSX15.1.sdk %t/
-// RUN: mkdir -p %t/MacOSX15.1.sdk/System/Library/Frameworks
-// RUN: mkdir -p %t/MacOSX15.1.sdk/System/Library/SubFrameworks
-// RUN: mkdir -p %t/MacOSX15.1.sdk/usr/include
-
-// RUN: %clang %s -target arm64-apple-darwin13.0 -isysroot %t/MacOSX15.1.sdk -E -v 2>&1 | FileCheck %s
-
-// CHECK: -isysroot [[PATH:[^ ]*/MacOSX15.1.sdk]]
-// CHECK: #include <...> search starts here:
-// CHECK: [[PATH]]/usr/include
-// CHECK: [[PATH]]/System/Library/Frameworks (framework directory)
-// CHECK: [[PATH]]/System/Library/SubFrameworks (framework directory)
diff --git a/clang/test/Driver/driverkit-path.c b/clang/test/Driver/driverkit-path.c
index 3caae38..32f0a672 100644
--- a/clang/test/Driver/driverkit-path.c
+++ b/clang/test/Driver/driverkit-path.c
@@ -21,13 +21,15 @@ int main() { return 0; }
// LD64-NEW: "-isysroot" "[[PATH:[^"]*]]Inputs/DriverKit19.0.sdk"
// LD64-NEW-NOT: "-L[[PATH]]Inputs/DriverKit19.0.sdk/System/DriverKit/usr/lib"
// LD64-NEW-NOT: "-F[[PATH]]Inputs/DriverKit19.0.sdk/System/DriverKit/System/Library/Frameworks"
+// LD64-NEW-NOT: "-F[[PATH]]Inputs/DriverKit19.0.sdk/System/DriverKit/System/Library/SubFrameworks"
-// RUN: %clang %s -target x86_64-apple-driverkit19.0 -isysroot %S/Inputs/DriverKit19.0.sdk -E -v -x c++ 2>&1 | FileCheck %s --check-prefix=INC
+// RUN: %clang %s -target x86_64-apple-driverkit19.0 -isysroot %S/Inputs/DriverKit19.0.sdk -x c++ -### 2>&1 \
+// RUN: | FileCheck %s -DSDKROOT=%S/Inputs/DriverKit19.0.sdk --check-prefix=INC
//
-// INC: -isysroot [[PATH:[^ ]*/Inputs/DriverKit19.0.sdk]]
-// INC-LABEL: #include <...> search starts here:
-// INC: [[PATH]]/System/DriverKit/usr/local/include
-// INC: /lib{{(64)?}}/clang/{{[^/ ]+}}/include
-// INC: [[PATH]]/System/DriverKit/usr/include
-// INC: [[PATH]]/System/DriverKit/System/Library/Frameworks (framework directory)
+// INC: "-isysroot" "[[SDKROOT]]"
+// INC: "-internal-isystem" "[[SDKROOT]]/System/DriverKit/usr/local/include"
+// INC: "-internal-isystem" "{{.+}}/lib{{(64)?}}/clang/{{[^/ ]+}}/include"
+// INC: "-internal-externc-isystem" "[[SDKROOT]]/System/DriverKit/usr/include"
+// INC: "-internal-iframework" "[[SDKROOT]]/System/DriverKit/System/Library/Frameworks"
+// INC: "-internal-iframework" "[[SDKROOT]]/System/DriverKit/System/Library/SubFrameworks"
diff --git a/clang/test/Preprocessor/cuda-macos-includes.cu b/clang/test/Preprocessor/cuda-macos-includes.cu
deleted file mode 100644
index 6ef94b0..0000000
--- a/clang/test/Preprocessor/cuda-macos-includes.cu
+++ /dev/null
@@ -1,13 +0,0 @@
-// RUN: %clang -cc1 -fcuda-is-device -isysroot /var/empty \
-// RUN: -triple nvptx-nvidia-cuda -aux-triple i386-apple-macosx \
-// RUN: -E -fcuda-is-device -v -o /dev/null -x cuda %s 2>&1 | FileCheck %s
-
-// RUN: %clang -cc1 -isysroot /var/empty \
-// RUN: -triple i386-apple-macosx -aux-triple nvptx-nvidia-cuda \
-// RUN: -E -fcuda-is-device -v -o /dev/null -x cuda %s 2>&1 | FileCheck %s
-
-// Check that when we do CUDA host and device compiles on MacOS, we check for
-// includes in /System/Library/Frameworks and /Library/Frameworks.
-
-// CHECK-DAG: ignoring nonexistent directory "/var/empty/System/Library/Frameworks"
-// CHECK-DAG: ignoring nonexistent directory "/var/empty/Library/Frameworks"
diff --git a/clang/unittests/Frontend/CMakeLists.txt b/clang/unittests/Frontend/CMakeLists.txt
index bbf0396..0d9fc71 100644
--- a/clang/unittests/Frontend/CMakeLists.txt
+++ b/clang/unittests/Frontend/CMakeLists.txt
@@ -10,6 +10,7 @@ add_clang_unittest(FrontendTests
PCHPreambleTest.cpp
ReparseWorkingDirTest.cpp
OutputStreamTest.cpp
+ SearchPathTest.cpp
TextDiagnosticTest.cpp
UtilsTest.cpp
CLANG_LIBS
diff --git a/clang/unittests/Frontend/SearchPathTest.cpp b/clang/unittests/Frontend/SearchPathTest.cpp
new file mode 100644
index 0000000..5d382a4
--- /dev/null
+++ b/clang/unittests/Frontend/SearchPathTest.cpp
@@ -0,0 +1,157 @@
+//====-- unittests/Frontend/SearchPathTest.cpp - FrontendAction tests -----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/VirtualFileSystem.h"
+
+#include "gtest/gtest.h"
+
+#include <memory>
+#include <optional>
+#include <tuple>
+#include <vector>
+
+namespace clang {
+namespace {
+
+class SearchPathTest : public ::testing::Test {
+protected:
+ SearchPathTest()
+ : Diags(new DiagnosticIDs(), new DiagnosticOptions,
+ new IgnoringDiagConsumer()),
+ VFS(new llvm::vfs::InMemoryFileSystem),
+ FileMgr(FileSystemOptions(), VFS), SourceMgr(Diags, FileMgr),
+ Invocation(std::make_unique<CompilerInvocation>()) {}
+
+ DiagnosticsEngine Diags;
+ IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS;
+ FileManager FileMgr;
+ SourceManager SourceMgr;
+ std::unique_ptr<CompilerInvocation> Invocation;
+
+ void addDirectories(ArrayRef<StringRef> Dirs) {
+ for (StringRef Dir : Dirs) {
+ VFS->addFile(Dir, 0, llvm::MemoryBuffer::getMemBuffer(""),
+ /*User=*/std::nullopt, /*Group=*/std::nullopt,
+ llvm::sys::fs::file_type::directory_file);
+ }
+ }
+
+ std::unique_ptr<HeaderSearch>
+ makeHeaderSearchFromCC1Args(llvm::opt::ArgStringList Args) {
+ CompilerInvocation::CreateFromArgs(*Invocation, Args, Diags);
+ HeaderSearchOptions HSOpts = Invocation->getHeaderSearchOpts();
+ LangOptions LangOpts = Invocation->getLangOpts();
+ TargetInfo *Target =
+ TargetInfo::CreateTargetInfo(Diags, Invocation->getTargetOpts());
+ auto HeaderInfo = std::make_unique<HeaderSearch>(HSOpts, SourceMgr, Diags,
+ LangOpts, Target);
+ ApplyHeaderSearchOptions(*HeaderInfo, HSOpts, LangOpts,
+ Target->getTriple());
+ return HeaderInfo;
+ }
+};
+
+TEST_F(SearchPathTest, SearchPathOrder) {
+ addDirectories({"One", "Two", "Three", "Four", "Five", "Six", "Seven",
+ "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen",
+ "Fourteen", "Fifteen", "Sixteen", "Seventeen"});
+ llvm::opt::ArgStringList Args = {
+ // Make sure to use a triple and language that don't automatically add any
+ // search paths.
+ "-triple", "arm64-apple-darwin24.4.0", "-x", "c",
+
+ // clang-format off
+ "-internal-isystem", "One",
+ "-iwithsysroot", "Two",
+ "-c-isystem", "Three",
+ "-IFour",
+ "-idirafter", "Five",
+ "-internal-externc-isystem", "Six",
+ "-iwithprefix", "Seven",
+ "-FEight",
+ "-idirafter", "Nine",
+ "-iframeworkwithsysroot", "Ten",
+ "-internal-iframework", "Eleven",
+ "-iframework", "Twelve",
+ "-iwithprefixbefore", "Thirteen",
+ "-internal-isystem", "Fourteen",
+ "-isystem", "Fifteen",
+ "-ISixteen",
+ "-iwithsysroot", "Seventeen",
+ // clang-format on
+ };
+
+ // The search path arguments get categorized by IncludeDirGroup, but
+ // ultimately are sorted with some groups mixed together and some flags sorted
+ // very specifically within their group. The conceptual groups below don't
+ // exactly correspond to IncludeDirGroup.
+ const std::vector<StringRef> expected = {
+ // User paths: -I and -F mixed together, -iwithprefixbefore.
+ /*-I*/ "Four",
+ /*-F*/ "Eight",
+ /*-I*/ "Sixteen",
+ /*-iwithprefixbefore*/ "Thirteen",
+
+ // System paths: -isystem and -iwithsysroot, -iframework,
+ // -iframeworkwithsysroot, one of {-c-isystem, -cxx-isystem,
+ // -objc-isystem, -objcxx-isystem}
+ /*-iwithsysroot*/ "Two",
+ /*-isystem*/ "Fifteen",
+ /*-iwithsysroot*/ "Seventeen",
+ /*-iframework*/ "Twelve",
+ /*-iframeworkwithsysroot*/ "Ten",
+ /*-c-isystem*/ "Three",
+
+ // Internal paths: -internal-isystem and -internal-externc-isystem,
+ // -internal-iframework
+ /*-internal-isystem*/ "One",
+ /*-internal-externc-isystem*/ "Six",
+ /*-internal-isystem*/ "Fourteen",
+ /*-internal-iframework*/ "Eleven",
+
+ // After paths: -iwithprefix, -idirafter
+ /*-iwithprefix*/ "Seven",
+ /*-idirafter*/ "Five",
+ /*-idirafter*/ "Nine",
+ };
+
+ auto HeaderInfo = makeHeaderSearchFromCC1Args(Args);
+ ConstSearchDirRange SearchDirs(HeaderInfo->angled_dir_begin(),
+ HeaderInfo->search_dir_end());
+ for (auto SearchPaths : zip_longest(SearchDirs, expected)) {
+ auto ActualDirectory = std::get<0>(SearchPaths);
+ EXPECT_TRUE(ActualDirectory.has_value());
+ auto ExpectedPath = std::get<1>(SearchPaths);
+ EXPECT_TRUE(ExpectedPath.has_value());
+ if (ActualDirectory && ExpectedPath) {
+ EXPECT_EQ(ActualDirectory->getName(), *ExpectedPath);
+ }
+ }
+}
+
+} // namespace
+} // namespace clang