26#include "llvm/ADT/APInt.h"
27#include "llvm/ADT/STLExtras.h"
28#include "llvm/ADT/SmallString.h"
29#include "llvm/ADT/SmallVector.h"
30#include "llvm/ADT/Statistic.h"
31#include "llvm/ADT/StringRef.h"
32#include "llvm/Support/Allocator.h"
33#include "llvm/Support/Capacity.h"
34#include "llvm/Support/Errc.h"
35#include "llvm/Support/ErrorHandling.h"
36#include "llvm/Support/FileSystem.h"
37#include "llvm/Support/Path.h"
38#include "llvm/Support/VirtualFileSystem.h"
39#include "llvm/Support/xxhash.h"
46#include <system_error>
51#define DEBUG_TYPE "file-search"
55 NumMultiIncludeFileOptzn,
56 "Number of #includes skipped due to the multi-include optimization.");
59 "Number of subframework lookups.");
73 if (ControllingMacro && ControllingMacro->
isOutOfDate()) {
74 assert(
External &&
"We must have an external source if we have a "
75 "controlling macro that is out of date.");
76 External->updateOutOfDateIdentifier(*ControllingMacro);
78 return ControllingMacro;
87 : HSOpts(
std::move(HSOpts)), Diags(Diags),
88 FileMgr(SourceMgr.getFileManager()), FrameworkMap(64),
89 ModMap(SourceMgr, Diags, LangOpts,
Target, *this) {}
92 llvm::errs() <<
"\n*** HeaderSearch Stats:\n"
93 << FileInfo.size() <<
" files tracked.\n";
94 unsigned NumOnceOnlyFiles = 0;
95 for (
unsigned i = 0, e = FileInfo.size(); i != e; ++i)
96 NumOnceOnlyFiles += (FileInfo[i].isPragmaOnce || FileInfo[i].isImport);
97 llvm::errs() <<
" " << NumOnceOnlyFiles <<
" #import/#pragma once files.\n";
99 llvm::errs() <<
" " << NumIncluded <<
" #include/#include_next/#import.\n"
100 <<
" " << NumMultiIncludeFileOptzn
101 <<
" #includes skipped due to the multi-include optimization.\n";
103 llvm::errs() << NumFrameworkLookups <<
" framework lookups.\n"
104 << NumSubFrameworkLookups <<
" subframework lookups.\n";
108 std::vector<DirectoryLookup> dirs,
unsigned int angledDirIdx,
109 unsigned int systemDirIdx,
110 llvm::DenseMap<unsigned int, unsigned int> searchDirToHSEntry) {
111 assert(angledDirIdx <= systemDirIdx && systemDirIdx <= dirs.size() &&
112 "Directory indices are unordered");
113 SearchDirs = std::move(dirs);
114 SearchDirsUsage.assign(SearchDirs.size(),
false);
115 AngledDirIdx = angledDirIdx;
116 SystemDirIdx = systemDirIdx;
117 SearchDirToHSEntry = std::move(searchDirToHSEntry);
119 indexInitialHeaderMaps();
123 unsigned idx = isAngled ? SystemDirIdx : AngledDirIdx;
124 SearchDirs.insert(SearchDirs.begin() + idx, dir);
125 SearchDirsUsage.insert(SearchDirsUsage.begin() + idx,
false);
132 std::vector<bool> UserEntryUsage(HSOpts->UserEntries.size());
133 for (
unsigned I = 0,
E = SearchDirsUsage.size(); I <
E; ++I) {
135 if (SearchDirsUsage[I]) {
136 auto UserEntryIdxIt = SearchDirToHSEntry.find(I);
138 if (UserEntryIdxIt != SearchDirToHSEntry.end())
139 UserEntryUsage[UserEntryIdxIt->second] =
true;
142 return UserEntryUsage;
146 std::vector<bool> VFSUsage;
153 RootFS.visit([&](llvm::vfs::FileSystem &FS) {
154 if (
auto *RFS = dyn_cast<llvm::vfs::RedirectingFileSystem>(&FS)) {
155 VFSUsage.push_back(RFS->hasBeenUsed());
156 RFS->clearHasBeenUsed();
160 "A different number of RedirectingFileSystem's were present than "
161 "-ivfsoverlay options passed to Clang!");
163 std::reverse(VFSUsage.begin(), VFSUsage.end());
172 if (!HeaderMaps.empty()) {
173 for (
unsigned i = 0, e = HeaderMaps.size(); i != e; ++i)
176 if (HeaderMaps[i].first == FE)
177 return HeaderMaps[i].second.get();
181 HeaderMaps.emplace_back(FE, std::move(HM));
182 return HeaderMaps.back().second.get();
191 for (
auto &HM : HeaderMaps)
192 Names.push_back(std::string(HM.first.getName()));
208 auto i(HSOpts->PrebuiltModuleFiles.find(ModuleName));
209 if (i != HSOpts->PrebuiltModuleFiles.end())
212 if (FileMapOnly || HSOpts->PrebuiltModulePaths.empty())
217 for (
const std::string &Dir : HSOpts->PrebuiltModulePaths) {
219 llvm::sys::fs::make_absolute(
Result);
220 if (ModuleName.contains(
':'))
224 llvm::sys::path::append(
Result, ModuleName.split(
':').first +
"-" +
225 ModuleName.split(
':').second +
228 llvm::sys::path::append(
Result, ModuleName +
".pcm");
230 return std::string(
Result);
240 StringRef ModuleMapPath =
ModuleMap->getName();
241 StringRef ModuleCacheHash = HSOpts->DisableModuleHash ?
"" :
getModuleHash();
242 for (
const std::string &Dir : HSOpts->PrebuiltModulePaths) {
244 llvm::sys::fs::make_absolute(CachePath);
245 llvm::sys::path::append(CachePath, ModuleCacheHash);
247 getCachedModuleFileNameImpl(ModuleName, ModuleMapPath, CachePath);
255 StringRef ModuleMapPath) {
256 return getCachedModuleFileNameImpl(ModuleName, ModuleMapPath,
260std::string HeaderSearch::getCachedModuleFileNameImpl(StringRef ModuleName,
261 StringRef ModuleMapPath,
262 StringRef CachePath) {
265 if (CachePath.empty())
270 if (HSOpts->DisableModuleHash) {
271 llvm::sys::path::append(
Result, ModuleName +
".pcm");
281 if (
getModuleMap().canonicalizeModuleMapPath(CanonicalPath))
284 auto Hash = llvm::xxh3_64bits(CanonicalPath.str().lower());
287 llvm::APInt(64, Hash).toStringUnsigned(HashStr, 36);
288 llvm::sys::path::append(
Result, ModuleName +
"-" + HashStr +
".pcm");
290 return Result.str().str();
295 bool AllowExtraModuleMapSearch) {
298 if (
Module || !AllowSearch || !HSOpts->ImplicitModuleMaps)
301 StringRef SearchName = ModuleName;
303 AllowExtraModuleMapSearch);
313 if (!
Module && SearchName.consume_back(
"_Private"))
315 AllowExtraModuleMapSearch);
316 if (!
Module && SearchName.consume_back(
"Private"))
318 AllowExtraModuleMapSearch);
324 bool AllowExtraModuleMapSearch) {
330 if (Dir.isFramework()) {
335 FrameworkDirName += Dir.getFrameworkDirRef()->getName();
336 llvm::sys::path::append(FrameworkDirName, SearchName +
".framework");
337 if (
auto FrameworkDir =
340 Module = loadFrameworkModule(ModuleName, *FrameworkDir, IsSystem);
349 if (!Dir.isNormalDir())
352 bool IsSystem = Dir.isSystemHeaderDirectory();
358 false) == LMM_NewlyLoaded) {
369 NestedModuleMapDirName = Dir.getDirRef()->getName();
370 llvm::sys::path::append(NestedModuleMapDirName, ModuleName);
372 false) == LMM_NewlyLoaded){
379 if (HSOpts->AllowModuleMapSubdirectorySearch) {
382 if (Dir.haveSearchedAllModuleMaps())
387 if (AllowExtraModuleMapSearch)
388 loadSubdirectoryModuleMaps(Dir);
400void HeaderSearch::indexInitialHeaderMaps() {
401 llvm::StringMap<unsigned, llvm::BumpPtrAllocator> Index(SearchDirs.size());
404 for (
unsigned i = 0; i != SearchDirs.size(); ++i) {
405 auto &Dir = SearchDirs[i];
410 if (!Dir.isHeaderMap()) {
411 SearchDirHeaderMapIndex = std::move(Index);
412 FirstNonHeaderMapSearchDirIdx = i;
417 auto Callback = [&](StringRef
Filename) {
418 Index.try_emplace(
Filename.lower(), i);
420 Dir.getHeaderMap()->forEachKey(Callback);
435 assert(
isHeaderMap() &&
"Unknown DirectoryLookup");
441 bool IsSystemHeaderDir,
Module *RequestingModule,
443 bool CacheFailures ) {
450 std::error_code EC = llvm::errorToErrorCode(
File.takeError());
451 if (EC != llvm::errc::no_such_file_or_directory &&
452 EC != llvm::errc::invalid_argument &&
453 EC != llvm::errc::is_a_directory && EC != llvm::errc::not_a_directory) {
454 Diags.
Report(IncludeLoc, diag::err_cannot_open_file)
461 if (!findUsableModuleForHeader(
462 *
File, Dir ? Dir :
File->getFileEntry().getDir(), RequestingModule,
463 SuggestedModule, IsSystemHeaderDir))
475 bool &InUserSpecifiedSystemFramework,
bool &IsFrameworkFound,
477 bool OpenFile)
const {
478 InUserSpecifiedSystemFramework =
false;
479 IsInHeaderMap =
false;
486 llvm::sys::path::append(TmpDir,
Filename);
490 SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
493 RelativePath->clear();
497 return HS.getFileAndSuggestModule(
499 RequestingModule, SuggestedModule, OpenFile);
503 return DoFrameworkLookup(
Filename, HS, SearchPath, RelativePath,
504 RequestingModule, SuggestedModule,
505 InUserSpecifiedSystemFramework, IsFrameworkFound);
507 assert(
isHeaderMap() &&
"Unknown directory lookup");
514 IsInHeaderMap =
true;
516 auto FixupSearchPathAndFindUsableModule =
519 StringRef SearchPathRef(
getName());
521 SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
524 RelativePath->clear();
527 if (!HS.findUsableModuleForHeader(
File,
File.getFileEntry().getDir(),
528 RequestingModule, SuggestedModule,
538 if (llvm::sys::path::is_relative(Dest)) {
539 MappedName.append(Dest.begin(), Dest.end());
540 Filename = StringRef(MappedName.begin(), MappedName.size());
545 return FixupSearchPathAndFindUsableModule(*Res);
565 assert(llvm::sys::path::extension(DirName) ==
".framework" &&
566 "Not a framework directory");
588 DirName = llvm::sys::path::parent_path(DirName);
599 if (llvm::sys::path::extension(DirName) ==
".framework") {
600 SubmodulePath.push_back(std::string(llvm::sys::path::stem(DirName)));
601 TopFrameworkDir = *Dir;
605 return TopFrameworkDir;
609 bool HasSuggestedModule) {
610 return HasSuggestedModule ||
620 bool &InUserSpecifiedSystemFramework,
bool &IsFrameworkFound)
const {
624 size_t SlashPos =
Filename.find(
'/');
625 if (SlashPos == StringRef::npos)
642 if (FrameworkName.empty() || FrameworkName.back() !=
'/')
643 FrameworkName.push_back(
'/');
646 StringRef ModuleName(
Filename.begin(), SlashPos);
647 FrameworkName += ModuleName;
650 FrameworkName +=
".framework/";
654 ++NumFrameworkLookups;
669 SystemFrameworkMarker +=
".system_framework";
670 if (llvm::sys::fs::exists(SystemFrameworkMarker)) {
681 RelativePath->clear();
686 unsigned OrigSize = FrameworkName.size();
688 FrameworkName +=
"Headers/";
693 SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1);
702 const char *
Private =
"Private";
703 FrameworkName.insert(FrameworkName.begin()+OrigSize,
Private,
706 SearchPath->insert(SearchPath->begin()+OrigSize,
Private,
716 StringRef FrameworkPath =
File->getDir().getName();
717 bool FoundFramework =
false;
726 if (llvm::sys::path::extension(FrameworkPath) ==
".framework") {
727 FoundFramework =
true;
732 FrameworkPath = llvm::sys::path::parent_path(FrameworkPath);
733 if (FrameworkPath.empty())
738 if (FoundFramework) {
739 if (!HS.findUsableModuleForFrameworkHeader(*
File, FrameworkPath,
741 SuggestedModule, IsSystem))
744 if (!HS.findUsableModuleForHeader(*
File,
getDir(), RequestingModule,
745 SuggestedModule, IsSystem))
754void HeaderSearch::cacheLookupSuccess(LookupFileCacheInfo &CacheLookup,
757 CacheLookup.HitIt = HitIt;
758 noteLookupUsage(HitIt.Idx,
Loc);
762 SearchDirsUsage[HitIdx] =
true;
764 auto UserEntryIdxIt = SearchDirToHSEntry.find(HitIdx);
765 if (UserEntryIdxIt != SearchDirToHSEntry.end())
766 Diags.
Report(
Loc, diag::remark_pp_search_path_usage)
767 << HSOpts->UserEntries[UserEntryIdxIt->second].Path;
785 if (MSFE && FE != *MSFE) {
786 Diags.
Report(IncludeLoc, diag::ext_pp_include_search_ms) << MSFE->
getName();
792static const char *
copyString(StringRef Str, llvm::BumpPtrAllocator &Alloc) {
793 assert(!Str.empty());
794 char *CopyStr = Alloc.Allocate<
char>(Str.size()+1);
795 std::copy(Str.begin(), Str.end(), CopyStr);
796 CopyStr[Str.size()] =
'\0';
803 using namespace llvm::sys;
804 path::const_iterator I = path::begin(
Path);
805 path::const_iterator
E = path::end(
Path);
806 IsPrivateHeader =
false;
818 if (*I ==
"Headers") {
820 }
else if (*I ==
"PrivateHeaders") {
822 IsPrivateHeader =
true;
823 }
else if (I->ends_with(
".framework")) {
824 StringRef Name = I->drop_back(10);
826 FrameworkName.clear();
827 FrameworkName.append(Name.begin(), Name.end());
828 IncludeSpelling.clear();
829 IncludeSpelling.append(Name.begin(), Name.end());
831 }
else if (FoundComp >= 2) {
832 IncludeSpelling.push_back(
'/');
833 IncludeSpelling.append(I->begin(), I->end());
838 return !FrameworkName.empty() && FoundComp >= 2;
843 StringRef Includer, StringRef IncludeFilename,
845 bool FoundByHeaderMap =
false) {
846 bool IsIncluderPrivateHeader =
false;
850 FromIncludeSpelling))
852 bool IsIncludeePrivateHeader =
false;
853 bool IsIncludeeInFramework =
855 ToFramework, ToIncludeSpelling);
857 if (!isAngled && !FoundByHeaderMap) {
859 if (IsIncludeeInFramework) {
860 NewInclude += ToIncludeSpelling;
863 NewInclude += IncludeFilename;
866 Diags.
Report(IncludeLoc, diag::warn_quoted_include_in_framework_header)
874 if (!IsIncluderPrivateHeader && IsIncludeeInFramework &&
875 IsIncludeePrivateHeader && FromFramework == ToFramework)
876 Diags.
Report(IncludeLoc, diag::warn_framework_include_private_from_public)
888 ArrayRef<std::pair<OptionalFileEntryRef, DirectoryEntryRef>> Includers,
891 bool *IsMapped,
bool *IsFrameworkFound,
bool SkipCache,
892 bool BuildSystemModule,
bool OpenFile,
bool CacheFailures) {
899 if (IsFrameworkFound)
900 *IsFrameworkFound =
false;
906 if (llvm::sys::path::is_absolute(
Filename)) {
916 RelativePath->clear();
920 return getFileAndSuggestModule(
Filename, IncludeLoc,
nullptr,
922 RequestingModule, SuggestedModule, OpenFile,
935 if (!Includers.empty() && !isAngled) {
938 for (
const auto &IncluderAndDir : Includers) {
942 TmpDir = IncluderAndDir.second.getName();
943 llvm::sys::path::append(TmpDir,
Filename);
952 bool IncluderIsSystemHeader = [&]() {
954 return BuildSystemModule;
956 assert(HFI &&
"includer without file info");
960 TmpDir, IncludeLoc, IncluderAndDir.second, IncluderIsSystemHeader,
961 RequestingModule, SuggestedModule)) {
963 assert(
First &&
"only first includer can have no file");
974 assert(FromHFI &&
"includer without file info");
975 unsigned DirInfo = FromHFI->
DirInfo;
981 StringRef SearchPathRef(IncluderAndDir.second.getName());
983 SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
986 RelativePath->clear();
991 IncluderAndDir.second.getName(),
Filename,
999 if (Diags.
isIgnored(diag::ext_pp_include_search_ms, IncludeLoc)) {
1003 if (SuggestedModule) {
1004 MSSuggestedModule = *SuggestedModule;
1029 LookupFileCacheInfo &CacheLookup = LookupFileCache[
Filename];
1034 if (CacheLookup.StartIt == NextIt &&
1035 CacheLookup.RequestingModule == RequestingModule) {
1037 if (CacheLookup.HitIt)
1038 It = CacheLookup.HitIt;
1039 if (CacheLookup.MappedName) {
1048 CacheLookup.reset(RequestingModule, NextIt);
1054 auto Iter = SearchDirHeaderMapIndex.find(
Filename.lower());
1055 if (
Iter == SearchDirHeaderMapIndex.end())
1064 CacheLookup.reset(RequestingModule, NextIt);
1071 bool InUserSpecifiedSystemFramework =
false;
1072 bool IsInHeaderMap =
false;
1073 bool IsFrameworkFoundInDir =
false;
1075 Filename, *
this, IncludeLoc, SearchPath, RelativePath, RequestingModule,
1076 SuggestedModule, InUserSpecifiedSystemFramework, IsFrameworkFoundInDir,
1077 IsInHeaderMap, MappedName, OpenFile);
1078 if (!MappedName.empty()) {
1079 assert(IsInHeaderMap &&
"MappedName should come from a header map");
1080 CacheLookup.MappedName =
1081 copyString(MappedName, LookupFileCache.getAllocator());
1087 *IsMapped |= (!MappedName.empty() || (IsInHeaderMap &&
File));
1088 if (IsFrameworkFound)
1092 *IsFrameworkFound |= (IsFrameworkFoundInDir && !CacheLookup.MappedName);
1102 HFI.
DirInfo = CurDir->getDirCharacteristic();
1112 for (
unsigned j = SystemHeaderPrefixes.size(); j; --j) {
1113 if (
Filename.starts_with(SystemHeaderPrefixes[j - 1].first)) {
1121 if (SuggestedModule)
1122 *SuggestedModule = MSSuggestedModule;
1126 bool FoundByHeaderMap = !IsMapped ?
false : *IsMapped;
1127 if (!Includers.empty())
1129 Includers.front().second.getName(),
Filename,
1130 *
File, isAngled, FoundByHeaderMap);
1133 cacheLookupSuccess(CacheLookup, It, IncludeLoc);
1138 if (SuggestedModule)
1139 *SuggestedModule = MSSuggestedModule;
1145 return std::nullopt;
1159 size_t SlashPos =
Filename.find(
'/');
1160 if (SlashPos == StringRef::npos)
1161 return std::nullopt;
1164 StringRef ContextName = ContextFileEnt.
getName();
1167 const unsigned DotFrameworkLen = 10;
1168 auto FrameworkPos = ContextName.find(
".framework");
1169 if (FrameworkPos == StringRef::npos ||
1170 (ContextName[FrameworkPos + DotFrameworkLen] !=
'/' &&
1171 ContextName[FrameworkPos + DotFrameworkLen] !=
'\\'))
1172 return std::nullopt;
1176 DotFrameworkLen + 1);
1179 FrameworkName +=
"Frameworks/";
1181 FrameworkName +=
".framework/";
1184 *FrameworkMap.insert(std::make_pair(
Filename.substr(0, SlashPos),
1188 if (CacheLookup.second.Directory &&
1189 CacheLookup.first().size() == FrameworkName.size() &&
1190 memcmp(CacheLookup.first().data(), &FrameworkName[0],
1191 CacheLookup.first().size()) != 0)
1192 return std::nullopt;
1195 if (!CacheLookup.second.Directory) {
1196 ++NumSubFrameworkLookups;
1201 return std::nullopt;
1205 CacheLookup.second.Directory = Dir;
1210 RelativePath->clear();
1216 HeadersFilename +=
"Headers/";
1218 SearchPath->clear();
1220 SearchPath->append(HeadersFilename.begin(), HeadersFilename.end()-1);
1227 HeadersFilename = FrameworkName;
1228 HeadersFilename +=
"PrivateHeaders/";
1230 SearchPath->clear();
1232 SearchPath->append(HeadersFilename.begin(), HeadersFilename.end()-1);
1239 return std::nullopt;
1244 assert(ContextHFI &&
"context file without file info");
1247 unsigned DirInfo = ContextHFI->
DirInfo;
1250 FrameworkName.pop_back();
1251 if (!findUsableModuleForFrameworkHeader(*
File, FrameworkName,
1252 RequestingModule, SuggestedModule,
1254 return std::nullopt;
1273 bool isModuleHeader,
1274 bool isTextualModuleHeader) {
1291 assert(OtherHFI.
External &&
"expected to merge external HFI");
1307 if (FE.
getUID() >= FileInfo.size())
1308 FileInfo.resize(FE.
getUID() + 1);
1314 if (ExternalHFI.IsValid) {
1316 if (ExternalHFI.External)
1331 if (FE.
getUID() >= FileInfo.size())
1332 FileInfo.resize(FE.
getUID() + 1);
1334 HFI = &FileInfo[FE.
getUID()];
1338 if (ExternalHFI.IsValid) {
1340 if (ExternalHFI.External)
1344 }
else if (FE.
getUID() < FileInfo.size()) {
1345 HFI = &FileInfo[FE.
getUID()];
1350 return (HFI && HFI->
IsValid) ? HFI :
nullptr;
1356 if (FE.
getUID() < FileInfo.size()) {
1357 HFI = &FileInfo[FE.
getUID()];
1370 return HFI->isPragmaOnce || HFI->LazyControllingMacro.isValid();
1376 bool isCompilingModuleHeader) {
1378 if (!isCompilingModuleHeader) {
1387 HFI.mergeModuleMembership(Role);
1388 HFI.isCompilingModuleHeader |= isCompilingModuleHeader;
1393 bool ModulesEnabled,
Module *M,
1394 bool &IsFirstIncludeOfFile) {
1410 IsFirstIncludeOfFile =
false;
1413 auto MaybeReenterImportedFile = [&]() ->
bool {
1503 (FileInfo.
isImport && !MaybeReenterImportedFile()))
1519 ++NumMultiIncludeFileOptzn;
1529 return SearchDirs.capacity()
1530 + llvm::capacity_in_bytes(FileInfo)
1531 + llvm::capacity_in_bytes(HeaderMaps)
1532 + LookupFileCache.getAllocator().getTotalMemory()
1533 + FrameworkMap.getAllocator().getTotalMemory();
1537 return &DL - &*SearchDirs.begin();
1541 return FrameworkNames.insert(Framework).first->first();
1545 auto It = IncludeNames.find(
File);
1546 if (It == IncludeNames.end())
1554 if (!HSOpts->ImplicitModuleMaps)
1562 DirName = llvm::sys::path::parent_path(DirName);
1563 if (DirName.empty())
1573 llvm::sys::path::extension(Dir->getName()) ==
1575 case LMM_NewlyLoaded:
1576 case LMM_AlreadyLoaded:
1579 for (
unsigned I = 0, N = FixUpDirectories.size(); I != N; ++I)
1580 DirectoryHasModuleMap[FixUpDirectories[I]] =
true;
1583 case LMM_NoDirectory:
1584 case LMM_InvalidModuleMap:
1594 FixUpDirectories.push_back(*Dir);
1600 bool AllowExcluded)
const {
1630 Module *RequestingModule,
1646 if (SuggestedModule)
1656 if (SuggestedModule)
1664bool HeaderSearch::findUsableModuleForHeader(
1675bool HeaderSearch::findUsableModuleForFrameworkHeader(
1684 assert(TopFrameworkDir &&
"Could not find the top-most framework dir");
1687 StringRef ModuleName = llvm::sys::path::stem(TopFrameworkDir->
getName());
1691 loadFrameworkModule(ModuleName, *TopFrameworkDir, IsSystemFramework);
1705 StringRef
Filename = llvm::sys::path::filename(
File.getName());
1708 llvm::sys::path::append(PrivateFilename,
"module_private.map");
1709 else if (
Filename ==
"module.modulemap")
1710 llvm::sys::path::append(PrivateFilename,
"module.private.modulemap");
1712 return std::nullopt;
1716 Diags.
Report(diag::warn_deprecated_module_dot_map)
1717 << PrivateFilename << 1
1718 <<
File.getDir().getName().ends_with(
".framework");
1724 FileID ID,
unsigned *Offset,
1725 StringRef OriginalModuleMapFile) {
1732 if (!OriginalModuleMapFile.empty()) {
1736 llvm::sys::path::parent_path(OriginalModuleMapFile));
1739 Dir = FakeFile.getDir();
1742 Dir =
File.getDir();
1745 assert(Dir &&
"parent must exist");
1746 StringRef DirName(Dir->
getName());
1747 if (llvm::sys::path::filename(DirName) ==
"Modules") {
1748 DirName = llvm::sys::path::parent_path(DirName);
1749 if (DirName.ends_with(
".framework"))
1754 assert(Dir &&
"parent must exist");
1758 assert(Dir &&
"module map home directory must exist");
1759 switch (loadModuleMapFileImpl(
File, IsSystem, *Dir, ID, Offset)) {
1760 case LMM_AlreadyLoaded:
1761 case LMM_NewlyLoaded:
1763 case LMM_NoDirectory:
1764 case LMM_InvalidModuleMap:
1767 llvm_unreachable(
"Unknown load module map result");
1770HeaderSearch::LoadModuleMapResult
1776 auto AddResult = LoadedModuleMaps.insert(std::make_pair(
File,
true));
1777 if (!AddResult.second)
1778 return AddResult.first->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
1781 LoadedModuleMaps[
File] =
false;
1782 return LMM_InvalidModuleMap;
1789 LoadedModuleMaps[
File] =
false;
1790 return LMM_InvalidModuleMap;
1795 return LMM_NewlyLoaded;
1800 if (!HSOpts->ImplicitModuleMaps)
1801 return std::nullopt;
1806 llvm::sys::path::append(ModuleMapFileName,
"Modules");
1807 llvm::sys::path::append(ModuleMapFileName,
"module.modulemap");
1812 ModuleMapFileName = Dir.
getName();
1813 llvm::sys::path::append(ModuleMapFileName,
"module.map");
1815 Diags.
Report(diag::warn_deprecated_module_dot_map)
1816 << ModuleMapFileName << 0 << IsFramework;
1823 ModuleMapFileName = Dir.
getName();
1824 llvm::sys::path::append(ModuleMapFileName,
"Modules",
1825 "module.private.modulemap");
1829 return std::nullopt;
1836 case LMM_InvalidModuleMap:
1838 if (HSOpts->ImplicitModuleMaps)
1839 ModMap.inferFrameworkModule(Dir, IsSystem,
nullptr);
1842 case LMM_NoDirectory:
1845 case LMM_AlreadyLoaded:
1846 case LMM_NewlyLoaded:
1853HeaderSearch::LoadModuleMapResult
1859 return LMM_NoDirectory;
1862HeaderSearch::LoadModuleMapResult
1865 auto KnownDir = DirectoryHasModuleMap.find(Dir);
1866 if (KnownDir != DirectoryHasModuleMap.end())
1867 return KnownDir->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
1871 LoadModuleMapResult
Result =
1872 loadModuleMapFileImpl(*ModuleMapFile, IsSystem, Dir);
1876 if (
Result == LMM_NewlyLoaded)
1877 DirectoryHasModuleMap[Dir] =
true;
1878 else if (
Result == LMM_InvalidModuleMap)
1879 DirectoryHasModuleMap[Dir] =
false;
1882 return LMM_InvalidModuleMap;
1888 if (HSOpts->ImplicitModuleMaps) {
1891 bool IsSystem = DL.isSystemHeaderDirectory();
1892 if (DL.isFramework()) {
1895 llvm::sys::path::native(DL.getFrameworkDirRef()->getName(), DirNative);
1899 for (llvm::vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC),
1901 Dir != DirEnd && !EC; Dir.increment(EC)) {
1902 if (llvm::sys::path::extension(Dir->path()) !=
".framework")
1910 loadFrameworkModule(llvm::sys::path::stem(Dir->path()), *FrameworkDir,
1917 if (DL.isHeaderMap())
1925 loadSubdirectoryModuleMaps(DL);
1930 llvm::transform(ModMap.
modules(), std::back_inserter(Modules),
1931 [](
const auto &NameAndMod) { return NameAndMod.second; });
1935 if (!HSOpts->ImplicitModuleMaps)
1941 if (!DL.isNormalDir())
1950void HeaderSearch::loadSubdirectoryModuleMaps(
DirectoryLookup &SearchDir) {
1951 assert(HSOpts->ImplicitModuleMaps &&
1952 "Should not be loading subdirectory module maps");
1961 llvm::sys::path::native(Dir, DirNative);
1963 for (llvm::vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd;
1964 Dir != DirEnd && !EC; Dir.increment(EC)) {
1965 if (Dir->type() == llvm::sys::fs::file_type::regular_file)
1967 bool IsFramework = llvm::sys::path::extension(Dir->path()) ==
".framework";
1979 MainFile, IsAngled);
1983 llvm::StringRef
File, llvm::StringRef WorkingDir, llvm::StringRef MainFile,
1984 bool *IsAngled)
const {
1985 using namespace llvm::sys;
1988 if (!WorkingDir.empty() && !path::is_absolute(FilePath))
1989 fs::make_absolute(WorkingDir, FilePath);
1993 path::remove_dots(FilePath,
true);
1994 path::native(FilePath, path::Style::posix);
1997 unsigned BestPrefixLength = 0;
2002 if (!WorkingDir.empty() && !path::is_absolute(Dir))
2003 fs::make_absolute(WorkingDir, Dir);
2004 path::remove_dots(Dir,
true);
2005 for (
auto NI = path::begin(
File), NE = path::end(
File),
2006 DI = path::begin(Dir), DE = path::end(Dir);
2007 NI != NE; ++NI, ++DI) {
2010 unsigned PrefixLength = NI - path::begin(
File);
2011 if (PrefixLength > BestPrefixLength) {
2012 BestPrefixLength = PrefixLength;
2019 if (NI->size() == 1 && DI->size() == 1 &&
2020 path::is_separator(NI->front()) && path::is_separator(DI->front()))
2026 if (NI->ends_with(
".sdk") && DI->ends_with(
".sdk")) {
2027 StringRef NBasename = path::stem(*NI);
2028 StringRef DBasename = path::stem(*DI);
2029 if (DBasename.starts_with(NBasename))
2039 bool BestPrefixIsFramework =
false;
2041 if (DL.isNormalDir()) {
2042 StringRef Dir = DL.getDirRef()->getName();
2043 if (CheckDir(Dir)) {
2045 *IsAngled = BestPrefixLength && isSystem(DL.getDirCharacteristic());
2046 BestPrefixIsFramework =
false;
2048 }
else if (DL.isFramework()) {
2049 StringRef Dir = DL.getFrameworkDirRef()->getName();
2050 if (CheckDir(Dir)) {
2053 *IsAngled = BestPrefixLength;
2054 BestPrefixIsFramework =
true;
2061 if (!BestPrefixLength && CheckDir(path::parent_path(MainFile))) {
2064 BestPrefixIsFramework =
false;
2069 StringRef
Filename =
File.drop_front(BestPrefixLength);
2071 if (!DL.isHeaderMap())
2074 StringRef SpelledFilename =
2075 DL.getHeaderMap()->reverseLookupFilename(
Filename);
2076 if (!SpelledFilename.empty()) {
2078 BestPrefixIsFramework =
false;
2085 bool IsPrivateHeader;
2087 if (BestPrefixIsFramework &&
2092 return path::convert_to_slash(
Filename);
Defines the Diagnostic-related interfaces.
Defines the clang::FileManager interface and associated types.
Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.
llvm::MachO::Target Target
Defines the clang::Module class, which describes a module in the source code.
Defines the clang::Preprocessor interface.
Defines the SourceManager interface.
constexpr bool has_value() const
Concrete class used by the front-end to report problems and issues.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
bool isIgnored(unsigned DiagID, SourceLocation Loc) const
Determine whether the diagnostic is known to be ignored.
A reference to a DirectoryEntry that includes the name of the directory as it was accessed by the Fil...
StringRef getName() const
Cached information about one directory (either on disk or in the virtual file system).
DirectoryLookup - This class represents one entry in the search list that specifies the search order ...
SrcMgr::CharacteristicKind getDirCharacteristic() const
DirCharacteristic - The type of directory this is, one of the DirType enum values.
OptionalFileEntryRef LookupFile(StringRef &Filename, HeaderSearch &HS, SourceLocation IncludeLoc, SmallVectorImpl< char > *SearchPath, SmallVectorImpl< char > *RelativePath, Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule, bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound, bool &IsInHeaderMap, SmallVectorImpl< char > &MappedName, bool OpenFile=true) const
LookupFile - Lookup the specified file in this search path, returning it if it exists or returning nu...
bool isFramework() const
isFramework - True if this is a framework directory.
bool isSystemHeaderDirectory() const
Whether this describes a system header directory.
OptionalDirectoryEntryRef getFrameworkDirRef() const
void setSearchedAllModuleMaps(bool SAMM)
Specify whether we have already searched all of the subdirectories for module maps.
bool isHeaderMap() const
isHeaderMap - Return true if this is a header map, not a normal directory.
StringRef getName() const
getName - Return the directory or filename corresponding to this lookup object.
OptionalDirectoryEntryRef getDirRef() const
bool haveSearchedAllModuleMaps() const
Determine whether we have already searched this entire directory for module maps.
const DirectoryEntry * getDir() const
getDir - Return the directory that this entry refers to.
bool isNormalDir() const
isNormalDir - Return true if this is a normal directory, not a header map.
const HeaderMap * getHeaderMap() const
getHeaderMap - Return the directory that this entry refers to.
Abstract interface for external sources of preprocessor information.
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
StringRef getName() const
The name of this FileEntry.
Cached information about one file (either on disk or in the virtual file system).
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Implements support for file system lookup, file system caching, and directory search management.
llvm::vfs::FileSystem & getVirtualFileSystem() const
OptionalFileEntryRef getOptionalFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Get a FileEntryRef if it exists, without doing anything on error.
StringRef getCanonicalName(DirectoryEntryRef Dir)
Retrieve the canonical name for a given directory.
bool makeAbsolutePath(SmallVectorImpl< char > &Path) const
Makes Path absolute taking into account FileSystemOptions and the working directory option.
FileEntryRef getVirtualFileRef(StringRef Filename, off_t Size, time_t ModificationTime)
Retrieve a file entry for a "virtual" file that acts as if there were a file with the given name on d...
OptionalDirectoryEntryRef getOptionalDirectoryRef(StringRef DirName, bool CacheFailure=true)
Get a DirectoryEntryRef if it exists, without doing anything on error.
LLVM_DEPRECATED("Functions returning DirectoryEntry are deprecated.", "getOptionalDirectoryRef()") llvm LLVM_DEPRECATED("Functions returning FileEntry are deprecated.", "getOptionalFileRef()") llvm llvm::Expected< FileEntryRef > getFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true, bool IsText=true)
Lookup, cache, and verify the specified directory (real or virtual).
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string.
One of these records is kept for each identifier that is lexed.
bool isOutOfDate() const
Determine whether the information for this identifier is out of date with respect to the external sou...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
bool isValid() const
Whether this pointer is non-NULL.
IdentifierInfo * getPtr() const
bool isID() const
Whether this pointer is currently stored as ID.
Module * findModule(StringRef Name) const
Retrieve a module with the given name.
KnownHeader findModuleForHeader(FileEntryRef File, bool AllowTextual=false, bool AllowExcluded=false)
Retrieve the module that owns the given header file, if any.
static bool isModular(ModuleHeaderRole Role)
Check if the header with the given role is a modular one.
void resolveHeaderDirectives(const FileEntry *File) const
Resolve all lazy header directives for the specified file.
ArrayRef< KnownHeader > findResolvedModulesForHeader(FileEntryRef File) const
Like findAllModulesForHeader, but do not attempt to infer module ownership from umbrella headers if w...
OptionalFileEntryRef getModuleMapFileForUniquing(const Module *M) const
bool isBuiltinHeader(FileEntryRef File)
Is this a compiler builtin header?
bool parseModuleMapFile(FileEntryRef File, bool IsSystem, DirectoryEntryRef HomeDir, FileID ID=FileID(), unsigned *Offset=nullptr, SourceLocation ExternModuleLoc=SourceLocation())
Parse the given module map file, and record any modules we encounter.
void setTarget(const TargetInfo &Target)
Set the target information.
ModuleHeaderRole
Flags describing the role of a module header.
@ ExcludedHeader
This header is explicitly excluded from the module.
@ TextualHeader
This header is part of the module (for layering purposes) but should be textually included.
ArrayRef< KnownHeader > findAllModulesForHeader(FileEntryRef File)
Retrieve all the modules that contain the given header file.
llvm::iterator_range< module_iterator > modules() const
bool resolveUses(Module *Mod, bool Complain)
Resolve all of the unresolved uses in the given module.
Describes a module or submodule.
bool directlyUses(const Module *Requested)
Determine whether this module has declared its intention to directly use another module.
std::string Name
The name of this module.
unsigned NoUndeclaredIncludes
Whether files in this module can only include non-modular headers and headers from used modules.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
bool markIncluded(FileEntryRef File)
Mark the file as included.
bool isMacroDefinedInLocalModule(const IdentifierInfo *II, Module *M)
Determine whether II is defined as a macro within the module M, if that is a module that we've alread...
bool isMacroDefined(StringRef Id)
bool alreadyIncluded(FileEntryRef File) const
Return true if this header has already been included.
Encodes a location in the source.
This class handles loading and caching of source files into memory.
Exposes information about the current target.
The JSON file list parser is used to communicate input to InstallAPI.
@ Private
'private' clause, allowed on 'parallel', 'serial', 'loop', 'parallel loop', and 'serial loop' constru...
@ External
External linkage, which indicates that the entity can be referred to from other translation units.
@ Result
The result type of a method or function.
This structure is used to record entries in our framework cache.
bool IsUserSpecifiedSystemFramework
Whether this framework has been "user-specified" to be treated as if it were a system framework (even...
OptionalDirectoryEntryRef Directory
The directory entry which should be used for the cached framework.