158 lines · cpp
1//====-- unittests/Frontend/SearchPathTest.cpp - FrontendAction tests -----===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/Basic/Diagnostic.h"10#include "clang/Basic/DiagnosticIDs.h"11#include "clang/Basic/DiagnosticOptions.h"12#include "clang/Basic/FileManager.h"13#include "clang/Basic/FileSystemOptions.h"14#include "clang/Basic/LangOptions.h"15#include "clang/Basic/SourceManager.h"16#include "clang/Basic/TargetInfo.h"17#include "clang/Frontend/CompilerInvocation.h"18#include "clang/Lex/HeaderSearch.h"19#include "clang/Lex/HeaderSearchOptions.h"20 21#include "llvm/ADT/ArrayRef.h"22#include "llvm/ADT/IntrusiveRefCntPtr.h"23#include "llvm/ADT/STLExtras.h"24#include "llvm/ADT/StringRef.h"25#include "llvm/Option/Option.h"26#include "llvm/Support/FileSystem.h"27#include "llvm/Support/MemoryBuffer.h"28#include "llvm/Support/VirtualFileSystem.h"29 30#include "gtest/gtest.h"31 32#include <memory>33#include <optional>34#include <tuple>35#include <vector>36 37namespace clang {38namespace {39 40class SearchPathTest : public ::testing::Test {41protected:42 SearchPathTest()43 : Diags(DiagnosticIDs::create(), DiagOpts, new IgnoringDiagConsumer()),44 VFS(llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>()),45 FileMgr(FileSystemOptions(), VFS), SourceMgr(Diags, FileMgr),46 Invocation(std::make_unique<CompilerInvocation>()) {}47 48 DiagnosticOptions DiagOpts;49 DiagnosticsEngine Diags;50 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS;51 FileManager FileMgr;52 SourceManager SourceMgr;53 std::unique_ptr<CompilerInvocation> Invocation;54 IntrusiveRefCntPtr<TargetInfo> Target;55 56 void addDirectories(ArrayRef<StringRef> Dirs) {57 for (StringRef Dir : Dirs) {58 VFS->addFile(Dir, 0, llvm::MemoryBuffer::getMemBuffer(""),59 /*User=*/std::nullopt, /*Group=*/std::nullopt,60 llvm::sys::fs::file_type::directory_file);61 }62 }63 64 std::unique_ptr<HeaderSearch>65 makeHeaderSearchFromCC1Args(llvm::opt::ArgStringList Args) {66 CompilerInvocation::CreateFromArgs(*Invocation, Args, Diags);67 HeaderSearchOptions HSOpts = Invocation->getHeaderSearchOpts();68 LangOptions LangOpts = Invocation->getLangOpts();69 Target = TargetInfo::CreateTargetInfo(Diags, Invocation->getTargetOpts());70 auto HeaderInfo = std::make_unique<HeaderSearch>(HSOpts, SourceMgr, Diags,71 LangOpts, Target.get());72 ApplyHeaderSearchOptions(*HeaderInfo, HSOpts, LangOpts,73 Target->getTriple());74 return HeaderInfo;75 }76};77 78TEST_F(SearchPathTest, SearchPathOrder) {79 addDirectories({"One", "Two", "Three", "Four", "Five", "Six", "Seven",80 "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen",81 "Fourteen", "Fifteen", "Sixteen", "Seventeen"});82 llvm::opt::ArgStringList Args = {83 // Make sure to use a triple and language that don't automatically add any84 // search paths.85 "-triple", "arm64-apple-darwin24.4.0", "-x", "c",86 87 // clang-format off88 "-internal-isystem", "One",89 "-iwithsysroot", "Two",90 "-c-isystem", "Three",91 "-IFour",92 "-idirafter", "Five",93 "-internal-externc-isystem", "Six",94 "-iwithprefix", "Seven",95 "-FEight",96 "-idirafter", "Nine",97 "-iframeworkwithsysroot", "Ten",98 "-internal-iframework", "Eleven",99 "-iframework", "Twelve",100 "-iwithprefixbefore", "Thirteen",101 "-internal-isystem", "Fourteen",102 "-isystem", "Fifteen",103 "-ISixteen",104 "-iwithsysroot", "Seventeen",105 // clang-format on106 };107 108 // The search path arguments get categorized by IncludeDirGroup, but109 // ultimately are sorted with some groups mixed together and some flags sorted110 // very specifically within their group. The conceptual groups below don't111 // exactly correspond to IncludeDirGroup.112 const std::vector<StringRef> expected = {113 // User paths: -I and -F mixed together, -iwithprefixbefore.114 /*-I*/ "Four",115 /*-F*/ "Eight",116 /*-I*/ "Sixteen",117 /*-iwithprefixbefore*/ "Thirteen",118 119 // System paths: -isystem and -iwithsysroot, -iframework,120 // -iframeworkwithsysroot, one of {-c-isystem, -cxx-isystem,121 // -objc-isystem, -objcxx-isystem}122 /*-iwithsysroot*/ "Two",123 /*-isystem*/ "Fifteen",124 /*-iwithsysroot*/ "Seventeen",125 /*-iframework*/ "Twelve",126 /*-iframeworkwithsysroot*/ "Ten",127 /*-c-isystem*/ "Three",128 129 // Internal paths: -internal-isystem and -internal-externc-isystem,130 // -internal-iframework131 /*-internal-isystem*/ "One",132 /*-internal-externc-isystem*/ "Six",133 /*-internal-isystem*/ "Fourteen",134 /*-internal-iframework*/ "Eleven",135 136 // After paths: -iwithprefix, -idirafter137 /*-iwithprefix*/ "Seven",138 /*-idirafter*/ "Five",139 /*-idirafter*/ "Nine",140 };141 142 auto HeaderInfo = makeHeaderSearchFromCC1Args(Args);143 ConstSearchDirRange SearchDirs(HeaderInfo->angled_dir_begin(),144 HeaderInfo->search_dir_end());145 for (auto SearchPaths : zip_longest(SearchDirs, expected)) {146 auto ActualDirectory = std::get<0>(SearchPaths);147 EXPECT_TRUE(ActualDirectory.has_value());148 auto ExpectedPath = std::get<1>(SearchPaths);149 EXPECT_TRUE(ExpectedPath.has_value());150 if (ActualDirectory && ExpectedPath) {151 EXPECT_EQ(ActualDirectory->getName(), *ExpectedPath);152 }153 }154}155 156} // namespace157} // namespace clang158