26#include "llvm/ADT/APInt.h"
27#include "llvm/ADT/Hashing.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/ADT/STLExtras.h"
33#include "llvm/Support/Allocator.h"
34#include "llvm/Support/Capacity.h"
35#include "llvm/Support/Errc.h"
36#include "llvm/Support/ErrorHandling.h"
37#include "llvm/Support/FileSystem.h"
38#include "llvm/Support/Path.h"
39#include "llvm/Support/VirtualFileSystem.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.");
65 assert(
External &&
"We must have an external source if we have a "
66 "controlling macro that is out of date.");
86 : HSOpts(
std::move(HSOpts)), Diags(Diags),
87 FileMgr(SourceMgr.getFileManager()), FrameworkMap(64),
88 ModMap(SourceMgr, Diags, LangOpts,
Target, *this) {}
91 llvm::errs() <<
"\n*** HeaderSearch Stats:\n"
92 << FileInfo.size() <<
" files tracked.\n";
93 unsigned NumOnceOnlyFiles = 0;
94 for (
unsigned i = 0, e = FileInfo.size(); i != e; ++i)
95 NumOnceOnlyFiles += (FileInfo[i].isPragmaOnce || FileInfo[i].isImport);
96 llvm::errs() <<
" " << NumOnceOnlyFiles <<
" #import/#pragma once files.\n";
98 llvm::errs() <<
" " << NumIncluded <<
" #include/#include_next/#import.\n"
99 <<
" " << NumMultiIncludeFileOptzn
100 <<
" #includes skipped due to the multi-include optimization.\n";
102 llvm::errs() << NumFrameworkLookups <<
" framework lookups.\n"
103 << NumSubFrameworkLookups <<
" subframework lookups.\n";
107 std::vector<DirectoryLookup> dirs,
unsigned int angledDirIdx,
108 unsigned int systemDirIdx,
109 llvm::DenseMap<unsigned int, unsigned int> searchDirToHSEntry) {
110 assert(angledDirIdx <= systemDirIdx && systemDirIdx <= dirs.size() &&
111 "Directory indices are unordered");
112 SearchDirs = std::move(dirs);
113 SearchDirsUsage.assign(SearchDirs.size(),
false);
114 AngledDirIdx = angledDirIdx;
115 SystemDirIdx = systemDirIdx;
116 SearchDirToHSEntry = std::move(searchDirToHSEntry);
118 indexInitialHeaderMaps();
122 unsigned idx = isAngled ? SystemDirIdx : AngledDirIdx;
123 SearchDirs.insert(SearchDirs.begin() + idx, dir);
124 SearchDirsUsage.insert(SearchDirsUsage.begin() + idx,
false);
131 std::vector<bool> UserEntryUsage(HSOpts->UserEntries.size());
132 for (
unsigned I = 0, E = SearchDirsUsage.size(); I < E; ++I) {
134 if (SearchDirsUsage[I]) {
135 auto UserEntryIdxIt = SearchDirToHSEntry.find(I);
137 if (UserEntryIdxIt != SearchDirToHSEntry.end())
138 UserEntryUsage[UserEntryIdxIt->second] =
true;
141 return UserEntryUsage;
145 std::vector<bool> VFSUsage;
152 RootFS.visit([&](llvm::vfs::FileSystem &FS) {
153 if (
auto *RFS = dyn_cast<llvm::vfs::RedirectingFileSystem>(&FS)) {
154 VFSUsage.push_back(RFS->hasBeenUsed());
155 RFS->clearHasBeenUsed();
159 "A different number of RedirectingFileSystem's were present than "
160 "-ivfsoverlay options passed to Clang!");
162 std::reverse(VFSUsage.begin(), VFSUsage.end());
171 if (!HeaderMaps.empty()) {
172 for (
unsigned i = 0, e = HeaderMaps.size(); i != e; ++i)
175 if (HeaderMaps[i].first == FE)
176 return HeaderMaps[i].second.get();
180 HeaderMaps.emplace_back(FE, std::move(HM));
181 return HeaderMaps.back().second.get();
190 for (
auto &HM : HeaderMaps)
191 Names.push_back(std::string(HM.first.getName()));
207 auto i(HSOpts->PrebuiltModuleFiles.find(ModuleName));
208 if (i != HSOpts->PrebuiltModuleFiles.end())
211 if (FileMapOnly || HSOpts->PrebuiltModulePaths.empty())
216 for (
const std::string &Dir : HSOpts->PrebuiltModulePaths) {
218 llvm::sys::fs::make_absolute(
Result);
219 if (ModuleName.contains(
':'))
223 llvm::sys::path::append(
Result, ModuleName.split(
':').first +
"-" +
224 ModuleName.split(
':').second +
227 llvm::sys::path::append(
Result, ModuleName +
".pcm");
229 return std::string(
Result);
239 StringRef ModuleMapPath =
ModuleMap->getName();
240 StringRef ModuleCacheHash = HSOpts->DisableModuleHash ?
"" :
getModuleHash();
241 for (
const std::string &Dir : HSOpts->PrebuiltModulePaths) {
243 llvm::sys::fs::make_absolute(CachePath);
244 llvm::sys::path::append(CachePath, ModuleCacheHash);
246 getCachedModuleFileNameImpl(ModuleName, ModuleMapPath, CachePath);
254 StringRef ModuleMapPath) {
255 return getCachedModuleFileNameImpl(ModuleName, ModuleMapPath,
259std::string HeaderSearch::getCachedModuleFileNameImpl(StringRef ModuleName,
260 StringRef ModuleMapPath,
261 StringRef CachePath) {
264 if (CachePath.empty())
268 llvm::sys::fs::make_absolute(
Result);
270 if (HSOpts->DisableModuleHash) {
271 llvm::sys::path::append(
Result, ModuleName +
".pcm");
281 if (
getModuleMap().canonicalizeModuleMapPath(CanonicalPath))
284 llvm::hash_code Hash = llvm::hash_combine(CanonicalPath.str().lower());
287 llvm::APInt(64,
size_t(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){
381 if (Dir.haveSearchedAllModuleMaps())
386 if (AllowExtraModuleMapSearch)
387 loadSubdirectoryModuleMaps(Dir);
398void HeaderSearch::indexInitialHeaderMaps() {
399 llvm::StringMap<unsigned, llvm::BumpPtrAllocator> Index(SearchDirs.size());
402 for (
unsigned i = 0; i != SearchDirs.size(); ++i) {
403 auto &Dir = SearchDirs[i];
408 if (!Dir.isHeaderMap()) {
409 SearchDirHeaderMapIndex = std::move(Index);
410 FirstNonHeaderMapSearchDirIdx = i;
415 auto Callback = [&](StringRef
Filename) {
416 Index.try_emplace(
Filename.lower(), i);
418 Dir.getHeaderMap()->forEachKey(Callback);
433 assert(
isHeaderMap() &&
"Unknown DirectoryLookup");
439 bool IsSystemHeaderDir,
Module *RequestingModule,
441 bool CacheFailures ) {
448 std::error_code EC = llvm::errorToErrorCode(
File.takeError());
449 if (EC != llvm::errc::no_such_file_or_directory &&
450 EC != llvm::errc::invalid_argument &&
451 EC != llvm::errc::is_a_directory && EC != llvm::errc::not_a_directory) {
452 Diags.
Report(IncludeLoc, diag::err_cannot_open_file)
459 if (!findUsableModuleForHeader(
460 *
File, Dir ? Dir :
File->getFileEntry().getDir(), RequestingModule,
461 SuggestedModule, IsSystemHeaderDir))
473 bool &InUserSpecifiedSystemFramework,
bool &IsFrameworkFound,
475 bool OpenFile)
const {
476 InUserSpecifiedSystemFramework =
false;
477 IsInHeaderMap =
false;
484 llvm::sys::path::append(TmpDir,
Filename);
488 SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
491 RelativePath->clear();
495 return HS.getFileAndSuggestModule(
497 RequestingModule, SuggestedModule, OpenFile);
501 return DoFrameworkLookup(
Filename, HS, SearchPath, RelativePath,
502 RequestingModule, SuggestedModule,
503 InUserSpecifiedSystemFramework, IsFrameworkFound);
505 assert(
isHeaderMap() &&
"Unknown directory lookup");
512 IsInHeaderMap =
true;
514 auto FixupSearchPathAndFindUsableModule =
517 StringRef SearchPathRef(
getName());
519 SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
522 RelativePath->clear();
525 if (!HS.findUsableModuleForHeader(
File,
File.getFileEntry().getDir(),
526 RequestingModule, SuggestedModule,
536 if (llvm::sys::path::is_relative(Dest)) {
537 MappedName.append(Dest.begin(), Dest.end());
538 Filename = StringRef(MappedName.begin(), MappedName.size());
543 return FixupSearchPathAndFindUsableModule(*Res);
563 assert(llvm::sys::path::extension(DirName) ==
".framework" &&
564 "Not a framework directory");
586 DirName = llvm::sys::path::parent_path(DirName);
597 if (llvm::sys::path::extension(DirName) ==
".framework") {
598 SubmodulePath.push_back(std::string(llvm::sys::path::stem(DirName)));
599 TopFrameworkDir = *Dir;
603 return TopFrameworkDir;
607 bool HasSuggestedModule) {
608 return HasSuggestedModule ||
618 bool &InUserSpecifiedSystemFramework,
bool &IsFrameworkFound)
const {
622 size_t SlashPos =
Filename.find(
'/');
623 if (SlashPos == StringRef::npos)
640 if (FrameworkName.empty() || FrameworkName.back() !=
'/')
641 FrameworkName.push_back(
'/');
644 StringRef ModuleName(
Filename.begin(), SlashPos);
645 FrameworkName += ModuleName;
648 FrameworkName +=
".framework/";
652 ++NumFrameworkLookups;
667 SystemFrameworkMarker +=
".system_framework";
668 if (llvm::sys::fs::exists(SystemFrameworkMarker)) {
679 RelativePath->clear();
684 unsigned OrigSize = FrameworkName.size();
686 FrameworkName +=
"Headers/";
691 SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1);
700 const char *
Private =
"Private";
701 FrameworkName.insert(FrameworkName.begin()+OrigSize,
Private,
704 SearchPath->insert(SearchPath->begin()+OrigSize,
Private,
714 StringRef FrameworkPath =
File->getDir().getName();
715 bool FoundFramework =
false;
724 if (llvm::sys::path::extension(FrameworkPath) ==
".framework") {
725 FoundFramework =
true;
730 FrameworkPath = llvm::sys::path::parent_path(FrameworkPath);
731 if (FrameworkPath.empty())
736 if (FoundFramework) {
737 if (!HS.findUsableModuleForFrameworkHeader(*
File, FrameworkPath,
739 SuggestedModule, IsSystem))
742 if (!HS.findUsableModuleForHeader(*
File,
getDir(), RequestingModule,
743 SuggestedModule, IsSystem))
752void HeaderSearch::cacheLookupSuccess(LookupFileCacheInfo &CacheLookup,
755 CacheLookup.HitIt = HitIt;
756 noteLookupUsage(HitIt.Idx, Loc);
759void HeaderSearch::noteLookupUsage(
unsigned HitIdx,
SourceLocation Loc) {
760 SearchDirsUsage[HitIdx] =
true;
762 auto UserEntryIdxIt = SearchDirToHSEntry.find(HitIdx);
763 if (UserEntryIdxIt != SearchDirToHSEntry.end())
764 Diags.
Report(Loc, diag::remark_pp_search_path_usage)
765 << HSOpts->UserEntries[UserEntryIdxIt->second].Path;
783 if (MSFE && FE != *MSFE) {
784 Diags.
Report(IncludeLoc, diag::ext_pp_include_search_ms) << MSFE->
getName();
790static const char *
copyString(StringRef Str, llvm::BumpPtrAllocator &Alloc) {
791 assert(!Str.empty());
792 char *CopyStr = Alloc.Allocate<
char>(Str.size()+1);
793 std::copy(Str.begin(), Str.end(), CopyStr);
794 CopyStr[Str.size()] =
'\0';
801 using namespace llvm::sys;
802 path::const_iterator I = path::begin(Path);
803 path::const_iterator E = path::end(Path);
804 IsPrivateHeader =
false;
816 if (*I ==
"Headers") {
818 }
else if (*I ==
"PrivateHeaders") {
820 IsPrivateHeader =
true;
821 }
else if (I->ends_with(
".framework")) {
822 StringRef Name = I->drop_back(10);
824 FrameworkName.clear();
825 FrameworkName.append(Name.begin(), Name.end());
826 IncludeSpelling.clear();
827 IncludeSpelling.append(Name.begin(), Name.end());
829 }
else if (FoundComp >= 2) {
830 IncludeSpelling.push_back(
'/');
831 IncludeSpelling.append(I->begin(), I->end());
836 return !FrameworkName.empty() && FoundComp >= 2;
841 StringRef Includer, StringRef IncludeFilename,
843 bool FoundByHeaderMap =
false) {
844 bool IsIncluderPrivateHeader =
false;
848 FromIncludeSpelling))
850 bool IsIncludeePrivateHeader =
false;
851 bool IsIncludeeInFramework =
853 ToFramework, ToIncludeSpelling);
855 if (!isAngled && !FoundByHeaderMap) {
857 if (IsIncludeeInFramework) {
858 NewInclude += ToIncludeSpelling;
861 NewInclude += IncludeFilename;
864 Diags.
Report(IncludeLoc, diag::warn_quoted_include_in_framework_header)
872 if (!IsIncluderPrivateHeader && IsIncludeeInFramework &&
873 IsIncludeePrivateHeader && FromFramework == ToFramework)
874 Diags.
Report(IncludeLoc, diag::warn_framework_include_private_from_public)
886 ArrayRef<std::pair<OptionalFileEntryRef, DirectoryEntryRef>> Includers,
889 bool *IsMapped,
bool *IsFrameworkFound,
bool SkipCache,
890 bool BuildSystemModule,
bool OpenFile,
bool CacheFailures) {
897 if (IsFrameworkFound)
898 *IsFrameworkFound =
false;
904 if (llvm::sys::path::is_absolute(
Filename)) {
914 RelativePath->clear();
918 return getFileAndSuggestModule(
Filename, IncludeLoc,
nullptr,
920 RequestingModule, SuggestedModule, OpenFile,
933 if (!Includers.empty() && !isAngled) {
936 for (
const auto &IncluderAndDir : Includers) {
940 TmpDir = IncluderAndDir.second.getName();
941 llvm::sys::path::append(TmpDir,
Filename);
950 bool IncluderIsSystemHeader =
954 TmpDir, IncludeLoc, IncluderAndDir.second, IncluderIsSystemHeader,
955 RequestingModule, SuggestedModule)) {
957 assert(
First &&
"only first includer can have no file");
968 unsigned DirInfo = FromHFI.
DirInfo;
978 StringRef SearchPathRef(IncluderAndDir.second.getName());
980 SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
983 RelativePath->clear();
988 IncluderAndDir.second.getName(),
Filename,
996 if (Diags.
isIgnored(diag::ext_pp_include_search_ms, IncludeLoc)) {
1000 if (SuggestedModule) {
1001 MSSuggestedModule = *SuggestedModule;
1026 LookupFileCacheInfo &CacheLookup = LookupFileCache[
Filename];
1031 if (CacheLookup.StartIt == NextIt &&
1032 CacheLookup.RequestingModule == RequestingModule) {
1034 if (CacheLookup.HitIt)
1035 It = CacheLookup.HitIt;
1036 if (CacheLookup.MappedName) {
1045 CacheLookup.reset(RequestingModule, NextIt);
1051 auto Iter = SearchDirHeaderMapIndex.find(
Filename.lower());
1052 if (
Iter == SearchDirHeaderMapIndex.end())
1061 CacheLookup.reset(RequestingModule, NextIt);
1068 bool InUserSpecifiedSystemFramework =
false;
1069 bool IsInHeaderMap =
false;
1070 bool IsFrameworkFoundInDir =
false;
1072 Filename, *
this, IncludeLoc, SearchPath, RelativePath, RequestingModule,
1073 SuggestedModule, InUserSpecifiedSystemFramework, IsFrameworkFoundInDir,
1074 IsInHeaderMap, MappedName, OpenFile);
1075 if (!MappedName.empty()) {
1076 assert(IsInHeaderMap &&
"MappedName should come from a header map");
1077 CacheLookup.MappedName =
1078 copyString(MappedName, LookupFileCache.getAllocator());
1084 *IsMapped |= (!MappedName.empty() || (IsInHeaderMap &&
File));
1085 if (IsFrameworkFound)
1089 *IsFrameworkFound |= (IsFrameworkFoundInDir && !CacheLookup.MappedName);
1099 HFI.
DirInfo = CurDir->getDirCharacteristic();
1109 for (
unsigned j = SystemHeaderPrefixes.size(); j; --j) {
1110 if (
Filename.starts_with(SystemHeaderPrefixes[j - 1].first)) {
1120 if (CurDir->isHeaderMap() && isAngled) {
1121 size_t SlashPos =
Filename.find(
'/');
1122 if (SlashPos != StringRef::npos)
1125 if (CurDir->isIndexHeaderMap())
1127 }
else if (CurDir->isFramework()) {
1128 size_t SlashPos =
Filename.find(
'/');
1129 if (SlashPos != StringRef::npos)
1135 if (SuggestedModule)
1136 *SuggestedModule = MSSuggestedModule;
1140 bool FoundByHeaderMap = !IsMapped ?
false : *IsMapped;
1141 if (!Includers.empty())
1143 Includers.front().second.getName(),
Filename,
1144 *
File, isAngled, FoundByHeaderMap);
1147 cacheLookupSuccess(CacheLookup, It, IncludeLoc);
1155 if (!Includers.empty() && Includers.front().first && !isAngled &&
1160 ScratchFilename += IncludingHFI.
Framework;
1161 ScratchFilename +=
'/';
1165 ScratchFilename, IncludeLoc,
true, FromDir, &CurDir,
1166 Includers.front(), SearchPath, RelativePath, RequestingModule,
1167 SuggestedModule, IsMapped,
nullptr);
1170 File ? &
File->getFileEntry() :
nullptr,
1172 if (SuggestedModule)
1173 *SuggestedModule = MSSuggestedModule;
1177 cacheLookupSuccess(LookupFileCache[
Filename],
1178 LookupFileCache[ScratchFilename].HitIt, IncludeLoc);
1185 if (SuggestedModule)
1186 *SuggestedModule = MSSuggestedModule;
1192 return std::nullopt;
1206 size_t SlashPos =
Filename.find(
'/');
1207 if (SlashPos == StringRef::npos)
1208 return std::nullopt;
1211 StringRef ContextName = ContextFileEnt.
getName();
1214 const unsigned DotFrameworkLen = 10;
1215 auto FrameworkPos = ContextName.find(
".framework");
1216 if (FrameworkPos == StringRef::npos ||
1217 (ContextName[FrameworkPos + DotFrameworkLen] !=
'/' &&
1218 ContextName[FrameworkPos + DotFrameworkLen] !=
'\\'))
1219 return std::nullopt;
1223 DotFrameworkLen + 1);
1226 FrameworkName +=
"Frameworks/";
1228 FrameworkName +=
".framework/";
1231 *FrameworkMap.insert(std::make_pair(
Filename.substr(0, SlashPos),
1235 if (CacheLookup.second.Directory &&
1236 CacheLookup.first().size() == FrameworkName.size() &&
1237 memcmp(CacheLookup.first().data(), &FrameworkName[0],
1238 CacheLookup.first().size()) != 0)
1239 return std::nullopt;
1242 if (!CacheLookup.second.Directory) {
1243 ++NumSubFrameworkLookups;
1248 return std::nullopt;
1252 CacheLookup.second.Directory = Dir;
1257 RelativePath->clear();
1263 HeadersFilename +=
"Headers/";
1265 SearchPath->clear();
1267 SearchPath->append(HeadersFilename.begin(), HeadersFilename.end()-1);
1274 HeadersFilename = FrameworkName;
1275 HeadersFilename +=
"PrivateHeaders/";
1277 SearchPath->clear();
1279 SearchPath->append(HeadersFilename.begin(), HeadersFilename.end()-1);
1286 return std::nullopt;
1297 FrameworkName.pop_back();
1298 if (!findUsableModuleForFrameworkHeader(*
File, FrameworkName,
1299 RequestingModule, SuggestedModule,
1301 return std::nullopt;
1314 assert(OtherHFI.
External &&
"expected to merge external HFI");
1337 if (FE.
getUID() >= FileInfo.size())
1338 FileInfo.resize(FE.
getUID() + 1);
1344 if (ExternalHFI.IsValid) {
1346 if (ExternalHFI.External)
1364 if (FE.
getUID() >= FileInfo.size()) {
1367 FileInfo.resize(FE.
getUID() + 1);
1370 HFI = &FileInfo[FE.
getUID()];
1375 if (ExternalHFI.IsValid) {
1377 if (ExternalHFI.External)
1381 }
else if (FE.
getUID() >= FileInfo.size()) {
1384 HFI = &FileInfo[FE.
getUID()];
1398 return HFI->isPragmaOnce || HFI->ControllingMacro ||
1399 HFI->ControllingMacroID;
1405 bool isCompilingModuleHeader) {
1409 if (!isCompilingModuleHeader) {
1410 if (!isModularHeader)
1413 if (HFI && HFI->isModuleHeader)
1418 HFI.isModuleHeader |= isModularHeader;
1419 HFI.isCompilingModuleHeader |= isCompilingModuleHeader;
1424 bool ModulesEnabled,
Module *M,
1425 bool &IsFirstIncludeOfFile) {
1428 IsFirstIncludeOfFile =
false;
1435 auto TryEnterImported = [&]() ->
bool {
1436 if (!ModulesEnabled)
1457 bool TryEnterHdr =
false;
1496 ++NumMultiIncludeFileOptzn;
1507 return SearchDirs.capacity()
1508 + llvm::capacity_in_bytes(FileInfo)
1509 + llvm::capacity_in_bytes(HeaderMaps)
1510 + LookupFileCache.getAllocator().getTotalMemory()
1511 + FrameworkMap.getAllocator().getTotalMemory();
1515 return &DL - &*SearchDirs.begin();
1519 return FrameworkNames.insert(Framework).first->first();
1523 auto It = IncludeNames.find(
File);
1524 if (It == IncludeNames.end())
1532 if (!HSOpts->ImplicitModuleMaps)
1540 DirName = llvm::sys::path::parent_path(DirName);
1541 if (DirName.empty())
1551 llvm::sys::path::extension(Dir->getName()) ==
1553 case LMM_NewlyLoaded:
1554 case LMM_AlreadyLoaded:
1557 for (
unsigned I = 0, N = FixUpDirectories.size(); I != N; ++I)
1558 DirectoryHasModuleMap[FixUpDirectories[I]] =
true;
1561 case LMM_NoDirectory:
1562 case LMM_InvalidModuleMap:
1572 FixUpDirectories.push_back(*Dir);
1578 bool AllowExcluded)
const {
1608 Module *RequestingModule,
1624 if (SuggestedModule)
1634 if (SuggestedModule)
1642bool HeaderSearch::findUsableModuleForHeader(
1653bool HeaderSearch::findUsableModuleForFrameworkHeader(
1662 assert(TopFrameworkDir &&
"Could not find the top-most framework dir");
1665 StringRef ModuleName = llvm::sys::path::stem(TopFrameworkDir->
getName());
1669 loadFrameworkModule(ModuleName, *TopFrameworkDir, IsSystemFramework);
1683 StringRef
Filename = llvm::sys::path::filename(
File.getName());
1686 llvm::sys::path::append(PrivateFilename,
"module_private.map");
1687 else if (
Filename ==
"module.modulemap")
1688 llvm::sys::path::append(PrivateFilename,
"module.private.modulemap");
1690 return std::nullopt;
1694 Diags.
Report(diag::warn_deprecated_module_dot_map)
1695 << PrivateFilename << 1
1696 <<
File.getDir().getName().ends_with(
".framework");
1702 FileID ID,
unsigned *Offset,
1703 StringRef OriginalModuleMapFile) {
1710 if (!OriginalModuleMapFile.empty()) {
1714 llvm::sys::path::parent_path(OriginalModuleMapFile));
1717 Dir = FakeFile.getDir();
1720 Dir =
File.getDir();
1723 assert(Dir &&
"parent must exist");
1724 StringRef DirName(Dir->
getName());
1725 if (llvm::sys::path::filename(DirName) ==
"Modules") {
1726 DirName = llvm::sys::path::parent_path(DirName);
1727 if (DirName.ends_with(
".framework"))
1732 assert(Dir &&
"parent must exist");
1736 assert(Dir &&
"module map home directory must exist");
1737 switch (loadModuleMapFileImpl(
File, IsSystem, *Dir, ID, Offset)) {
1738 case LMM_AlreadyLoaded:
1739 case LMM_NewlyLoaded:
1741 case LMM_NoDirectory:
1742 case LMM_InvalidModuleMap:
1745 llvm_unreachable(
"Unknown load module map result");
1748HeaderSearch::LoadModuleMapResult
1754 auto AddResult = LoadedModuleMaps.insert(std::make_pair(
File,
true));
1755 if (!AddResult.second)
1756 return AddResult.first->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
1759 LoadedModuleMaps[
File] =
false;
1760 return LMM_InvalidModuleMap;
1767 LoadedModuleMaps[
File] =
false;
1768 return LMM_InvalidModuleMap;
1773 return LMM_NewlyLoaded;
1778 if (!HSOpts->ImplicitModuleMaps)
1779 return std::nullopt;
1784 llvm::sys::path::append(ModuleMapFileName,
"Modules");
1785 llvm::sys::path::append(ModuleMapFileName,
"module.modulemap");
1790 ModuleMapFileName = Dir.
getName();
1791 llvm::sys::path::append(ModuleMapFileName,
"module.map");
1793 Diags.
Report(diag::warn_deprecated_module_dot_map)
1794 << ModuleMapFileName << 0 << IsFramework;
1801 ModuleMapFileName = Dir.
getName();
1802 llvm::sys::path::append(ModuleMapFileName,
"Modules",
1803 "module.private.modulemap");
1807 return std::nullopt;
1814 case LMM_InvalidModuleMap:
1816 if (HSOpts->ImplicitModuleMaps)
1817 ModMap.inferFrameworkModule(Dir, IsSystem,
nullptr);
1820 case LMM_NoDirectory:
1823 case LMM_AlreadyLoaded:
1824 case LMM_NewlyLoaded:
1831HeaderSearch::LoadModuleMapResult
1837 return LMM_NoDirectory;
1840HeaderSearch::LoadModuleMapResult
1843 auto KnownDir = DirectoryHasModuleMap.find(Dir);
1844 if (KnownDir != DirectoryHasModuleMap.end())
1845 return KnownDir->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
1849 LoadModuleMapResult
Result =
1850 loadModuleMapFileImpl(*ModuleMapFile, IsSystem, Dir);
1854 if (
Result == LMM_NewlyLoaded)
1855 DirectoryHasModuleMap[Dir] =
true;
1856 else if (
Result == LMM_InvalidModuleMap)
1857 DirectoryHasModuleMap[Dir] =
false;
1860 return LMM_InvalidModuleMap;
1866 if (HSOpts->ImplicitModuleMaps) {
1869 bool IsSystem = DL.isSystemHeaderDirectory();
1870 if (DL.isFramework()) {
1873 llvm::sys::path::native(DL.getFrameworkDirRef()->getName(), DirNative);
1877 for (llvm::vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC),
1879 Dir != DirEnd && !EC; Dir.increment(EC)) {
1880 if (llvm::sys::path::extension(Dir->path()) !=
".framework")
1888 loadFrameworkModule(llvm::sys::path::stem(Dir->path()), *FrameworkDir,
1895 if (DL.isHeaderMap())
1903 loadSubdirectoryModuleMaps(DL);
1908 llvm::transform(ModMap.
modules(), std::back_inserter(Modules),
1909 [](
const auto &NameAndMod) { return NameAndMod.second; });
1913 if (!HSOpts->ImplicitModuleMaps)
1919 if (!DL.isNormalDir())
1928void HeaderSearch::loadSubdirectoryModuleMaps(
DirectoryLookup &SearchDir) {
1929 assert(HSOpts->ImplicitModuleMaps &&
1930 "Should not be loading subdirectory module maps");
1939 llvm::sys::path::native(Dir, DirNative);
1941 for (llvm::vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd;
1942 Dir != DirEnd && !EC; Dir.increment(EC)) {
1943 if (Dir->type() == llvm::sys::fs::file_type::regular_file)
1945 bool IsFramework = llvm::sys::path::extension(Dir->path()) ==
".framework";
1957 MainFile, IsAngled);
1961 llvm::StringRef
File, llvm::StringRef WorkingDir, llvm::StringRef MainFile,
1962 bool *IsAngled)
const {
1963 using namespace llvm::sys;
1969 path::remove_dots(FilePath,
true);
1970 path::native(FilePath, path::Style::posix);
1973 unsigned BestPrefixLength = 0;
1978 if (!WorkingDir.empty() && !path::is_absolute(Dir))
1979 fs::make_absolute(WorkingDir, Dir);
1980 path::remove_dots(Dir,
true);
1981 for (
auto NI = path::begin(
File), NE = path::end(
File),
1982 DI = path::begin(Dir), DE = path::end(Dir);
1983 NI != NE; ++NI, ++DI) {
1986 unsigned PrefixLength = NI - path::begin(
File);
1987 if (PrefixLength > BestPrefixLength) {
1988 BestPrefixLength = PrefixLength;
1995 if (NI->size() == 1 && DI->size() == 1 &&
1996 path::is_separator(NI->front()) && path::is_separator(DI->front()))
2002 if (NI->ends_with(
".sdk") && DI->ends_with(
".sdk")) {
2003 StringRef NBasename = path::stem(*NI);
2004 StringRef DBasename = path::stem(*DI);
2005 if (DBasename.starts_with(NBasename))
2015 bool BestPrefixIsFramework =
false;
2017 if (DL.isNormalDir()) {
2018 StringRef Dir = DL.getDirRef()->getName();
2019 if (CheckDir(Dir)) {
2021 *IsAngled = BestPrefixLength && isSystem(DL.getDirCharacteristic());
2022 BestPrefixIsFramework =
false;
2024 }
else if (DL.isFramework()) {
2025 StringRef Dir = DL.getFrameworkDirRef()->getName();
2026 if (CheckDir(Dir)) {
2029 *IsAngled = BestPrefixLength;
2030 BestPrefixIsFramework =
true;
2037 if (!BestPrefixLength && CheckDir(path::parent_path(MainFile))) {
2040 BestPrefixIsFramework =
false;
2045 StringRef
Filename =
File.drop_front(BestPrefixLength);
2047 if (!DL.isHeaderMap())
2050 StringRef SpelledFilename =
2051 DL.getHeaderMap()->reverseLookupFilename(
Filename);
2052 if (!SpelledFilename.empty()) {
2054 BestPrefixIsFramework =
false;
2061 bool IsPrivateHeader;
2063 if (BestPrefixIsFramework &&
2068 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.
llvm::ErrorOr< const DirectoryEntry * > getDirectory(StringRef DirName, bool CacheFailure=true)
Lookup, cache, and verify the specified directory (real or virtual).
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::Expected< FileEntryRef > getFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (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...
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
Get the module map file that (along with the module name) uniquely identifies this module.
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.
@ 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.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T -> getSizeExpr()))
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.