1afd1b1c9SEugene Zelenko //===- HeaderSearch.cpp - Resolve Header File Locations -------------------===//
27a51313dSChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67a51313dSChris Lattner //
77a51313dSChris Lattner //===----------------------------------------------------------------------===//
87a51313dSChris Lattner //
97a51313dSChris Lattner // This file implements the DirectoryLookup and HeaderSearch interfaces.
107a51313dSChris Lattner //
117a51313dSChris Lattner //===----------------------------------------------------------------------===//
127a51313dSChris Lattner
137a51313dSChris Lattner #include "clang/Lex/HeaderSearch.h"
14afd1b1c9SEugene Zelenko #include "clang/Basic/Diagnostic.h"
157a51313dSChris Lattner #include "clang/Basic/FileManager.h"
167a51313dSChris Lattner #include "clang/Basic/IdentifierTable.h"
17afd1b1c9SEugene Zelenko #include "clang/Basic/Module.h"
18afd1b1c9SEugene Zelenko #include "clang/Basic/SourceManager.h"
19afd1b1c9SEugene Zelenko #include "clang/Lex/DirectoryLookup.h"
202aedca34SRichard Smith #include "clang/Lex/ExternalPreprocessorSource.h"
213a02247dSChandler Carruth #include "clang/Lex/HeaderMap.h"
223a02247dSChandler Carruth #include "clang/Lex/HeaderSearchOptions.h"
230fafd34aSWill Wilson #include "clang/Lex/LexDiagnostic.h"
24afd1b1c9SEugene Zelenko #include "clang/Lex/ModuleMap.h"
2520e883e5SRichard Smith #include "clang/Lex/Preprocessor.h"
26beee15e7SBen Langmuir #include "llvm/ADT/APInt.h"
27beee15e7SBen Langmuir #include "llvm/ADT/Hashing.h"
287a51313dSChris Lattner #include "llvm/ADT/SmallString.h"
29afd1b1c9SEugene Zelenko #include "llvm/ADT/SmallVector.h"
30e8752a9dSVolodymyr Sapsai #include "llvm/ADT/Statistic.h"
31afd1b1c9SEugene Zelenko #include "llvm/ADT/StringRef.h"
3232c2ea5cSJan Svoboda #include "llvm/ADT/STLExtras.h"
33afd1b1c9SEugene Zelenko #include "llvm/Support/Allocator.h"
34ae63d101STed Kremenek #include "llvm/Support/Capacity.h"
354a0328c9SAlexey Bataev #include "llvm/Support/Errc.h"
36afd1b1c9SEugene Zelenko #include "llvm/Support/ErrorHandling.h"
373a02247dSChandler Carruth #include "llvm/Support/FileSystem.h"
383a02247dSChandler Carruth #include "llvm/Support/Path.h"
39fc51490bSJonas Devlieghere #include "llvm/Support/VirtualFileSystem.h"
40afd1b1c9SEugene Zelenko #include <algorithm>
41afd1b1c9SEugene Zelenko #include <cassert>
42afd1b1c9SEugene Zelenko #include <cstddef>
43c25d8a7eSChris Lattner #include <cstdio>
44afd1b1c9SEugene Zelenko #include <cstring>
45afd1b1c9SEugene Zelenko #include <string>
46afd1b1c9SEugene Zelenko #include <system_error>
47cfeacf56SBenjamin Kramer #include <utility>
48afd1b1c9SEugene Zelenko
497a51313dSChris Lattner using namespace clang;
507a51313dSChris Lattner
51e8752a9dSVolodymyr Sapsai #define DEBUG_TYPE "file-search"
52e8752a9dSVolodymyr Sapsai
53e8752a9dSVolodymyr Sapsai ALWAYS_ENABLED_STATISTIC(NumIncluded, "Number of attempted #includes.");
54e8752a9dSVolodymyr Sapsai ALWAYS_ENABLED_STATISTIC(
55e8752a9dSVolodymyr Sapsai NumMultiIncludeFileOptzn,
56e8752a9dSVolodymyr Sapsai "Number of #includes skipped due to the multi-include optimization.");
57e8752a9dSVolodymyr Sapsai ALWAYS_ENABLED_STATISTIC(NumFrameworkLookups, "Number of framework lookups.");
58e8752a9dSVolodymyr Sapsai ALWAYS_ENABLED_STATISTIC(NumSubFrameworkLookups,
59e8752a9dSVolodymyr Sapsai "Number of subframework lookups.");
60e8752a9dSVolodymyr Sapsai
6199734e76SDouglas Gregor const IdentifierInfo *
getControllingMacro(ExternalPreprocessorSource * External)622aedca34SRichard Smith HeaderFileInfo::getControllingMacro(ExternalPreprocessorSource *External) {
632aedca34SRichard Smith if (ControllingMacro) {
6459666777SChandler Carruth if (ControllingMacro->isOutOfDate()) {
6559666777SChandler Carruth assert(External && "We must have an external source if we have a "
6659666777SChandler Carruth "controlling macro that is out of date.");
672aedca34SRichard Smith External->updateOutOfDateIdentifier(
682aedca34SRichard Smith *const_cast<IdentifierInfo *>(ControllingMacro));
6959666777SChandler Carruth }
7099734e76SDouglas Gregor return ControllingMacro;
712aedca34SRichard Smith }
7299734e76SDouglas Gregor
7399734e76SDouglas Gregor if (!ControllingMacroID || !External)
74d2d442caSCraig Topper return nullptr;
7599734e76SDouglas Gregor
7699734e76SDouglas Gregor ControllingMacro = External->GetIdentifier(ControllingMacroID);
7799734e76SDouglas Gregor return ControllingMacro;
7899734e76SDouglas Gregor }
7999734e76SDouglas Gregor
80afd1b1c9SEugene Zelenko ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() = default;
8109b6989eSDouglas Gregor
HeaderSearch(std::shared_ptr<HeaderSearchOptions> HSOpts,SourceManager & SourceMgr,DiagnosticsEngine & Diags,const LangOptions & LangOpts,const TargetInfo * Target)829c28cb3fSDavid Blaikie HeaderSearch::HeaderSearch(std::shared_ptr<HeaderSearchOptions> HSOpts,
831f76c4e8SManuel Klimek SourceManager &SourceMgr, DiagnosticsEngine &Diags,
8489929282SDouglas Gregor const LangOptions &LangOpts,
8589929282SDouglas Gregor const TargetInfo *Target)
86cfeacf56SBenjamin Kramer : HSOpts(std::move(HSOpts)), Diags(Diags),
87cfeacf56SBenjamin Kramer FileMgr(SourceMgr.getFileManager()), FrameworkMap(64),
88afd1b1c9SEugene Zelenko ModMap(SourceMgr, Diags, LangOpts, Target, *this) {}
897a51313dSChris Lattner
PrintStats()907a51313dSChris Lattner void HeaderSearch::PrintStats() {
91e8752a9dSVolodymyr Sapsai llvm::errs() << "\n*** HeaderSearch Stats:\n"
92e8752a9dSVolodymyr Sapsai << FileInfo.size() << " files tracked.\n";
93f7202723SJan Svoboda unsigned NumOnceOnlyFiles = 0;
94f7202723SJan Svoboda for (unsigned i = 0, e = FileInfo.size(); i != e; ++i)
9564ebf313SVolodymyr Sapsai NumOnceOnlyFiles += (FileInfo[i].isPragmaOnce || FileInfo[i].isImport);
96f7202723SJan Svoboda llvm::errs() << " " << NumOnceOnlyFiles << " #import/#pragma once files.\n";
977a51313dSChris Lattner
98e8752a9dSVolodymyr Sapsai llvm::errs() << " " << NumIncluded << " #include/#include_next/#import.\n"
99e8752a9dSVolodymyr Sapsai << " " << NumMultiIncludeFileOptzn
100e8752a9dSVolodymyr Sapsai << " #includes skipped due to the multi-include optimization.\n";
1017a51313dSChris Lattner
102e8752a9dSVolodymyr Sapsai llvm::errs() << NumFrameworkLookups << " framework lookups.\n"
103e8752a9dSVolodymyr Sapsai << NumSubFrameworkLookups << " subframework lookups.\n";
1047a51313dSChris Lattner }
1057a51313dSChris Lattner
SetSearchPaths(std::vector<DirectoryLookup> dirs,unsigned int angledDirIdx,unsigned int systemDirIdx,bool noCurDirSearch,llvm::DenseMap<unsigned int,unsigned int> searchDirToHSEntry)106d5ba066cSJan Svoboda void HeaderSearch::SetSearchPaths(
107d5ba066cSJan Svoboda std::vector<DirectoryLookup> dirs, unsigned int angledDirIdx,
108d5ba066cSJan Svoboda unsigned int systemDirIdx, bool noCurDirSearch,
109d5ba066cSJan Svoboda llvm::DenseMap<unsigned int, unsigned int> searchDirToHSEntry) {
110d5ba066cSJan Svoboda assert(angledDirIdx <= systemDirIdx && systemDirIdx <= dirs.size() &&
111d5ba066cSJan Svoboda "Directory indices are unordered");
112ccd7e783SJan Svoboda SearchDirs = std::move(dirs);
113ccd7e783SJan Svoboda SearchDirsUsage.assign(SearchDirs.size(), false);
114d5ba066cSJan Svoboda AngledDirIdx = angledDirIdx;
115d5ba066cSJan Svoboda SystemDirIdx = systemDirIdx;
116d5ba066cSJan Svoboda NoCurDirSearch = noCurDirSearch;
117ccd7e783SJan Svoboda SearchDirToHSEntry = std::move(searchDirToHSEntry);
118d5ba066cSJan Svoboda //LookupFileCache.clear();
119d5ba066cSJan Svoboda }
120d5ba066cSJan Svoboda
AddSearchPath(const DirectoryLookup & dir,bool isAngled)121d5ba066cSJan Svoboda void HeaderSearch::AddSearchPath(const DirectoryLookup &dir, bool isAngled) {
122d5ba066cSJan Svoboda unsigned idx = isAngled ? SystemDirIdx : AngledDirIdx;
123ccd7e783SJan Svoboda SearchDirs.insert(SearchDirs.begin() + idx, dir);
124ccd7e783SJan Svoboda SearchDirsUsage.insert(SearchDirsUsage.begin() + idx, false);
125d5ba066cSJan Svoboda if (!isAngled)
126d5ba066cSJan Svoboda AngledDirIdx++;
127d5ba066cSJan Svoboda SystemDirIdx++;
128d5ba066cSJan Svoboda }
129d5ba066cSJan Svoboda
computeUserEntryUsage() const13044451351SJan Svoboda std::vector<bool> HeaderSearch::computeUserEntryUsage() const {
13144451351SJan Svoboda std::vector<bool> UserEntryUsage(HSOpts->UserEntries.size());
132ccd7e783SJan Svoboda for (unsigned I = 0, E = SearchDirsUsage.size(); I < E; ++I) {
133ccd7e783SJan Svoboda // Check whether this DirectoryLookup has been successfully used.
134ccd7e783SJan Svoboda if (SearchDirsUsage[I]) {
135ccd7e783SJan Svoboda auto UserEntryIdxIt = SearchDirToHSEntry.find(I);
13644451351SJan Svoboda // Check whether this DirectoryLookup maps to a HeaderSearch::UserEntry.
13744451351SJan Svoboda if (UserEntryIdxIt != SearchDirToHSEntry.end())
13844451351SJan Svoboda UserEntryUsage[UserEntryIdxIt->second] = true;
13944451351SJan Svoboda }
14044451351SJan Svoboda }
14144451351SJan Svoboda return UserEntryUsage;
14244451351SJan Svoboda }
14344451351SJan Svoboda
1447a51313dSChris Lattner /// CreateHeaderMap - This method returns a HeaderMap for the specified
145830885caSSylvestre Ledru /// FileEntry, uniquing them through the 'HeaderMaps' datastructure.
CreateHeaderMap(const FileEntry * FE)1467a51313dSChris Lattner const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) {
1477a51313dSChris Lattner // We expect the number of headermaps to be small, and almost always empty.
1487a51313dSChris Lattner // If it ever grows, use of a linear search should be re-evaluated.
1497a51313dSChris Lattner if (!HeaderMaps.empty()) {
1507a51313dSChris Lattner for (unsigned i = 0, e = HeaderMaps.size(); i != e; ++i)
1517a51313dSChris Lattner // Pointer equality comparison of FileEntries works because they are
1527a51313dSChris Lattner // already uniqued by inode.
1537a51313dSChris Lattner if (HeaderMaps[i].first == FE)
15448769770SFangrui Song return HeaderMaps[i].second.get();
1557a51313dSChris Lattner }
1567a51313dSChris Lattner
15748769770SFangrui Song if (std::unique_ptr<HeaderMap> HM = HeaderMap::Create(FE, FileMgr)) {
15848769770SFangrui Song HeaderMaps.emplace_back(FE, std::move(HM));
15948769770SFangrui Song return HeaderMaps.back().second.get();
1607a51313dSChris Lattner }
1617a51313dSChris Lattner
162d2d442caSCraig Topper return nullptr;
1637a51313dSChris Lattner }
1647a51313dSChris Lattner
1659fc8faf9SAdrian Prantl /// Get filenames for all registered header maps.
getHeaderMapFileNames(SmallVectorImpl<std::string> & Names) const166181225b8SBruno Cardoso Lopes void HeaderSearch::getHeaderMapFileNames(
167181225b8SBruno Cardoso Lopes SmallVectorImpl<std::string> &Names) const {
168181225b8SBruno Cardoso Lopes for (auto &HM : HeaderMaps)
169adcd0268SBenjamin Kramer Names.push_back(std::string(HM.first->getName()));
170181225b8SBruno Cardoso Lopes }
171181225b8SBruno Cardoso Lopes
getCachedModuleFileName(Module * Module)172d30446fdSBoris Kolpackov std::string HeaderSearch::getCachedModuleFileName(Module *Module) {
1739d6448b1SBen Langmuir const FileEntry *ModuleMap =
1749d6448b1SBen Langmuir getModuleMap().getModuleMapFileForUniquing(Module);
175d7969012SZezhengLi // The ModuleMap maybe a nullptr, when we load a cached C++ module without
176d7969012SZezhengLi // *.modulemap file. In this case, just return an empty string.
177d7969012SZezhengLi if (ModuleMap == nullptr)
178d7969012SZezhengLi return {};
179d30446fdSBoris Kolpackov return getCachedModuleFileName(Module->Name, ModuleMap->getName());
1801735f4e7SDouglas Gregor }
1811e44e022SDouglas Gregor
getPrebuiltModuleFileName(StringRef ModuleName,bool FileMapOnly)182d30446fdSBoris Kolpackov std::string HeaderSearch::getPrebuiltModuleFileName(StringRef ModuleName,
183d30446fdSBoris Kolpackov bool FileMapOnly) {
184d30446fdSBoris Kolpackov // First check the module name to pcm file map.
185ef83d46bSBenjamin Kramer auto i(HSOpts->PrebuiltModuleFiles.find(ModuleName));
186d30446fdSBoris Kolpackov if (i != HSOpts->PrebuiltModuleFiles.end())
187d30446fdSBoris Kolpackov return i->second;
188d30446fdSBoris Kolpackov
189d30446fdSBoris Kolpackov if (FileMapOnly || HSOpts->PrebuiltModulePaths.empty())
190afd1b1c9SEugene Zelenko return {};
19111f2a477SManman Ren
192d30446fdSBoris Kolpackov // Then go through each prebuilt module directory and try to find the pcm
193d30446fdSBoris Kolpackov // file.
19411f2a477SManman Ren for (const std::string &Dir : HSOpts->PrebuiltModulePaths) {
19511f2a477SManman Ren SmallString<256> Result(Dir);
19611f2a477SManman Ren llvm::sys::fs::make_absolute(Result);
197ee572129SChuanqi Xu if (ModuleName.contains(':'))
198ee572129SChuanqi Xu // The separator of C++20 modules partitions (':') is not good for file
199ee572129SChuanqi Xu // systems, here clang and gcc choose '-' by default since it is not a
200ee572129SChuanqi Xu // valid character of C++ indentifiers. So we could avoid conflicts.
201ee572129SChuanqi Xu llvm::sys::path::append(Result, ModuleName.split(':').first + "-" +
202ee572129SChuanqi Xu ModuleName.split(':').second +
203ee572129SChuanqi Xu ".pcm");
204ee572129SChuanqi Xu else
20511f2a477SManman Ren llvm::sys::path::append(Result, ModuleName + ".pcm");
20611f2a477SManman Ren if (getFileMgr().getFile(Result.str()))
207509e21a1SJonas Devlieghere return std::string(Result);
20811f2a477SManman Ren }
209ee572129SChuanqi Xu
210afd1b1c9SEugene Zelenko return {};
21111f2a477SManman Ren }
21211f2a477SManman Ren
getPrebuiltImplicitModuleFileName(Module * Module)21358c586e7SAlexandre Rames std::string HeaderSearch::getPrebuiltImplicitModuleFileName(Module *Module) {
21458c586e7SAlexandre Rames const FileEntry *ModuleMap =
21558c586e7SAlexandre Rames getModuleMap().getModuleMapFileForUniquing(Module);
21658c586e7SAlexandre Rames StringRef ModuleName = Module->Name;
21758c586e7SAlexandre Rames StringRef ModuleMapPath = ModuleMap->getName();
21858c586e7SAlexandre Rames StringRef ModuleCacheHash = HSOpts->DisableModuleHash ? "" : getModuleHash();
21958c586e7SAlexandre Rames for (const std::string &Dir : HSOpts->PrebuiltModulePaths) {
22058c586e7SAlexandre Rames SmallString<256> CachePath(Dir);
22158c586e7SAlexandre Rames llvm::sys::fs::make_absolute(CachePath);
22258c586e7SAlexandre Rames llvm::sys::path::append(CachePath, ModuleCacheHash);
22358c586e7SAlexandre Rames std::string FileName =
22458c586e7SAlexandre Rames getCachedModuleFileNameImpl(ModuleName, ModuleMapPath, CachePath);
22558c586e7SAlexandre Rames if (!FileName.empty() && getFileMgr().getFile(FileName))
22658c586e7SAlexandre Rames return FileName;
22758c586e7SAlexandre Rames }
22858c586e7SAlexandre Rames return {};
22958c586e7SAlexandre Rames }
23058c586e7SAlexandre Rames
getCachedModuleFileName(StringRef ModuleName,StringRef ModuleMapPath)231d30446fdSBoris Kolpackov std::string HeaderSearch::getCachedModuleFileName(StringRef ModuleName,
232d30446fdSBoris Kolpackov StringRef ModuleMapPath) {
23358c586e7SAlexandre Rames return getCachedModuleFileNameImpl(ModuleName, ModuleMapPath,
23458c586e7SAlexandre Rames getModuleCachePath());
23558c586e7SAlexandre Rames }
23658c586e7SAlexandre Rames
getCachedModuleFileNameImpl(StringRef ModuleName,StringRef ModuleMapPath,StringRef CachePath)23758c586e7SAlexandre Rames std::string HeaderSearch::getCachedModuleFileNameImpl(StringRef ModuleName,
23858c586e7SAlexandre Rames StringRef ModuleMapPath,
23958c586e7SAlexandre Rames StringRef CachePath) {
240d520a250SRichard Smith // If we don't have a module cache path or aren't supposed to use one, we
241d520a250SRichard Smith // can't do anything.
24258c586e7SAlexandre Rames if (CachePath.empty())
243afd1b1c9SEugene Zelenko return {};
2441735f4e7SDouglas Gregor
24558c586e7SAlexandre Rames SmallString<256> Result(CachePath);
246beee15e7SBen Langmuir llvm::sys::fs::make_absolute(Result);
247beee15e7SBen Langmuir
248beee15e7SBen Langmuir if (HSOpts->DisableModuleHash) {
249279a6c37SDouglas Gregor llvm::sys::path::append(Result, ModuleName + ".pcm");
250beee15e7SBen Langmuir } else {
251beee15e7SBen Langmuir // Construct the name <ModuleName>-<hash of ModuleMapPath>.pcm which should
25254cc3c2fSRichard Smith // ideally be globally unique to this particular module. Name collisions
25354cc3c2fSRichard Smith // in the hash are safe (because any translation unit can only import one
25454cc3c2fSRichard Smith // module with each name), but result in a loss of caching.
25554cc3c2fSRichard Smith //
25654cc3c2fSRichard Smith // To avoid false-negatives, we form as canonical a path as we can, and map
25754cc3c2fSRichard Smith // to lower-case in case we're on a case-insensitive file system.
258adcd0268SBenjamin Kramer std::string Parent =
259adcd0268SBenjamin Kramer std::string(llvm::sys::path::parent_path(ModuleMapPath));
2603f57cff1SRichard Smith if (Parent.empty())
2613f57cff1SRichard Smith Parent = ".";
2628d323d15SHarlan Haskins auto Dir = FileMgr.getDirectory(Parent);
26354cc3c2fSRichard Smith if (!Dir)
264afd1b1c9SEugene Zelenko return {};
2658d323d15SHarlan Haskins auto DirName = FileMgr.getCanonicalName(*Dir);
26654cc3c2fSRichard Smith auto FileName = llvm::sys::path::filename(ModuleMapPath);
26754cc3c2fSRichard Smith
26854cc3c2fSRichard Smith llvm::hash_code Hash =
269793038d3SAdrian Prantl llvm::hash_combine(DirName.lower(), FileName.lower());
27054cc3c2fSRichard Smith
271beee15e7SBen Langmuir SmallString<128> HashStr;
27254cc3c2fSRichard Smith llvm::APInt(64, size_t(Hash)).toStringUnsigned(HashStr, /*Radix*/36);
27392e1b62dSYaron Keren llvm::sys::path::append(Result, ModuleName + "-" + HashStr + ".pcm");
274beee15e7SBen Langmuir }
275279a6c37SDouglas Gregor return Result.str().str();
276279a6c37SDouglas Gregor }
277279a6c37SDouglas Gregor
lookupModule(StringRef ModuleName,SourceLocation ImportLoc,bool AllowSearch,bool AllowExtraModuleMapSearch)278638c673aSJan Svoboda Module *HeaderSearch::lookupModule(StringRef ModuleName,
279638c673aSJan Svoboda SourceLocation ImportLoc, bool AllowSearch,
28052431f39SBruno Cardoso Lopes bool AllowExtraModuleMapSearch) {
281af28ec80SDouglas Gregor // Look in the module map to determine if there is a module by this name.
282279a6c37SDouglas Gregor Module *Module = ModMap.findModule(ModuleName);
28347972afdSRichard Smith if (Module || !AllowSearch || !HSOpts->ImplicitModuleMaps)
284279a6c37SDouglas Gregor return Module;
285279a6c37SDouglas Gregor
2864d867640SGraydon Hoare StringRef SearchName = ModuleName;
287638c673aSJan Svoboda Module = lookupModule(ModuleName, SearchName, ImportLoc,
288638c673aSJan Svoboda AllowExtraModuleMapSearch);
2894d867640SGraydon Hoare
2904d867640SGraydon Hoare // The facility for "private modules" -- adjacent, optional module maps named
2914d867640SGraydon Hoare // module.private.modulemap that are supposed to define private submodules --
29229729919SBruno Cardoso Lopes // may have different flavors of names: FooPrivate, Foo_Private and Foo.Private.
29329729919SBruno Cardoso Lopes //
2942a8c18d9SAlexander Kornienko // Foo.Private is now deprecated in favor of Foo_Private. Users of FooPrivate
29529729919SBruno Cardoso Lopes // should also rename to Foo_Private. Representing private as submodules
29629729919SBruno Cardoso Lopes // could force building unwanted dependencies into the parent module and cause
29729729919SBruno Cardoso Lopes // dependency cycles.
29829729919SBruno Cardoso Lopes if (!Module && SearchName.consume_back("_Private"))
299638c673aSJan Svoboda Module = lookupModule(ModuleName, SearchName, ImportLoc,
300638c673aSJan Svoboda AllowExtraModuleMapSearch);
3014d867640SGraydon Hoare if (!Module && SearchName.consume_back("Private"))
302638c673aSJan Svoboda Module = lookupModule(ModuleName, SearchName, ImportLoc,
303638c673aSJan Svoboda AllowExtraModuleMapSearch);
3044d867640SGraydon Hoare return Module;
3054d867640SGraydon Hoare }
3064d867640SGraydon Hoare
lookupModule(StringRef ModuleName,StringRef SearchName,SourceLocation ImportLoc,bool AllowExtraModuleMapSearch)30752431f39SBruno Cardoso Lopes Module *HeaderSearch::lookupModule(StringRef ModuleName, StringRef SearchName,
308638c673aSJan Svoboda SourceLocation ImportLoc,
30952431f39SBruno Cardoso Lopes bool AllowExtraModuleMapSearch) {
3104d867640SGraydon Hoare Module *Module = nullptr;
3114d867640SGraydon Hoare
3124ddf2221SDouglas Gregor // Look through the various header search paths to load any available module
313af28ec80SDouglas Gregor // maps, searching for a module map that describes this module.
3146007b0b6SJan Svoboda for (DirectoryLookup Dir : search_dir_range()) {
3156007b0b6SJan Svoboda if (Dir.isFramework()) {
3164d867640SGraydon Hoare // Search for or infer a module map for a framework. Here we use
3174d867640SGraydon Hoare // SearchName rather than ModuleName, to permit finding private modules
3184d867640SGraydon Hoare // named FooPrivate in buggy frameworks named Foo.
3192c1dd271SDylan Noblesmith SmallString<128> FrameworkDirName;
3206007b0b6SJan Svoboda FrameworkDirName += Dir.getFrameworkDir()->getName();
3214d867640SGraydon Hoare llvm::sys::path::append(FrameworkDirName, SearchName + ".framework");
322d9390b6aSJan Svoboda if (auto FrameworkDir =
323d9390b6aSJan Svoboda FileMgr.getOptionalDirectoryRef(FrameworkDirName)) {
3246007b0b6SJan Svoboda bool IsSystem = Dir.getDirCharacteristic() != SrcMgr::C_User;
3258d323d15SHarlan Haskins Module = loadFrameworkModule(ModuleName, *FrameworkDir, IsSystem);
326ca295457SDouglas Gregor if (Module)
327ca295457SDouglas Gregor break;
328ca295457SDouglas Gregor }
329ca295457SDouglas Gregor }
330ca295457SDouglas Gregor
331ca295457SDouglas Gregor // FIXME: Figure out how header maps and module maps will work together.
332ca295457SDouglas Gregor
333ca295457SDouglas Gregor // Only deal with normal search directories.
3346007b0b6SJan Svoboda if (!Dir.isNormalDir())
335af28ec80SDouglas Gregor continue;
336af28ec80SDouglas Gregor
3376007b0b6SJan Svoboda bool IsSystem = Dir.isSystemHeaderDirectory();
338d9390b6aSJan Svoboda // Only returns None if not a normal directory, which we just checked
339d9390b6aSJan Svoboda DirectoryEntryRef NormalDir = *Dir.getDirRef();
34080b6904bSDouglas Gregor // Search for a module map file in this directory.
341d9390b6aSJan Svoboda if (loadModuleMapFile(NormalDir, IsSystem,
342984e1df7SBen Langmuir /*IsFramework*/false) == LMM_NewlyLoaded) {
34380b6904bSDouglas Gregor // We just loaded a module map file; check whether the module is
34480b6904bSDouglas Gregor // available now.
345af28ec80SDouglas Gregor Module = ModMap.findModule(ModuleName);
346af28ec80SDouglas Gregor if (Module)
347af28ec80SDouglas Gregor break;
348af28ec80SDouglas Gregor }
349af28ec80SDouglas Gregor
350af28ec80SDouglas Gregor // Search for a module map in a subdirectory with the same name as the
351af28ec80SDouglas Gregor // module.
3522c1dd271SDylan Noblesmith SmallString<128> NestedModuleMapDirName;
3536007b0b6SJan Svoboda NestedModuleMapDirName = Dir.getDir()->getName();
354af28ec80SDouglas Gregor llvm::sys::path::append(NestedModuleMapDirName, ModuleName);
355984e1df7SBen Langmuir if (loadModuleMapFile(NestedModuleMapDirName, IsSystem,
356984e1df7SBen Langmuir /*IsFramework*/false) == LMM_NewlyLoaded){
35780b6904bSDouglas Gregor // If we just loaded a module map file, look for the module again.
358af28ec80SDouglas Gregor Module = ModMap.findModule(ModuleName);
359af28ec80SDouglas Gregor if (Module)
360af28ec80SDouglas Gregor break;
361af28ec80SDouglas Gregor }
3620339a64aSDouglas Gregor
3630339a64aSDouglas Gregor // If we've already performed the exhaustive search for module maps in this
3640339a64aSDouglas Gregor // search directory, don't do it again.
3656007b0b6SJan Svoboda if (Dir.haveSearchedAllModuleMaps())
3660339a64aSDouglas Gregor continue;
3670339a64aSDouglas Gregor
3680339a64aSDouglas Gregor // Load all module maps in the immediate subdirectories of this search
36952431f39SBruno Cardoso Lopes // directory if ModuleName was from @import.
37052431f39SBruno Cardoso Lopes if (AllowExtraModuleMapSearch)
3716007b0b6SJan Svoboda loadSubdirectoryModuleMaps(Dir);
3720339a64aSDouglas Gregor
3730339a64aSDouglas Gregor // Look again for the module.
3740339a64aSDouglas Gregor Module = ModMap.findModule(ModuleName);
3750339a64aSDouglas Gregor if (Module)
3760339a64aSDouglas Gregor break;
377af28ec80SDouglas Gregor }
378af28ec80SDouglas Gregor
379279a6c37SDouglas Gregor return Module;
3801e44e022SDouglas Gregor }
3811e44e022SDouglas Gregor
3827a51313dSChris Lattner //===----------------------------------------------------------------------===//
3837a51313dSChris Lattner // File lookup within a DirectoryLookup scope
3847a51313dSChris Lattner //===----------------------------------------------------------------------===//
3857a51313dSChris Lattner
3867a51313dSChris Lattner /// getName - Return the directory or filename corresponding to this lookup
3877a51313dSChris Lattner /// object.
getName() const38899d1b295SMehdi Amini StringRef DirectoryLookup::getName() const {
3890377ca64SAlex Lorenz // FIXME: Use the name from \c DirectoryEntryRef.
3907a51313dSChris Lattner if (isNormalDir())
3917a51313dSChris Lattner return getDir()->getName();
3927a51313dSChris Lattner if (isFramework())
3937a51313dSChris Lattner return getFrameworkDir()->getName();
3947a51313dSChris Lattner assert(isHeaderMap() && "Unknown DirectoryLookup");
3957a51313dSChris Lattner return getHeaderMap()->getFileName();
3967a51313dSChris Lattner }
3977a51313dSChris Lattner
getFileAndSuggestModule(StringRef FileName,SourceLocation IncludeLoc,const DirectoryEntry * Dir,bool IsSystemHeaderDir,Module * RequestingModule,ModuleMap::KnownHeader * SuggestedModule)3984dc5573aSAlex Lorenz Optional<FileEntryRef> HeaderSearch::getFileAndSuggestModule(
399f42103ceSTaewook Oh StringRef FileName, SourceLocation IncludeLoc, const DirectoryEntry *Dir,
400f42103ceSTaewook Oh bool IsSystemHeaderDir, Module *RequestingModule,
401f42103ceSTaewook Oh ModuleMap::KnownHeader *SuggestedModule) {
4028c71eba1SRichard Smith // If we have a module map that might map this header, load it and
4038c71eba1SRichard Smith // check whether we'll have a suggestion for a module.
4044dc5573aSAlex Lorenz auto File = getFileMgr().getFileRef(FileName, /*OpenFile=*/true);
405babdfdecSNico Weber if (!File) {
406babdfdecSNico Weber // For rare, surprising errors (e.g. "out of file handles"), diag the EC
407babdfdecSNico Weber // message.
4089ef6c49bSDuncan P. N. Exon Smith std::error_code EC = llvm::errorToErrorCode(File.takeError());
4094a0328c9SAlexey Bataev if (EC != llvm::errc::no_such_file_or_directory &&
4104a0328c9SAlexey Bataev EC != llvm::errc::invalid_argument &&
4114a0328c9SAlexey Bataev EC != llvm::errc::is_a_directory && EC != llvm::errc::not_a_directory) {
4121d63b02fSReid Kleckner Diags.Report(IncludeLoc, diag::err_cannot_open_file)
4131d63b02fSReid Kleckner << FileName << EC.message();
414babdfdecSNico Weber }
4154dc5573aSAlex Lorenz return None;
416babdfdecSNico Weber }
4178c71eba1SRichard Smith
4183d5b48c4SRichard Smith // If there is a module that corresponds to this header, suggest it.
4194dc5573aSAlex Lorenz if (!findUsableModuleForHeader(
4204dc5573aSAlex Lorenz &File->getFileEntry(), Dir ? Dir : File->getFileEntry().getDir(),
4214dc5573aSAlex Lorenz RequestingModule, SuggestedModule, IsSystemHeaderDir))
4224dc5573aSAlex Lorenz return None;
4238c71eba1SRichard Smith
4248d323d15SHarlan Haskins return *File;
4258c71eba1SRichard Smith }
4268c71eba1SRichard Smith
4277a51313dSChris Lattner /// LookupFile - Lookup the specified file in this search path, returning it
4287a51313dSChris Lattner /// if it exists or returning null if not.
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) const4294dc5573aSAlex Lorenz Optional<FileEntryRef> DirectoryLookup::LookupFile(
4304dc5573aSAlex Lorenz StringRef &Filename, HeaderSearch &HS, SourceLocation IncludeLoc,
4314dc5573aSAlex Lorenz SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
4324dc5573aSAlex Lorenz Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
4334dc5573aSAlex Lorenz bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound,
4342f843616SVolodymyr Sapsai bool &IsInHeaderMap, SmallVectorImpl<char> &MappedName) const {
4353c9bc4dbSDaniel Dunbar InUserSpecifiedSystemFramework = false;
4362f843616SVolodymyr Sapsai IsInHeaderMap = false;
4372f843616SVolodymyr Sapsai MappedName.clear();
4383c9bc4dbSDaniel Dunbar
4392c1dd271SDylan Noblesmith SmallString<1024> TmpDir;
4407a51313dSChris Lattner if (isNormalDir()) {
4417a51313dSChris Lattner // Concatenate the requested file onto the directory.
442b672638dSJan Svoboda TmpDir = getDirRef()->getName();
443f7ca26a0SEli Friedman llvm::sys::path::append(TmpDir, Filename);
444d2d442caSCraig Topper if (SearchPath) {
445b672638dSJan Svoboda StringRef SearchPathRef(getDirRef()->getName());
4460c69fd27SManuel Klimek SearchPath->clear();
4470c69fd27SManuel Klimek SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
4480c69fd27SManuel Klimek }
449d2d442caSCraig Topper if (RelativePath) {
4500c69fd27SManuel Klimek RelativePath->clear();
4510c69fd27SManuel Klimek RelativePath->append(Filename.begin(), Filename.end());
4520c69fd27SManuel Klimek }
453718292f2SDouglas Gregor
454f42103ceSTaewook Oh return HS.getFileAndSuggestModule(TmpDir, IncludeLoc, getDir(),
4558c71eba1SRichard Smith isSystemHeaderDirectory(),
4563d5b48c4SRichard Smith RequestingModule, SuggestedModule);
4577a51313dSChris Lattner }
4587a51313dSChris Lattner
4597a51313dSChris Lattner if (isFramework())
46097eec24bSDouglas Gregor return DoFrameworkLookup(Filename, HS, SearchPath, RelativePath,
4613d5b48c4SRichard Smith RequestingModule, SuggestedModule,
462421380a1SVolodymyr Sapsai InUserSpecifiedSystemFramework, IsFrameworkFound);
4637a51313dSChris Lattner
4647a51313dSChris Lattner assert(isHeaderMap() && "Unknown directory lookup");
46575fa9eddSArgyrios Kyrtzidis const HeaderMap *HM = getHeaderMap();
46675fa9eddSArgyrios Kyrtzidis SmallString<1024> Path;
46775fa9eddSArgyrios Kyrtzidis StringRef Dest = HM->lookupFilename(Filename, Path);
46875fa9eddSArgyrios Kyrtzidis if (Dest.empty())
4694dc5573aSAlex Lorenz return None;
47075fa9eddSArgyrios Kyrtzidis
4712f843616SVolodymyr Sapsai IsInHeaderMap = true;
4722f843616SVolodymyr Sapsai
4734dc5573aSAlex Lorenz auto FixupSearchPath = [&]() {
474d2d442caSCraig Topper if (SearchPath) {
4750e62c1ccSChris Lattner StringRef SearchPathRef(getName());
4760c69fd27SManuel Klimek SearchPath->clear();
4770c69fd27SManuel Klimek SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
4780c69fd27SManuel Klimek }
479d2d442caSCraig Topper if (RelativePath) {
4800c69fd27SManuel Klimek RelativePath->clear();
4810c69fd27SManuel Klimek RelativePath->append(Filename.begin(), Filename.end());
4820c69fd27SManuel Klimek }
4834dc5573aSAlex Lorenz };
4844dc5573aSAlex Lorenz
4854dc5573aSAlex Lorenz // Check if the headermap maps the filename to a framework include
4864dc5573aSAlex Lorenz // ("Foo.h" -> "Foo/Foo.h"), in which case continue header lookup using the
4874dc5573aSAlex Lorenz // framework include.
4884dc5573aSAlex Lorenz if (llvm::sys::path::is_relative(Dest)) {
4894dc5573aSAlex Lorenz MappedName.append(Dest.begin(), Dest.end());
4904dc5573aSAlex Lorenz Filename = StringRef(MappedName.begin(), MappedName.size());
49144451351SJan Svoboda Dest = HM->lookupFilename(Filename, Path);
4920c69fd27SManuel Klimek }
49344451351SJan Svoboda
49444451351SJan Svoboda if (auto Res = HS.getFileMgr().getOptionalFileRef(Dest)) {
4954dc5573aSAlex Lorenz FixupSearchPath();
4964dc5573aSAlex Lorenz return *Res;
4974dc5573aSAlex Lorenz }
4984dc5573aSAlex Lorenz
49944451351SJan Svoboda // Header maps need to be marked as used whenever the filename matches.
50044451351SJan Svoboda // The case where the target file **exists** is handled by callee of this
50144451351SJan Svoboda // function as part of the regular logic that applies to include search paths.
50244451351SJan Svoboda // The case where the target file **does not exist** is handled here:
503e7dcf09fSJan Svoboda HS.noteLookupUsage(HS.searchDirIdx(*this), IncludeLoc);
5044dc5573aSAlex Lorenz return None;
5057a51313dSChris Lattner }
5067a51313dSChris Lattner
5079fc8faf9SAdrian Prantl /// Given a framework directory, find the top-most framework directory.
5084ddf2221SDouglas Gregor ///
5094ddf2221SDouglas Gregor /// \param FileMgr The file manager to use for directory lookups.
5104ddf2221SDouglas Gregor /// \param DirName The name of the framework directory.
5114ddf2221SDouglas Gregor /// \param SubmodulePath Will be populated with the submodule path from the
5124ddf2221SDouglas Gregor /// returned top-level module to the originally named framework.
513d9390b6aSJan Svoboda static Optional<DirectoryEntryRef>
getTopFrameworkDir(FileManager & FileMgr,StringRef DirName,SmallVectorImpl<std::string> & SubmodulePath)5144ddf2221SDouglas Gregor getTopFrameworkDir(FileManager &FileMgr, StringRef DirName,
5154ddf2221SDouglas Gregor SmallVectorImpl<std::string> &SubmodulePath) {
5164ddf2221SDouglas Gregor assert(llvm::sys::path::extension(DirName) == ".framework" &&
5174ddf2221SDouglas Gregor "Not a framework directory");
5184ddf2221SDouglas Gregor
5194ddf2221SDouglas Gregor // Note: as an egregious but useful hack we use the real path here, because
5204ddf2221SDouglas Gregor // frameworks moving between top-level frameworks to embedded frameworks tend
5214ddf2221SDouglas Gregor // to be symlinked, and we base the logical structure of modules on the
5224ddf2221SDouglas Gregor // physical layout. In particular, we need to deal with crazy includes like
5234ddf2221SDouglas Gregor //
5244ddf2221SDouglas Gregor // #include <Foo/Frameworks/Bar.framework/Headers/Wibble.h>
5254ddf2221SDouglas Gregor //
5264ddf2221SDouglas Gregor // where 'Bar' used to be embedded in 'Foo', is now a top-level framework
5274ddf2221SDouglas Gregor // which one should access with, e.g.,
5284ddf2221SDouglas Gregor //
5294ddf2221SDouglas Gregor // #include <Bar/Wibble.h>
5304ddf2221SDouglas Gregor //
5314ddf2221SDouglas Gregor // Similar issues occur when a top-level framework has moved into an
5324ddf2221SDouglas Gregor // embedded framework.
533d9390b6aSJan Svoboda auto TopFrameworkDir = FileMgr.getOptionalDirectoryRef(DirName);
5348d323d15SHarlan Haskins
5358d323d15SHarlan Haskins if (TopFrameworkDir)
536d9390b6aSJan Svoboda DirName = FileMgr.getCanonicalName(*TopFrameworkDir);
5374ddf2221SDouglas Gregor do {
5384ddf2221SDouglas Gregor // Get the parent directory name.
5394ddf2221SDouglas Gregor DirName = llvm::sys::path::parent_path(DirName);
5404ddf2221SDouglas Gregor if (DirName.empty())
5414ddf2221SDouglas Gregor break;
5424ddf2221SDouglas Gregor
5434ddf2221SDouglas Gregor // Determine whether this directory exists.
544d9390b6aSJan Svoboda auto Dir = FileMgr.getOptionalDirectoryRef(DirName);
5454ddf2221SDouglas Gregor if (!Dir)
5464ddf2221SDouglas Gregor break;
5474ddf2221SDouglas Gregor
5484ddf2221SDouglas Gregor // If this is a framework directory, then we're a subframework of this
5494ddf2221SDouglas Gregor // framework.
5504ddf2221SDouglas Gregor if (llvm::sys::path::extension(DirName) == ".framework") {
551adcd0268SBenjamin Kramer SubmodulePath.push_back(std::string(llvm::sys::path::stem(DirName)));
5528d323d15SHarlan Haskins TopFrameworkDir = *Dir;
5534ddf2221SDouglas Gregor }
5544ddf2221SDouglas Gregor } while (true);
5554ddf2221SDouglas Gregor
5564ddf2221SDouglas Gregor return TopFrameworkDir;
5574ddf2221SDouglas Gregor }
5587a51313dSChris Lattner
needModuleLookup(Module * RequestingModule,bool HasSuggestedModule)559ed84df00SBruno Cardoso Lopes static bool needModuleLookup(Module *RequestingModule,
560ed84df00SBruno Cardoso Lopes bool HasSuggestedModule) {
561ed84df00SBruno Cardoso Lopes return HasSuggestedModule ||
562ed84df00SBruno Cardoso Lopes (RequestingModule && RequestingModule->NoUndeclaredIncludes);
563ed84df00SBruno Cardoso Lopes }
564ed84df00SBruno Cardoso Lopes
5657a51313dSChris Lattner /// DoFrameworkLookup - Do a lookup of the specified file in the current
5667a51313dSChris Lattner /// DirectoryLookup, which is a framework directory.
DoFrameworkLookup(StringRef Filename,HeaderSearch & HS,SmallVectorImpl<char> * SearchPath,SmallVectorImpl<char> * RelativePath,Module * RequestingModule,ModuleMap::KnownHeader * SuggestedModule,bool & InUserSpecifiedSystemFramework,bool & IsFrameworkFound) const5674dc5573aSAlex Lorenz Optional<FileEntryRef> DirectoryLookup::DoFrameworkLookup(
5683d5b48c4SRichard Smith StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath,
5693d5b48c4SRichard Smith SmallVectorImpl<char> *RelativePath, Module *RequestingModule,
570b53e5483SLawrence Crowl ModuleMap::KnownHeader *SuggestedModule,
571421380a1SVolodymyr Sapsai bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound) const {
5727a51313dSChris Lattner FileManager &FileMgr = HS.getFileMgr();
5737a51313dSChris Lattner
5747a51313dSChris Lattner // Framework names must have a '/' in the filename.
575d081f8c8SChris Lattner size_t SlashPos = Filename.find('/');
5764dc5573aSAlex Lorenz if (SlashPos == StringRef::npos)
5774dc5573aSAlex Lorenz return None;
5787a51313dSChris Lattner
5797a51313dSChris Lattner // Find out if this is the home for the specified framework, by checking
58017138613SDaniel Dunbar // HeaderSearch. Possible answers are yes/no and unknown.
581421380a1SVolodymyr Sapsai FrameworkCacheEntry &CacheEntry =
582d081f8c8SChris Lattner HS.LookupFrameworkCache(Filename.substr(0, SlashPos));
5837a51313dSChris Lattner
5847a51313dSChris Lattner // If it is known and in some other directory, fail.
585f43ce519SJan Svoboda if (CacheEntry.Directory && CacheEntry.Directory != getFrameworkDirRef())
5864dc5573aSAlex Lorenz return None;
5877a51313dSChris Lattner
5887a51313dSChris Lattner // Otherwise, construct the path to this framework dir.
5897a51313dSChris Lattner
5907a51313dSChris Lattner // FrameworkName = "/System/Library/Frameworks/"
5912c1dd271SDylan Noblesmith SmallString<1024> FrameworkName;
5920377ca64SAlex Lorenz FrameworkName += getFrameworkDirRef()->getName();
5937a51313dSChris Lattner if (FrameworkName.empty() || FrameworkName.back() != '/')
5947a51313dSChris Lattner FrameworkName.push_back('/');
5957a51313dSChris Lattner
5967a51313dSChris Lattner // FrameworkName = "/System/Library/Frameworks/Cocoa"
59756c64013SDouglas Gregor StringRef ModuleName(Filename.begin(), SlashPos);
59856c64013SDouglas Gregor FrameworkName += ModuleName;
5997a51313dSChris Lattner
6007a51313dSChris Lattner // FrameworkName = "/System/Library/Frameworks/Cocoa.framework/"
6017a51313dSChris Lattner FrameworkName += ".framework/";
6027a51313dSChris Lattner
60317138613SDaniel Dunbar // If the cache entry was unresolved, populate it now.
604d2d442caSCraig Topper if (!CacheEntry.Directory) {
605e8752a9dSVolodymyr Sapsai ++NumFrameworkLookups;
6067a51313dSChris Lattner
6077a51313dSChris Lattner // If the framework dir doesn't exist, we fail.
6088d323d15SHarlan Haskins auto Dir = FileMgr.getDirectory(FrameworkName);
6094dc5573aSAlex Lorenz if (!Dir)
6104dc5573aSAlex Lorenz return None;
6117a51313dSChris Lattner
6127a51313dSChris Lattner // Otherwise, if it does, remember that this is the right direntry for this
6137a51313dSChris Lattner // framework.
614f43ce519SJan Svoboda CacheEntry.Directory = getFrameworkDirRef();
6153c9bc4dbSDaniel Dunbar
6163c9bc4dbSDaniel Dunbar // If this is a user search directory, check if the framework has been
6173c9bc4dbSDaniel Dunbar // user-specified as a system framework.
6183c9bc4dbSDaniel Dunbar if (getDirCharacteristic() == SrcMgr::C_User) {
6193c9bc4dbSDaniel Dunbar SmallString<1024> SystemFrameworkMarker(FrameworkName);
6203c9bc4dbSDaniel Dunbar SystemFrameworkMarker += ".system_framework";
62192e1b62dSYaron Keren if (llvm::sys::fs::exists(SystemFrameworkMarker)) {
6223c9bc4dbSDaniel Dunbar CacheEntry.IsUserSpecifiedSystemFramework = true;
6237a51313dSChris Lattner }
6243c9bc4dbSDaniel Dunbar }
6253c9bc4dbSDaniel Dunbar }
6263c9bc4dbSDaniel Dunbar
627421380a1SVolodymyr Sapsai // Set out flags.
6283c9bc4dbSDaniel Dunbar InUserSpecifiedSystemFramework = CacheEntry.IsUserSpecifiedSystemFramework;
629*0916d96dSKazu Hirata IsFrameworkFound = CacheEntry.Directory.has_value();
6307a51313dSChris Lattner
631d2d442caSCraig Topper if (RelativePath) {
6320c69fd27SManuel Klimek RelativePath->clear();
6330c69fd27SManuel Klimek RelativePath->append(Filename.begin()+SlashPos+1, Filename.end());
6340c69fd27SManuel Klimek }
6350c69fd27SManuel Klimek
6367a51313dSChris Lattner // Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h"
6377a51313dSChris Lattner unsigned OrigSize = FrameworkName.size();
6387a51313dSChris Lattner
6397a51313dSChris Lattner FrameworkName += "Headers/";
6400c69fd27SManuel Klimek
641d2d442caSCraig Topper if (SearchPath) {
6420c69fd27SManuel Klimek SearchPath->clear();
6430c69fd27SManuel Klimek // Without trailing '/'.
6440c69fd27SManuel Klimek SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1);
6450c69fd27SManuel Klimek }
6460c69fd27SManuel Klimek
647d081f8c8SChris Lattner FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
6488d323d15SHarlan Haskins
6499ef6c49bSDuncan P. N. Exon Smith auto File =
6509ef6c49bSDuncan P. N. Exon Smith FileMgr.getOptionalFileRef(FrameworkName, /*OpenFile=*/!SuggestedModule);
6514dc5573aSAlex Lorenz if (!File) {
6527a51313dSChris Lattner // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
6537a51313dSChris Lattner const char *Private = "Private";
6547a51313dSChris Lattner FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
6557a51313dSChris Lattner Private+strlen(Private));
656d2d442caSCraig Topper if (SearchPath)
6570c69fd27SManuel Klimek SearchPath->insert(SearchPath->begin()+OrigSize, Private,
6580c69fd27SManuel Klimek Private+strlen(Private));
6590c69fd27SManuel Klimek
6609ef6c49bSDuncan P. N. Exon Smith File = FileMgr.getOptionalFileRef(FrameworkName,
6619ef6c49bSDuncan P. N. Exon Smith /*OpenFile=*/!SuggestedModule);
6624ddf2221SDouglas Gregor }
6634ddf2221SDouglas Gregor
6644ddf2221SDouglas Gregor // If we found the header and are allowed to suggest a module, do so now.
6654dc5573aSAlex Lorenz if (File && needModuleLookup(RequestingModule, SuggestedModule)) {
6664ddf2221SDouglas Gregor // Find the framework in which this header occurs.
6674dc5573aSAlex Lorenz StringRef FrameworkPath = File->getFileEntry().getDir()->getName();
6684ddf2221SDouglas Gregor bool FoundFramework = false;
6694ddf2221SDouglas Gregor do {
6704ddf2221SDouglas Gregor // Determine whether this directory exists.
6718d323d15SHarlan Haskins auto Dir = FileMgr.getDirectory(FrameworkPath);
6724ddf2221SDouglas Gregor if (!Dir)
6734ddf2221SDouglas Gregor break;
6744ddf2221SDouglas Gregor
6754ddf2221SDouglas Gregor // If this is a framework directory, then we're a subframework of this
6764ddf2221SDouglas Gregor // framework.
6774ddf2221SDouglas Gregor if (llvm::sys::path::extension(FrameworkPath) == ".framework") {
6784ddf2221SDouglas Gregor FoundFramework = true;
6794ddf2221SDouglas Gregor break;
6804ddf2221SDouglas Gregor }
681ef914b89SBen Langmuir
682ef914b89SBen Langmuir // Get the parent directory name.
683ef914b89SBen Langmuir FrameworkPath = llvm::sys::path::parent_path(FrameworkPath);
684ef914b89SBen Langmuir if (FrameworkPath.empty())
685ef914b89SBen Langmuir break;
6864ddf2221SDouglas Gregor } while (true);
6874ddf2221SDouglas Gregor
6884ddf2221SDouglas Gregor bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
6893d5b48c4SRichard Smith if (FoundFramework) {
6903d5b48c4SRichard Smith if (!HS.findUsableModuleForFrameworkHeader(
6914dc5573aSAlex Lorenz &File->getFileEntry(), FrameworkPath, RequestingModule,
6923d5b48c4SRichard Smith SuggestedModule, IsSystem))
6934dc5573aSAlex Lorenz return None;
6944dc5573aSAlex Lorenz } else {
6954dc5573aSAlex Lorenz if (!HS.findUsableModuleForHeader(&File->getFileEntry(), getDir(),
6964dc5573aSAlex Lorenz RequestingModule, SuggestedModule,
6974dc5573aSAlex Lorenz IsSystem))
6984dc5573aSAlex Lorenz return None;
6994ddf2221SDouglas Gregor }
7004ddf2221SDouglas Gregor }
7014dc5573aSAlex Lorenz if (File)
7024dc5573aSAlex Lorenz return *File;
7034dc5573aSAlex Lorenz return None;
7047a51313dSChris Lattner }
7057a51313dSChris Lattner
cacheLookupSuccess(LookupFileCacheInfo & CacheLookup,ConstSearchDirIterator HitIt,SourceLocation Loc)70644451351SJan Svoboda void HeaderSearch::cacheLookupSuccess(LookupFileCacheInfo &CacheLookup,
70717c9fcd6SJan Svoboda ConstSearchDirIterator HitIt,
70817c9fcd6SJan Svoboda SourceLocation Loc) {
70917c9fcd6SJan Svoboda CacheLookup.HitIt = HitIt;
71017c9fcd6SJan Svoboda noteLookupUsage(HitIt.Idx, Loc);
71144451351SJan Svoboda }
71244451351SJan Svoboda
noteLookupUsage(unsigned HitIdx,SourceLocation Loc)713ccd7e783SJan Svoboda void HeaderSearch::noteLookupUsage(unsigned HitIdx, SourceLocation Loc) {
714ccd7e783SJan Svoboda SearchDirsUsage[HitIdx] = true;
71544451351SJan Svoboda
716ccd7e783SJan Svoboda auto UserEntryIdxIt = SearchDirToHSEntry.find(HitIdx);
71744451351SJan Svoboda if (UserEntryIdxIt != SearchDirToHSEntry.end())
71844451351SJan Svoboda Diags.Report(Loc, diag::remark_pp_search_path_usage)
71944451351SJan Svoboda << HSOpts->UserEntries[UserEntryIdxIt->second].Path;
72044451351SJan Svoboda }
72144451351SJan Svoboda
setTarget(const TargetInfo & Target)72289929282SDouglas Gregor void HeaderSearch::setTarget(const TargetInfo &Target) {
72389929282SDouglas Gregor ModMap.setTarget(Target);
72489929282SDouglas Gregor }
72589929282SDouglas Gregor
7267a51313dSChris Lattner //===----------------------------------------------------------------------===//
7277a51313dSChris Lattner // Header File Location.
7287a51313dSChris Lattner //===----------------------------------------------------------------------===//
7297a51313dSChris Lattner
7309fc8faf9SAdrian Prantl /// Return true with a diagnostic if the file that MSVC would have found
731a97d4c06SReid Kleckner /// fails to match the one that Clang would have found with MSVC header search
732a97d4c06SReid Kleckner /// disabled.
checkMSVCHeaderSearch(DiagnosticsEngine & Diags,const FileEntry * MSFE,const FileEntry * FE,SourceLocation IncludeLoc)733a97d4c06SReid Kleckner static bool checkMSVCHeaderSearch(DiagnosticsEngine &Diags,
734a97d4c06SReid Kleckner const FileEntry *MSFE, const FileEntry *FE,
735a97d4c06SReid Kleckner SourceLocation IncludeLoc) {
736a97d4c06SReid Kleckner if (MSFE && FE != MSFE) {
737a97d4c06SReid Kleckner Diags.Report(IncludeLoc, diag::ext_pp_include_search_ms) << MSFE->getName();
738a97d4c06SReid Kleckner return true;
739a97d4c06SReid Kleckner }
740a97d4c06SReid Kleckner return false;
741a97d4c06SReid Kleckner }
7427a51313dSChris Lattner
copyString(StringRef Str,llvm::BumpPtrAllocator & Alloc)74334fad420SArgyrios Kyrtzidis static const char *copyString(StringRef Str, llvm::BumpPtrAllocator &Alloc) {
74434fad420SArgyrios Kyrtzidis assert(!Str.empty());
74534fad420SArgyrios Kyrtzidis char *CopyStr = Alloc.Allocate<char>(Str.size()+1);
74634fad420SArgyrios Kyrtzidis std::copy(Str.begin(), Str.end(), CopyStr);
74734fad420SArgyrios Kyrtzidis CopyStr[Str.size()] = '\0';
74834fad420SArgyrios Kyrtzidis return CopyStr;
74934fad420SArgyrios Kyrtzidis }
75034fad420SArgyrios Kyrtzidis
isFrameworkStylePath(StringRef Path,bool & IsPrivateHeader,SmallVectorImpl<char> & FrameworkName,SmallVectorImpl<char> & IncludeSpelling)7511b3b69fbSBruno Cardoso Lopes static bool isFrameworkStylePath(StringRef Path, bool &IsPrivateHeader,
7520cf7e61aSDavid Goldman SmallVectorImpl<char> &FrameworkName,
7530cf7e61aSDavid Goldman SmallVectorImpl<char> &IncludeSpelling) {
754a9c51fe0SBruno Cardoso Lopes using namespace llvm::sys;
755a9c51fe0SBruno Cardoso Lopes path::const_iterator I = path::begin(Path);
756a9c51fe0SBruno Cardoso Lopes path::const_iterator E = path::end(Path);
7571b3b69fbSBruno Cardoso Lopes IsPrivateHeader = false;
758a9c51fe0SBruno Cardoso Lopes
759a9c51fe0SBruno Cardoso Lopes // Detect different types of framework style paths:
760a9c51fe0SBruno Cardoso Lopes //
761a9c51fe0SBruno Cardoso Lopes // ...Foo.framework/{Headers,PrivateHeaders}
762a9c51fe0SBruno Cardoso Lopes // ...Foo.framework/Versions/{A,Current}/{Headers,PrivateHeaders}
763a9c51fe0SBruno Cardoso Lopes // ...Foo.framework/Frameworks/Nested.framework/{Headers,PrivateHeaders}
764a9c51fe0SBruno Cardoso Lopes // ...<other variations with 'Versions' like in the above path>
765a9c51fe0SBruno Cardoso Lopes //
766a9c51fe0SBruno Cardoso Lopes // and some other variations among these lines.
767a9c51fe0SBruno Cardoso Lopes int FoundComp = 0;
768a9c51fe0SBruno Cardoso Lopes while (I != E) {
7690cf7e61aSDavid Goldman if (*I == "Headers") {
7701b3b69fbSBruno Cardoso Lopes ++FoundComp;
7710cf7e61aSDavid Goldman } else if (*I == "PrivateHeaders") {
772a9c51fe0SBruno Cardoso Lopes ++FoundComp;
7731b3b69fbSBruno Cardoso Lopes IsPrivateHeader = true;
7740cf7e61aSDavid Goldman } else if (I->endswith(".framework")) {
7750cf7e61aSDavid Goldman StringRef Name = I->drop_back(10); // Drop .framework
7760cf7e61aSDavid Goldman // Need to reset the strings and counter to support nested frameworks.
7770cf7e61aSDavid Goldman FrameworkName.clear();
7780cf7e61aSDavid Goldman FrameworkName.append(Name.begin(), Name.end());
7790cf7e61aSDavid Goldman IncludeSpelling.clear();
7800cf7e61aSDavid Goldman IncludeSpelling.append(Name.begin(), Name.end());
7810cf7e61aSDavid Goldman FoundComp = 1;
7820cf7e61aSDavid Goldman } else if (FoundComp >= 2) {
7830cf7e61aSDavid Goldman IncludeSpelling.push_back('/');
7840cf7e61aSDavid Goldman IncludeSpelling.append(I->begin(), I->end());
7851b3b69fbSBruno Cardoso Lopes }
786a9c51fe0SBruno Cardoso Lopes ++I;
787a9c51fe0SBruno Cardoso Lopes }
788a9c51fe0SBruno Cardoso Lopes
789abacc253SErik Pilkington return !FrameworkName.empty() && FoundComp >= 2;
790a9c51fe0SBruno Cardoso Lopes }
791a9c51fe0SBruno Cardoso Lopes
792a9c51fe0SBruno Cardoso Lopes static void
diagnoseFrameworkInclude(DiagnosticsEngine & Diags,SourceLocation IncludeLoc,StringRef Includer,StringRef IncludeFilename,const FileEntry * IncludeFE,bool isAngled=false,bool FoundByHeaderMap=false)793a9c51fe0SBruno Cardoso Lopes diagnoseFrameworkInclude(DiagnosticsEngine &Diags, SourceLocation IncludeLoc,
794a9c51fe0SBruno Cardoso Lopes StringRef Includer, StringRef IncludeFilename,
795a9c51fe0SBruno Cardoso Lopes const FileEntry *IncludeFE, bool isAngled = false,
796a9c51fe0SBruno Cardoso Lopes bool FoundByHeaderMap = false) {
7971b3b69fbSBruno Cardoso Lopes bool IsIncluderPrivateHeader = false;
798a9c51fe0SBruno Cardoso Lopes SmallString<128> FromFramework, ToFramework;
7990cf7e61aSDavid Goldman SmallString<128> FromIncludeSpelling, ToIncludeSpelling;
8000cf7e61aSDavid Goldman if (!isFrameworkStylePath(Includer, IsIncluderPrivateHeader, FromFramework,
8010cf7e61aSDavid Goldman FromIncludeSpelling))
802a9c51fe0SBruno Cardoso Lopes return;
8031b3b69fbSBruno Cardoso Lopes bool IsIncludeePrivateHeader = false;
8040cf7e61aSDavid Goldman bool IsIncludeeInFramework =
8050cf7e61aSDavid Goldman isFrameworkStylePath(IncludeFE->getName(), IsIncludeePrivateHeader,
8060cf7e61aSDavid Goldman ToFramework, ToIncludeSpelling);
807a9c51fe0SBruno Cardoso Lopes
808a9c51fe0SBruno Cardoso Lopes if (!isAngled && !FoundByHeaderMap) {
809a9c51fe0SBruno Cardoso Lopes SmallString<128> NewInclude("<");
810a9c51fe0SBruno Cardoso Lopes if (IsIncludeeInFramework) {
8110cf7e61aSDavid Goldman NewInclude += ToIncludeSpelling;
8120cf7e61aSDavid Goldman NewInclude += ">";
8130cf7e61aSDavid Goldman } else {
814a9c51fe0SBruno Cardoso Lopes NewInclude += IncludeFilename;
815a9c51fe0SBruno Cardoso Lopes NewInclude += ">";
8160cf7e61aSDavid Goldman }
817a9c51fe0SBruno Cardoso Lopes Diags.Report(IncludeLoc, diag::warn_quoted_include_in_framework_header)
818a9c51fe0SBruno Cardoso Lopes << IncludeFilename
819a9c51fe0SBruno Cardoso Lopes << FixItHint::CreateReplacement(IncludeLoc, NewInclude);
820a9c51fe0SBruno Cardoso Lopes }
8211b3b69fbSBruno Cardoso Lopes
8221b3b69fbSBruno Cardoso Lopes // Headers in Foo.framework/Headers should not include headers
8231b3b69fbSBruno Cardoso Lopes // from Foo.framework/PrivateHeaders, since this violates public/private
8241b3b69fbSBruno Cardoso Lopes // API boundaries and can cause modular dependency cycles.
8251b3b69fbSBruno Cardoso Lopes if (!IsIncluderPrivateHeader && IsIncludeeInFramework &&
8261b3b69fbSBruno Cardoso Lopes IsIncludeePrivateHeader && FromFramework == ToFramework)
8271b3b69fbSBruno Cardoso Lopes Diags.Report(IncludeLoc, diag::warn_framework_include_private_from_public)
8281b3b69fbSBruno Cardoso Lopes << IncludeFilename;
829a9c51fe0SBruno Cardoso Lopes }
830a9c51fe0SBruno Cardoso Lopes
831c07ab2c9SJames Dennett /// LookupFile - Given a "foo" or \<foo> reference, look up the indicated file,
8327a51313dSChris Lattner /// return null on failure. isAngled indicates whether the file reference is
8330fafd34aSWill Wilson /// for system \#include's or not (i.e. using <> instead of ""). Includers, if
8340fafd34aSWill Wilson /// non-empty, indicates where the \#including file(s) are, in case a relative
8350fafd34aSWill Wilson /// search is needed. Microsoft mode will pass all \#including files.
LookupFile(StringRef Filename,SourceLocation IncludeLoc,bool isAngled,ConstSearchDirIterator FromDir,ConstSearchDirIterator * CurDirArg,ArrayRef<std::pair<const FileEntry *,const DirectoryEntry * >> Includers,SmallVectorImpl<char> * SearchPath,SmallVectorImpl<char> * RelativePath,Module * RequestingModule,ModuleMap::KnownHeader * SuggestedModule,bool * IsMapped,bool * IsFrameworkFound,bool SkipCache,bool BuildSystemModule)8364dc5573aSAlex Lorenz Optional<FileEntryRef> HeaderSearch::LookupFile(
8370fafd34aSWill Wilson StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
8387631c366SJan Svoboda ConstSearchDirIterator FromDir, ConstSearchDirIterator *CurDirArg,
8399af34aeaSManuel Klimek ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
8409af34aeaSManuel Klimek SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
8413d5b48c4SRichard Smith Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
842421380a1SVolodymyr Sapsai bool *IsMapped, bool *IsFrameworkFound, bool SkipCache,
843421380a1SVolodymyr Sapsai bool BuildSystemModule) {
8447631c366SJan Svoboda ConstSearchDirIterator CurDirLocal = nullptr;
8457631c366SJan Svoboda ConstSearchDirIterator &CurDir = CurDirArg ? *CurDirArg : CurDirLocal;
846105c9131SJan Svoboda
847cfc1f6a6SDuncan P. N. Exon Smith if (IsMapped)
848cfc1f6a6SDuncan P. N. Exon Smith *IsMapped = false;
849cfc1f6a6SDuncan P. N. Exon Smith
850421380a1SVolodymyr Sapsai if (IsFrameworkFound)
851421380a1SVolodymyr Sapsai *IsFrameworkFound = false;
852421380a1SVolodymyr Sapsai
85397eec24bSDouglas Gregor if (SuggestedModule)
854b53e5483SLawrence Crowl *SuggestedModule = ModuleMap::KnownHeader();
85597eec24bSDouglas Gregor
8567a51313dSChris Lattner // If 'Filename' is absolute, check to see if it exists and no searching.
857f28df4cdSMichael J. Spencer if (llvm::sys::path::is_absolute(Filename)) {
858d2d442caSCraig Topper CurDir = nullptr;
8597a51313dSChris Lattner
8607a51313dSChris Lattner // If this was an #include_next "/absolute/file", fail.
8614dc5573aSAlex Lorenz if (FromDir)
8624dc5573aSAlex Lorenz return None;
8637a51313dSChris Lattner
864d2d442caSCraig Topper if (SearchPath)
8650c69fd27SManuel Klimek SearchPath->clear();
866d2d442caSCraig Topper if (RelativePath) {
8670c69fd27SManuel Klimek RelativePath->clear();
8680c69fd27SManuel Klimek RelativePath->append(Filename.begin(), Filename.end());
8690c69fd27SManuel Klimek }
8707a51313dSChris Lattner // Otherwise, just return the file.
871f42103ceSTaewook Oh return getFileAndSuggestModule(Filename, IncludeLoc, nullptr,
8723d5b48c4SRichard Smith /*IsSystemHeaderDir*/false,
8733d5b48c4SRichard Smith RequestingModule, SuggestedModule);
8747a51313dSChris Lattner }
8757a51313dSChris Lattner
876a97d4c06SReid Kleckner // This is the header that MSVC's header search would have found.
8778c71eba1SRichard Smith ModuleMap::KnownHeader MSSuggestedModule;
87874910cbbSDuncan P. N. Exon Smith Optional<FileEntryRef> MSFE;
879a97d4c06SReid Kleckner
8809f93e38aSDouglas Gregor // Unless disabled, check to see if the file is in the #includer's
8810fafd34aSWill Wilson // directory. This cannot be based on CurDir, because each includer could be
8820fafd34aSWill Wilson // a #include of a subdirectory (#include "foo/bar.h") and a subsequent
8830fafd34aSWill Wilson // include of "baz.h" should resolve to "whatever/foo/baz.h".
8847a51313dSChris Lattner // This search is not done for <> headers.
8850fafd34aSWill Wilson if (!Includers.empty() && !isAngled && !NoCurDirSearch) {
8869cb62649SNAKAMURA Takumi SmallString<1024> TmpDir;
8879af34aeaSManuel Klimek bool First = true;
8889af34aeaSManuel Klimek for (const auto &IncluderAndDir : Includers) {
8899af34aeaSManuel Klimek const FileEntry *Includer = IncluderAndDir.first;
8909af34aeaSManuel Klimek
891618e64a2SDouglas Gregor // Concatenate the requested file onto the directory.
892cf385dc8SNikola Smiljanic // FIXME: Portability. Filename concatenation should be in sys::Path.
8939af34aeaSManuel Klimek TmpDir = IncluderAndDir.second->getName();
894cf385dc8SNikola Smiljanic TmpDir.push_back('/');
895cf385dc8SNikola Smiljanic TmpDir.append(Filename.begin(), Filename.end());
8968c71eba1SRichard Smith
8976f548ec3SRichard Smith // FIXME: We don't cache the result of getFileInfo across the call to
8986f548ec3SRichard Smith // getFileAndSuggestModule, because it's a reference to an element of
8996f548ec3SRichard Smith // a container that could be reallocated across this call.
9003c1a41adSRichard Smith //
901e4a5d37dSManman Ren // If we have no includer, that means we're processing a #include
9023c1a41adSRichard Smith // from a module build. We should treat this as a system header if we're
9033c1a41adSRichard Smith // building a [system] module.
9046f548ec3SRichard Smith bool IncluderIsSystemHeader =
905e39c8143SManman Ren Includer ? getFileInfo(Includer).DirInfo != SrcMgr::C_User :
906e39c8143SManman Ren BuildSystemModule;
9074dc5573aSAlex Lorenz if (Optional<FileEntryRef> FE = getFileAndSuggestModule(
908f42103ceSTaewook Oh TmpDir, IncludeLoc, IncluderAndDir.second, IncluderIsSystemHeader,
9093d5b48c4SRichard Smith RequestingModule, SuggestedModule)) {
9103c1a41adSRichard Smith if (!Includer) {
9113c1a41adSRichard Smith assert(First && "only first includer can have no file");
9123c1a41adSRichard Smith return FE;
9133c1a41adSRichard Smith }
9143c1a41adSRichard Smith
9157a51313dSChris Lattner // Leave CurDir unset.
916618e64a2SDouglas Gregor // This file is a system header or C++ unfriendly if the old file is.
917618e64a2SDouglas Gregor //
91803b5ebe4SDouglas Gregor // Note that we only use one of FromHFI/ToHFI at once, due to potential
91903b5ebe4SDouglas Gregor // reallocation of the underlying vector potentially making the first
92003b5ebe4SDouglas Gregor // reference binding dangling.
9216f548ec3SRichard Smith HeaderFileInfo &FromHFI = getFileInfo(Includer);
92203b5ebe4SDouglas Gregor unsigned DirInfo = FromHFI.DirInfo;
92303b5ebe4SDouglas Gregor bool IndexHeaderMapHeader = FromHFI.IndexHeaderMapHeader;
92403b5ebe4SDouglas Gregor StringRef Framework = FromHFI.Framework;
92503b5ebe4SDouglas Gregor
9264dc5573aSAlex Lorenz HeaderFileInfo &ToHFI = getFileInfo(&FE->getFileEntry());
92703b5ebe4SDouglas Gregor ToHFI.DirInfo = DirInfo;
92803b5ebe4SDouglas Gregor ToHFI.IndexHeaderMapHeader = IndexHeaderMapHeader;
92903b5ebe4SDouglas Gregor ToHFI.Framework = Framework;
93003b5ebe4SDouglas Gregor
931d2d442caSCraig Topper if (SearchPath) {
9329af34aeaSManuel Klimek StringRef SearchPathRef(IncluderAndDir.second->getName());
9330c69fd27SManuel Klimek SearchPath->clear();
9340c69fd27SManuel Klimek SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
9350c69fd27SManuel Klimek }
936d2d442caSCraig Topper if (RelativePath) {
9370c69fd27SManuel Klimek RelativePath->clear();
9380c69fd27SManuel Klimek RelativePath->append(Filename.begin(), Filename.end());
9390c69fd27SManuel Klimek }
940a9c51fe0SBruno Cardoso Lopes if (First) {
941a9c51fe0SBruno Cardoso Lopes diagnoseFrameworkInclude(Diags, IncludeLoc,
942a9c51fe0SBruno Cardoso Lopes IncluderAndDir.second->getName(), Filename,
9434dc5573aSAlex Lorenz &FE->getFileEntry());
9447a51313dSChris Lattner return FE;
945a9c51fe0SBruno Cardoso Lopes }
946a97d4c06SReid Kleckner
947a97d4c06SReid Kleckner // Otherwise, we found the path via MSVC header search rules. If
948a97d4c06SReid Kleckner // -Wmsvc-include is enabled, we have to keep searching to see if we
949a97d4c06SReid Kleckner // would've found this header in -I or -isystem directories.
950d4a3f0e8SAlp Toker if (Diags.isIgnored(diag::ext_pp_include_search_ms, IncludeLoc)) {
951a97d4c06SReid Kleckner return FE;
952a97d4c06SReid Kleckner } else {
95374910cbbSDuncan P. N. Exon Smith MSFE = FE;
9548c71eba1SRichard Smith if (SuggestedModule) {
9558c71eba1SRichard Smith MSSuggestedModule = *SuggestedModule;
9568c71eba1SRichard Smith *SuggestedModule = ModuleMap::KnownHeader();
9578c71eba1SRichard Smith }
958a97d4c06SReid Kleckner break;
959a97d4c06SReid Kleckner }
9607a51313dSChris Lattner }
9619af34aeaSManuel Klimek First = false;
9627a51313dSChris Lattner }
9630fafd34aSWill Wilson }
9647a51313dSChris Lattner
965d2d442caSCraig Topper CurDir = nullptr;
9667a51313dSChris Lattner
9677a51313dSChris Lattner // If this is a system #include, ignore the user #include locs.
96817c9fcd6SJan Svoboda ConstSearchDirIterator It =
96917c9fcd6SJan Svoboda isAngled ? angled_dir_begin() : search_dir_begin();
9707a51313dSChris Lattner
9717a51313dSChris Lattner // If this is a #include_next request, start searching after the directory the
9727a51313dSChris Lattner // file was found in.
9737a51313dSChris Lattner if (FromDir)
97417c9fcd6SJan Svoboda It = FromDir;
9757a51313dSChris Lattner
9767a51313dSChris Lattner // Cache all of the lookups performed by this method. Many headers are
9777a51313dSChris Lattner // multiply included, and the "pragma once" optimization prevents them from
9787a51313dSChris Lattner // being relex/pp'd, but they would still have to search through a
9797a51313dSChris Lattner // (potentially huge) series of SearchDirs to find it.
98013156b68SDavid Blaikie LookupFileCacheInfo &CacheLookup = LookupFileCache[Filename];
9817a51313dSChris Lattner
98217c9fcd6SJan Svoboda ConstSearchDirIterator NextIt = std::next(It);
98317c9fcd6SJan Svoboda
9847a51313dSChris Lattner // If the entry has been previously looked up, the first value will be
9857a51313dSChris Lattner // non-zero. If the value is equal to i (the start point of our search), then
9867a51313dSChris Lattner // this is a matching hit.
98717c9fcd6SJan Svoboda if (!SkipCache && CacheLookup.StartIt == NextIt) {
9887a51313dSChris Lattner // Skip querying potentially lots of directories for this lookup.
98959dadd17SJan Svoboda if (CacheLookup.HitIt)
99017c9fcd6SJan Svoboda It = CacheLookup.HitIt;
991cfc1f6a6SDuncan P. N. Exon Smith if (CacheLookup.MappedName) {
99234fad420SArgyrios Kyrtzidis Filename = CacheLookup.MappedName;
993cfc1f6a6SDuncan P. N. Exon Smith if (IsMapped)
994cfc1f6a6SDuncan P. N. Exon Smith *IsMapped = true;
995cfc1f6a6SDuncan P. N. Exon Smith }
9967a51313dSChris Lattner } else {
9977a51313dSChris Lattner // Otherwise, this is the first query, or the previous query didn't match
9987a51313dSChris Lattner // our search start. We will fill in our found location below, so prime the
9997a51313dSChris Lattner // start point value.
100017c9fcd6SJan Svoboda CacheLookup.reset(/*NewStartIt=*/NextIt);
10017a51313dSChris Lattner }
10027a51313dSChris Lattner
100375fa9eddSArgyrios Kyrtzidis SmallString<64> MappedName;
100475fa9eddSArgyrios Kyrtzidis
10057a51313dSChris Lattner // Check each directory in sequence to see if it contains this file.
100617c9fcd6SJan Svoboda for (; It != search_dir_end(); ++It) {
10073c9bc4dbSDaniel Dunbar bool InUserSpecifiedSystemFramework = false;
10082f843616SVolodymyr Sapsai bool IsInHeaderMap = false;
1009421380a1SVolodymyr Sapsai bool IsFrameworkFoundInDir = false;
101017c9fcd6SJan Svoboda Optional<FileEntryRef> File = It->LookupFile(
1011f42103ceSTaewook Oh Filename, *this, IncludeLoc, SearchPath, RelativePath, RequestingModule,
1012421380a1SVolodymyr Sapsai SuggestedModule, InUserSpecifiedSystemFramework, IsFrameworkFoundInDir,
10132f843616SVolodymyr Sapsai IsInHeaderMap, MappedName);
10142f843616SVolodymyr Sapsai if (!MappedName.empty()) {
10152f843616SVolodymyr Sapsai assert(IsInHeaderMap && "MappedName should come from a header map");
101634fad420SArgyrios Kyrtzidis CacheLookup.MappedName =
10172f843616SVolodymyr Sapsai copyString(MappedName, LookupFileCache.getAllocator());
101834fad420SArgyrios Kyrtzidis }
10192f843616SVolodymyr Sapsai if (IsMapped)
10202f843616SVolodymyr Sapsai // A filename is mapped when a header map remapped it to a relative path
10212f843616SVolodymyr Sapsai // used in subsequent header search or to an absolute path pointing to an
10222f843616SVolodymyr Sapsai // existing file.
10232f843616SVolodymyr Sapsai *IsMapped |= (!MappedName.empty() || (IsInHeaderMap && File));
1024421380a1SVolodymyr Sapsai if (IsFrameworkFound)
1025e32ff096SVolodymyr Sapsai // Because we keep a filename remapped for subsequent search directory
1026e32ff096SVolodymyr Sapsai // lookups, ignore IsFrameworkFoundInDir after the first remapping and not
1027e32ff096SVolodymyr Sapsai // just for remapping in a current search directory.
1028e32ff096SVolodymyr Sapsai *IsFrameworkFound |= (IsFrameworkFoundInDir && !CacheLookup.MappedName);
10294dc5573aSAlex Lorenz if (!File)
10304dc5573aSAlex Lorenz continue;
10317a51313dSChris Lattner
103217c9fcd6SJan Svoboda CurDir = It;
10337a51313dSChris Lattner
1034b6c67c3cSCyndy Ishida const auto FE = &File->getFileEntry();
1035b6c67c3cSCyndy Ishida IncludeNames[FE] = Filename;
1036b6c67c3cSCyndy Ishida
10377a51313dSChris Lattner // This file is a system header or C++ unfriendly if the dir is.
1038b6c67c3cSCyndy Ishida HeaderFileInfo &HFI = getFileInfo(FE);
10399f93e38aSDouglas Gregor HFI.DirInfo = CurDir->getDirCharacteristic();
10409f93e38aSDouglas Gregor
10413c9bc4dbSDaniel Dunbar // If the directory characteristic is User but this framework was
10423c9bc4dbSDaniel Dunbar // user-specified to be treated as a system framework, promote the
10433c9bc4dbSDaniel Dunbar // characteristic.
10443c9bc4dbSDaniel Dunbar if (HFI.DirInfo == SrcMgr::C_User && InUserSpecifiedSystemFramework)
10453c9bc4dbSDaniel Dunbar HFI.DirInfo = SrcMgr::C_System;
10463c9bc4dbSDaniel Dunbar
10478acadcb8SRichard Smith // If the filename matches a known system header prefix, override
10488acadcb8SRichard Smith // whether the file is a system header.
1049871f5f32SRichard Trieu for (unsigned j = SystemHeaderPrefixes.size(); j; --j) {
1050871f5f32SRichard Trieu if (Filename.startswith(SystemHeaderPrefixes[j-1].first)) {
1051871f5f32SRichard Trieu HFI.DirInfo = SystemHeaderPrefixes[j-1].second ? SrcMgr::C_System
10528acadcb8SRichard Smith : SrcMgr::C_User;
10538acadcb8SRichard Smith break;
10548acadcb8SRichard Smith }
10558acadcb8SRichard Smith }
10568acadcb8SRichard Smith
10579385ece9SDavid Goldman // Set the `Framework` info if this file is in a header map with framework
10589385ece9SDavid Goldman // style include spelling or found in a framework dir. The header map case
10599385ece9SDavid Goldman // is possible when building frameworks which use header maps.
1060395e1fe3SCyndy Ishida if (CurDir->isHeaderMap() && isAngled) {
10619f93e38aSDouglas Gregor size_t SlashPos = Filename.find('/');
1062395e1fe3SCyndy Ishida if (SlashPos != StringRef::npos)
1063395e1fe3SCyndy Ishida HFI.Framework =
1064395e1fe3SCyndy Ishida getUniqueFrameworkName(StringRef(Filename.begin(), SlashPos));
1065395e1fe3SCyndy Ishida if (CurDir->isIndexHeaderMap())
10669f93e38aSDouglas Gregor HFI.IndexHeaderMapHeader = 1;
10679385ece9SDavid Goldman } else if (CurDir->isFramework()) {
10689385ece9SDavid Goldman size_t SlashPos = Filename.find('/');
10699385ece9SDavid Goldman if (SlashPos != StringRef::npos)
10709385ece9SDavid Goldman HFI.Framework =
10719385ece9SDavid Goldman getUniqueFrameworkName(StringRef(Filename.begin(), SlashPos));
10729f93e38aSDouglas Gregor }
10737a51313dSChris Lattner
10744dc5573aSAlex Lorenz if (checkMSVCHeaderSearch(Diags, MSFE ? &MSFE->getFileEntry() : nullptr,
10754dc5573aSAlex Lorenz &File->getFileEntry(), IncludeLoc)) {
10768c71eba1SRichard Smith if (SuggestedModule)
10778c71eba1SRichard Smith *SuggestedModule = MSSuggestedModule;
1078a97d4c06SReid Kleckner return MSFE;
10798c71eba1SRichard Smith }
1080a97d4c06SReid Kleckner
1081a9c51fe0SBruno Cardoso Lopes bool FoundByHeaderMap = !IsMapped ? false : *IsMapped;
1082a9c51fe0SBruno Cardoso Lopes if (!Includers.empty())
10834dc5573aSAlex Lorenz diagnoseFrameworkInclude(
10844dc5573aSAlex Lorenz Diags, IncludeLoc, Includers.front().second->getName(), Filename,
10854dc5573aSAlex Lorenz &File->getFileEntry(), isAngled, FoundByHeaderMap);
1086a9c51fe0SBruno Cardoso Lopes
10877a51313dSChris Lattner // Remember this location for the next lookup we do.
108817c9fcd6SJan Svoboda cacheLookupSuccess(CacheLookup, It, IncludeLoc);
10894dc5573aSAlex Lorenz return File;
10907a51313dSChris Lattner }
10917a51313dSChris Lattner
1092d8575e1eSDouglas Gregor // If we are including a file with a quoted include "foo.h" from inside
1093d8575e1eSDouglas Gregor // a header in a framework that is currently being built, and we couldn't
1094d8575e1eSDouglas Gregor // resolve "foo.h" any other way, change the include to <Foo/foo.h>, where
1095d8575e1eSDouglas Gregor // "Foo" is the name of the framework in which the including header was found.
10963c1a41adSRichard Smith if (!Includers.empty() && Includers.front().first && !isAngled &&
1097dccfaddcSKazu Hirata !Filename.contains('/')) {
10989af34aeaSManuel Klimek HeaderFileInfo &IncludingHFI = getFileInfo(Includers.front().first);
1099d8575e1eSDouglas Gregor if (IncludingHFI.IndexHeaderMapHeader) {
11002c1dd271SDylan Noblesmith SmallString<128> ScratchFilename;
1101d8575e1eSDouglas Gregor ScratchFilename += IncludingHFI.Framework;
1102d8575e1eSDouglas Gregor ScratchFilename += '/';
1103d8575e1eSDouglas Gregor ScratchFilename += Filename;
1104d8575e1eSDouglas Gregor
11054dc5573aSAlex Lorenz Optional<FileEntryRef> File = LookupFile(
1106105c9131SJan Svoboda ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, &CurDir,
1107421380a1SVolodymyr Sapsai Includers.front(), SearchPath, RelativePath, RequestingModule,
1108421380a1SVolodymyr Sapsai SuggestedModule, IsMapped, /*IsFrameworkFound=*/nullptr);
1109a97d4c06SReid Kleckner
11104dc5573aSAlex Lorenz if (checkMSVCHeaderSearch(Diags, MSFE ? &MSFE->getFileEntry() : nullptr,
11114dc5573aSAlex Lorenz File ? &File->getFileEntry() : nullptr,
11124dc5573aSAlex Lorenz IncludeLoc)) {
11138c71eba1SRichard Smith if (SuggestedModule)
11148c71eba1SRichard Smith *SuggestedModule = MSSuggestedModule;
1115a97d4c06SReid Kleckner return MSFE;
11168c71eba1SRichard Smith }
1117a97d4c06SReid Kleckner
111844451351SJan Svoboda cacheLookupSuccess(LookupFileCache[Filename],
111917c9fcd6SJan Svoboda LookupFileCache[ScratchFilename].HitIt, IncludeLoc);
11208c71eba1SRichard Smith // FIXME: SuggestedModule.
11214dc5573aSAlex Lorenz return File;
1122d8575e1eSDouglas Gregor }
1123d8575e1eSDouglas Gregor }
1124d8575e1eSDouglas Gregor
11254dc5573aSAlex Lorenz if (checkMSVCHeaderSearch(Diags, MSFE ? &MSFE->getFileEntry() : nullptr,
11264dc5573aSAlex Lorenz nullptr, IncludeLoc)) {
11278c71eba1SRichard Smith if (SuggestedModule)
11288c71eba1SRichard Smith *SuggestedModule = MSSuggestedModule;
1129a97d4c06SReid Kleckner return MSFE;
11308c71eba1SRichard Smith }
1131a97d4c06SReid Kleckner
11327a51313dSChris Lattner // Otherwise, didn't find it. Remember we didn't find this.
113317c9fcd6SJan Svoboda CacheLookup.HitIt = search_dir_end();
11344dc5573aSAlex Lorenz return None;
11357a51313dSChris Lattner }
11367a51313dSChris Lattner
11377a51313dSChris Lattner /// LookupSubframeworkHeader - Look up a subframework for the specified
1138c07ab2c9SJames Dennett /// \#include file. For example, if \#include'ing <HIToolbox/HIToolbox.h> from
11397a51313dSChris Lattner /// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox
11407a51313dSChris Lattner /// is a subframework within Carbon.framework. If so, return the FileEntry
11417a51313dSChris Lattner /// for the designated file, otherwise return null.
LookupSubframeworkHeader(StringRef Filename,const FileEntry * ContextFileEnt,SmallVectorImpl<char> * SearchPath,SmallVectorImpl<char> * RelativePath,Module * RequestingModule,ModuleMap::KnownHeader * SuggestedModule)11424dc5573aSAlex Lorenz Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
11434dc5573aSAlex Lorenz StringRef Filename, const FileEntry *ContextFileEnt,
11444dc5573aSAlex Lorenz SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
11454dc5573aSAlex Lorenz Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule) {
11467a51313dSChris Lattner assert(ContextFileEnt && "No context file?");
11477a51313dSChris Lattner
11487a51313dSChris Lattner // Framework names must have a '/' in the filename. Find it.
11495ca04bd4SDouglas Gregor // FIXME: Should we permit '\' on Windows?
1150d081f8c8SChris Lattner size_t SlashPos = Filename.find('/');
11514dc5573aSAlex Lorenz if (SlashPos == StringRef::npos)
11524dc5573aSAlex Lorenz return None;
11537a51313dSChris Lattner
11547a51313dSChris Lattner // Look up the base framework name of the ContextFileEnt.
1155004b9c7aSMehdi Amini StringRef ContextName = ContextFileEnt->getName();
11567a51313dSChris Lattner
11577a51313dSChris Lattner // If the context info wasn't a framework, couldn't be a subframework.
11585ca04bd4SDouglas Gregor const unsigned DotFrameworkLen = 10;
1159004b9c7aSMehdi Amini auto FrameworkPos = ContextName.find(".framework");
1160004b9c7aSMehdi Amini if (FrameworkPos == StringRef::npos ||
1161004b9c7aSMehdi Amini (ContextName[FrameworkPos + DotFrameworkLen] != '/' &&
1162004b9c7aSMehdi Amini ContextName[FrameworkPos + DotFrameworkLen] != '\\'))
11634dc5573aSAlex Lorenz return None;
11647a51313dSChris Lattner
1165004b9c7aSMehdi Amini SmallString<1024> FrameworkName(ContextName.data(), ContextName.data() +
1166004b9c7aSMehdi Amini FrameworkPos +
1167004b9c7aSMehdi Amini DotFrameworkLen + 1);
11687a51313dSChris Lattner
11697a51313dSChris Lattner // Append Frameworks/HIToolbox.framework/
11707a51313dSChris Lattner FrameworkName += "Frameworks/";
1171d081f8c8SChris Lattner FrameworkName.append(Filename.begin(), Filename.begin()+SlashPos);
11727a51313dSChris Lattner FrameworkName += ".framework/";
11737a51313dSChris Lattner
117413156b68SDavid Blaikie auto &CacheLookup =
117513156b68SDavid Blaikie *FrameworkMap.insert(std::make_pair(Filename.substr(0, SlashPos),
117613156b68SDavid Blaikie FrameworkCacheEntry())).first;
11777a51313dSChris Lattner
11787a51313dSChris Lattner // Some other location?
117913156b68SDavid Blaikie if (CacheLookup.second.Directory &&
118013156b68SDavid Blaikie CacheLookup.first().size() == FrameworkName.size() &&
118113156b68SDavid Blaikie memcmp(CacheLookup.first().data(), &FrameworkName[0],
118213156b68SDavid Blaikie CacheLookup.first().size()) != 0)
11834dc5573aSAlex Lorenz return None;
11847a51313dSChris Lattner
11857a51313dSChris Lattner // Cache subframework.
118613156b68SDavid Blaikie if (!CacheLookup.second.Directory) {
11877a51313dSChris Lattner ++NumSubFrameworkLookups;
11887a51313dSChris Lattner
11897a51313dSChris Lattner // If the framework dir doesn't exist, we fail.
1190f43ce519SJan Svoboda auto Dir = FileMgr.getOptionalDirectoryRef(FrameworkName);
11914dc5573aSAlex Lorenz if (!Dir)
11924dc5573aSAlex Lorenz return None;
11937a51313dSChris Lattner
11947a51313dSChris Lattner // Otherwise, if it does, remember that this is the right direntry for this
11957a51313dSChris Lattner // framework.
1196f43ce519SJan Svoboda CacheLookup.second.Directory = Dir;
11977a51313dSChris Lattner }
11987a51313dSChris Lattner
11997a51313dSChris Lattner
1200d2d442caSCraig Topper if (RelativePath) {
12010c69fd27SManuel Klimek RelativePath->clear();
12020c69fd27SManuel Klimek RelativePath->append(Filename.begin()+SlashPos+1, Filename.end());
12030c69fd27SManuel Klimek }
12040c69fd27SManuel Klimek
12057a51313dSChris Lattner // Check ".../Frameworks/HIToolbox.framework/Headers/HIToolbox.h"
12062c1dd271SDylan Noblesmith SmallString<1024> HeadersFilename(FrameworkName);
12077a51313dSChris Lattner HeadersFilename += "Headers/";
1208d2d442caSCraig Topper if (SearchPath) {
12090c69fd27SManuel Klimek SearchPath->clear();
12100c69fd27SManuel Klimek // Without trailing '/'.
12110c69fd27SManuel Klimek SearchPath->append(HeadersFilename.begin(), HeadersFilename.end()-1);
12120c69fd27SManuel Klimek }
12130c69fd27SManuel Klimek
1214d081f8c8SChris Lattner HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
12159ef6c49bSDuncan P. N. Exon Smith auto File = FileMgr.getOptionalFileRef(HeadersFilename, /*OpenFile=*/true);
12164dc5573aSAlex Lorenz if (!File) {
12177a51313dSChris Lattner // Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
12187a51313dSChris Lattner HeadersFilename = FrameworkName;
12197a51313dSChris Lattner HeadersFilename += "PrivateHeaders/";
1220d2d442caSCraig Topper if (SearchPath) {
12210c69fd27SManuel Klimek SearchPath->clear();
12220c69fd27SManuel Klimek // Without trailing '/'.
12230c69fd27SManuel Klimek SearchPath->append(HeadersFilename.begin(), HeadersFilename.end()-1);
12240c69fd27SManuel Klimek }
12250c69fd27SManuel Klimek
1226d081f8c8SChris Lattner HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
12279ef6c49bSDuncan P. N. Exon Smith File = FileMgr.getOptionalFileRef(HeadersFilename, /*OpenFile=*/true);
12288d323d15SHarlan Haskins
12294dc5573aSAlex Lorenz if (!File)
12304dc5573aSAlex Lorenz return None;
12317a51313dSChris Lattner }
12327a51313dSChris Lattner
12337a51313dSChris Lattner // This file is a system header or C++ unfriendly if the old file is.
12347a51313dSChris Lattner //
12357a51313dSChris Lattner // Note that the temporary 'DirInfo' is required here, as either call to
12367a51313dSChris Lattner // getFileInfo could resize the vector and we don't want to rely on order
12377a51313dSChris Lattner // of evaluation.
12387a51313dSChris Lattner unsigned DirInfo = getFileInfo(ContextFileEnt).DirInfo;
12394dc5573aSAlex Lorenz getFileInfo(&File->getFileEntry()).DirInfo = DirInfo;
1240f5f94528SDouglas Gregor
1241f5f94528SDouglas Gregor FrameworkName.pop_back(); // remove the trailing '/'
12424dc5573aSAlex Lorenz if (!findUsableModuleForFrameworkHeader(&File->getFileEntry(), FrameworkName,
12434dc5573aSAlex Lorenz RequestingModule, SuggestedModule,
12444dc5573aSAlex Lorenz /*IsSystem*/ false))
12454dc5573aSAlex Lorenz return None;
1246f5f94528SDouglas Gregor
12474dc5573aSAlex Lorenz return *File;
12487a51313dSChris Lattner }
12497a51313dSChris Lattner
12507a51313dSChris Lattner //===----------------------------------------------------------------------===//
12517a51313dSChris Lattner // File Info Management.
12527a51313dSChris Lattner //===----------------------------------------------------------------------===//
12537a51313dSChris Lattner
12549fc8faf9SAdrian Prantl /// Merge the header file info provided by \p OtherHFI into the current
12555d1bee25SDouglas Gregor /// header file info (\p HFI)
mergeHeaderFileInfo(HeaderFileInfo & HFI,const HeaderFileInfo & OtherHFI)12565d1bee25SDouglas Gregor static void mergeHeaderFileInfo(HeaderFileInfo &HFI,
12575d1bee25SDouglas Gregor const HeaderFileInfo &OtherHFI) {
1258d8879c85SRichard Smith assert(OtherHFI.External && "expected to merge external HFI");
1259d8879c85SRichard Smith
12605d1bee25SDouglas Gregor HFI.isImport |= OtherHFI.isImport;
12615d1bee25SDouglas Gregor HFI.isPragmaOnce |= OtherHFI.isPragmaOnce;
1262b146baabSArgyrios Kyrtzidis HFI.isModuleHeader |= OtherHFI.isModuleHeader;
12635d1bee25SDouglas Gregor
12645d1bee25SDouglas Gregor if (!HFI.ControllingMacro && !HFI.ControllingMacroID) {
12655d1bee25SDouglas Gregor HFI.ControllingMacro = OtherHFI.ControllingMacro;
12665d1bee25SDouglas Gregor HFI.ControllingMacroID = OtherHFI.ControllingMacroID;
12675d1bee25SDouglas Gregor }
12685d1bee25SDouglas Gregor
12695d1bee25SDouglas Gregor HFI.DirInfo = OtherHFI.DirInfo;
1270d8879c85SRichard Smith HFI.External = (!HFI.IsValid || HFI.External);
1271d8879c85SRichard Smith HFI.IsValid = true;
12725d1bee25SDouglas Gregor HFI.IndexHeaderMapHeader = OtherHFI.IndexHeaderMapHeader;
12735d1bee25SDouglas Gregor
12745d1bee25SDouglas Gregor if (HFI.Framework.empty())
12755d1bee25SDouglas Gregor HFI.Framework = OtherHFI.Framework;
12765d1bee25SDouglas Gregor }
12777a51313dSChris Lattner
12783fa455a1SSteve Naroff /// getFileInfo - Return the HeaderFileInfo structure for the specified
12797a51313dSChris Lattner /// FileEntry.
getFileInfo(const FileEntry * FE)12803fa455a1SSteve Naroff HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
12817a51313dSChris Lattner if (FE->getUID() >= FileInfo.size())
12827a51313dSChris Lattner FileInfo.resize(FE->getUID() + 1);
128309b6989eSDouglas Gregor
1284d8879c85SRichard Smith HeaderFileInfo *HFI = &FileInfo[FE->getUID()];
1285386bb073SRichard Smith // FIXME: Use a generation count to check whether this is really up to date.
1286d8879c85SRichard Smith if (ExternalSource && !HFI->Resolved) {
1287d8879c85SRichard Smith auto ExternalHFI = ExternalSource->GetHeaderFileInfo(FE);
12887ac737e5SVolodymyr Sapsai if (ExternalHFI.IsValid) {
12897ac737e5SVolodymyr Sapsai HFI->Resolved = true;
1290d8879c85SRichard Smith if (ExternalHFI.External)
1291d8879c85SRichard Smith mergeHeaderFileInfo(*HFI, ExternalHFI);
1292386bb073SRichard Smith }
12937ac737e5SVolodymyr Sapsai }
1294386bb073SRichard Smith
1295d8879c85SRichard Smith HFI->IsValid = true;
1296386bb073SRichard Smith // We have local information about this header file, so it's no longer
1297386bb073SRichard Smith // strictly external.
1298d8879c85SRichard Smith HFI->External = false;
1299d8879c85SRichard Smith return *HFI;
13007a51313dSChris Lattner }
13017a51313dSChris Lattner
1302386bb073SRichard Smith const HeaderFileInfo *
getExistingFileInfo(const FileEntry * FE,bool WantExternal) const1303d8879c85SRichard Smith HeaderSearch::getExistingFileInfo(const FileEntry *FE,
1304d8879c85SRichard Smith bool WantExternal) const {
1305386bb073SRichard Smith // If we have an external source, ensure we have the latest information.
1306386bb073SRichard Smith // FIXME: Use a generation count to check whether this is really up to date.
1307d8879c85SRichard Smith HeaderFileInfo *HFI;
1308d8879c85SRichard Smith if (ExternalSource) {
1309d8879c85SRichard Smith if (FE->getUID() >= FileInfo.size()) {
1310d8879c85SRichard Smith if (!WantExternal)
1311d8879c85SRichard Smith return nullptr;
1312386bb073SRichard Smith FileInfo.resize(FE->getUID() + 1);
1313386bb073SRichard Smith }
1314386bb073SRichard Smith
1315d8879c85SRichard Smith HFI = &FileInfo[FE->getUID()];
1316d8879c85SRichard Smith if (!WantExternal && (!HFI->IsValid || HFI->External))
1317d8879c85SRichard Smith return nullptr;
1318d8879c85SRichard Smith if (!HFI->Resolved) {
1319d8879c85SRichard Smith auto ExternalHFI = ExternalSource->GetHeaderFileInfo(FE);
13207ac737e5SVolodymyr Sapsai if (ExternalHFI.IsValid) {
13217ac737e5SVolodymyr Sapsai HFI->Resolved = true;
1322d8879c85SRichard Smith if (ExternalHFI.External)
1323d8879c85SRichard Smith mergeHeaderFileInfo(*HFI, ExternalHFI);
1324d8879c85SRichard Smith }
13257ac737e5SVolodymyr Sapsai }
1326d8879c85SRichard Smith } else if (FE->getUID() >= FileInfo.size()) {
1327d8879c85SRichard Smith return nullptr;
1328d8879c85SRichard Smith } else {
1329d8879c85SRichard Smith HFI = &FileInfo[FE->getUID()];
1330d8879c85SRichard Smith }
1331d8879c85SRichard Smith
1332d8879c85SRichard Smith if (!HFI->IsValid || (HFI->External && !WantExternal))
1333386bb073SRichard Smith return nullptr;
1334386bb073SRichard Smith
1335d8879c85SRichard Smith return HFI;
1336d285c503SBen Langmuir }
1337d285c503SBen Langmuir
isFileMultipleIncludeGuarded(const FileEntry * File)133837aa4938SDouglas Gregor bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) {
13390a088eadSRichard Smith // Check if we've entered this file and found an include guard or #pragma
13400a088eadSRichard Smith // once. Note that we dor't check for #import, because that's not a property
13410a088eadSRichard Smith // of the file itself.
1342386bb073SRichard Smith if (auto *HFI = getExistingFileInfo(File))
13430a088eadSRichard Smith return HFI->isPragmaOnce || HFI->ControllingMacro ||
1344386bb073SRichard Smith HFI->ControllingMacroID;
134537aa4938SDouglas Gregor return false;
134637aa4938SDouglas Gregor }
134737aa4938SDouglas Gregor
MarkFileModuleHeader(const FileEntry * FE,ModuleMap::ModuleHeaderRole Role,bool isCompilingModuleHeader)13486f722b4eSArgyrios Kyrtzidis void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE,
1349b53e5483SLawrence Crowl ModuleMap::ModuleHeaderRole Role,
13506f722b4eSArgyrios Kyrtzidis bool isCompilingModuleHeader) {
1351d8879c85SRichard Smith bool isModularHeader = !(Role & ModuleMap::TextualHeader);
1352d8879c85SRichard Smith
1353d8879c85SRichard Smith // Don't mark the file info as non-external if there's nothing to change.
1354d8879c85SRichard Smith if (!isCompilingModuleHeader) {
1355d8879c85SRichard Smith if (!isModularHeader)
1356d8879c85SRichard Smith return;
1357d8879c85SRichard Smith auto *HFI = getExistingFileInfo(FE);
1358d8879c85SRichard Smith if (HFI && HFI->isModuleHeader)
1359d8879c85SRichard Smith return;
1360d8879c85SRichard Smith }
1361d8879c85SRichard Smith
1362386bb073SRichard Smith auto &HFI = getFileInfo(FE);
1363d8879c85SRichard Smith HFI.isModuleHeader |= isModularHeader;
1364e70dadd6SRichard Smith HFI.isCompilingModuleHeader |= isCompilingModuleHeader;
1365b146baabSArgyrios Kyrtzidis }
1366b146baabSArgyrios Kyrtzidis
ShouldEnterIncludeFile(Preprocessor & PP,const FileEntry * File,bool isImport,bool ModulesEnabled,Module * M,bool & IsFirstIncludeOfFile)136720e883e5SRichard Smith bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
1368ba1b5c98SBruno Cardoso Lopes const FileEntry *File, bool isImport,
1369197576c4SJan Svoboda bool ModulesEnabled, Module *M,
1370197576c4SJan Svoboda bool &IsFirstIncludeOfFile) {
13717a51313dSChris Lattner ++NumIncluded; // Count # of attempted #includes.
13727a51313dSChris Lattner
1373197576c4SJan Svoboda IsFirstIncludeOfFile = false;
1374197576c4SJan Svoboda
13757a51313dSChris Lattner // Get information about this file.
13763fa455a1SSteve Naroff HeaderFileInfo &FileInfo = getFileInfo(File);
13777a51313dSChris Lattner
1378ba1b5c98SBruno Cardoso Lopes // FIXME: this is a workaround for the lack of proper modules-aware support
1379ba1b5c98SBruno Cardoso Lopes // for #import / #pragma once
1380afd1b1c9SEugene Zelenko auto TryEnterImported = [&]() -> bool {
1381ba1b5c98SBruno Cardoso Lopes if (!ModulesEnabled)
1382ba1b5c98SBruno Cardoso Lopes return false;
1383040e1266SRichard Smith // Ensure FileInfo bits are up to date.
1384040e1266SRichard Smith ModMap.resolveHeaderDirectives(File);
1385ba1b5c98SBruno Cardoso Lopes // Modules with builtins are special; multiple modules use builtins as
1386ba1b5c98SBruno Cardoso Lopes // modular headers, example:
1387ba1b5c98SBruno Cardoso Lopes //
1388ba1b5c98SBruno Cardoso Lopes // module stddef { header "stddef.h" export * }
1389ba1b5c98SBruno Cardoso Lopes //
1390ba1b5c98SBruno Cardoso Lopes // After module map parsing, this expands to:
1391ba1b5c98SBruno Cardoso Lopes //
1392ba1b5c98SBruno Cardoso Lopes // module stddef {
1393ba1b5c98SBruno Cardoso Lopes // header "/path_to_builtin_dirs/stddef.h"
1394ba1b5c98SBruno Cardoso Lopes // textual "stddef.h"
1395ba1b5c98SBruno Cardoso Lopes // }
1396ba1b5c98SBruno Cardoso Lopes //
1397ba1b5c98SBruno Cardoso Lopes // It's common that libc++ and system modules will both define such
1398ba1b5c98SBruno Cardoso Lopes // submodules. Make sure cached results for a builtin header won't
13998d74de9dSMartin Boehme // prevent other builtin modules from potentially entering the builtin
14008d74de9dSMartin Boehme // header. Note that builtins are header guarded and the decision to
14018d74de9dSMartin Boehme // actually enter them is postponed to the controlling macros logic below.
1402ba1b5c98SBruno Cardoso Lopes bool TryEnterHdr = false;
1403ba1b5c98SBruno Cardoso Lopes if (FileInfo.isCompilingModuleHeader && FileInfo.isModuleHeader)
14048d74de9dSMartin Boehme TryEnterHdr = ModMap.isBuiltinHeader(File);
1405ba1b5c98SBruno Cardoso Lopes
1406ba1b5c98SBruno Cardoso Lopes // Textual headers can be #imported from different modules. Since ObjC
1407ba1b5c98SBruno Cardoso Lopes // headers find in the wild might rely only on #import and do not contain
1408ba1b5c98SBruno Cardoso Lopes // controlling macros, be conservative and only try to enter textual headers
1409ba1b5c98SBruno Cardoso Lopes // if such macro is present.
14104164dd91SBruno Cardoso Lopes if (!FileInfo.isModuleHeader &&
1411ba1b5c98SBruno Cardoso Lopes FileInfo.getControllingMacro(ExternalLookup))
1412ba1b5c98SBruno Cardoso Lopes TryEnterHdr = true;
1413ba1b5c98SBruno Cardoso Lopes return TryEnterHdr;
1414ba1b5c98SBruno Cardoso Lopes };
1415ba1b5c98SBruno Cardoso Lopes
14167a51313dSChris Lattner // If this is a #import directive, check that we have not already imported
14177a51313dSChris Lattner // this header.
14187a51313dSChris Lattner if (isImport) {
14197a51313dSChris Lattner // If this has already been imported, don't import it again.
14207a51313dSChris Lattner FileInfo.isImport = true;
14217a51313dSChris Lattner
14227a51313dSChris Lattner // Has this already been #import'ed or #include'd?
1423f7202723SJan Svoboda if (PP.alreadyIncluded(File) && !TryEnterImported())
1424ba1b5c98SBruno Cardoso Lopes return false;
14257a51313dSChris Lattner } else {
14267a51313dSChris Lattner // Otherwise, if this is a #include of a file that was previously #import'd
14277a51313dSChris Lattner // or if this is the second #include of a #pragma once file, ignore it.
142864ebf313SVolodymyr Sapsai if ((FileInfo.isPragmaOnce || FileInfo.isImport) && !TryEnterImported())
14297a51313dSChris Lattner return false;
14307a51313dSChris Lattner }
14317a51313dSChris Lattner
14327a51313dSChris Lattner // Next, check to see if the file is wrapped with #ifndef guards. If so, and
14337a51313dSChris Lattner // if the macro that guards it is defined, we know the #include has no effect.
143499734e76SDouglas Gregor if (const IdentifierInfo *ControllingMacro
1435e70dadd6SRichard Smith = FileInfo.getControllingMacro(ExternalLookup)) {
1436e70dadd6SRichard Smith // If the header corresponds to a module, check whether the macro is already
1437e70dadd6SRichard Smith // defined in that module rather than checking in the current set of visible
1438e70dadd6SRichard Smith // modules.
1439e70dadd6SRichard Smith if (M ? PP.isMacroDefinedInLocalModule(ControllingMacro, M)
1440e70dadd6SRichard Smith : PP.isMacroDefined(ControllingMacro)) {
14417a51313dSChris Lattner ++NumMultiIncludeFileOptzn;
14427a51313dSChris Lattner return false;
14437a51313dSChris Lattner }
1444e70dadd6SRichard Smith }
14457a51313dSChris Lattner
1446f7202723SJan Svoboda IsFirstIncludeOfFile = PP.markIncluded(File);
1447197576c4SJan Svoboda
14487a51313dSChris Lattner return true;
14497a51313dSChris Lattner }
14507a51313dSChris Lattner
getTotalMemory() const1451fbcce6fbSTed Kremenek size_t HeaderSearch::getTotalMemory() const {
1452fbcce6fbSTed Kremenek return SearchDirs.capacity()
1453ae63d101STed Kremenek + llvm::capacity_in_bytes(FileInfo)
1454ae63d101STed Kremenek + llvm::capacity_in_bytes(HeaderMaps)
1455fbcce6fbSTed Kremenek + LookupFileCache.getAllocator().getTotalMemory()
1456fbcce6fbSTed Kremenek + FrameworkMap.getAllocator().getTotalMemory();
1457fbcce6fbSTed Kremenek }
14589f93e38aSDouglas Gregor
searchDirIdx(const DirectoryLookup & DL) const1459e7dcf09fSJan Svoboda unsigned HeaderSearch::searchDirIdx(const DirectoryLookup &DL) const {
1460e7dcf09fSJan Svoboda return &DL - &*SearchDirs.begin();
1461ccd7e783SJan Svoboda }
1462ccd7e783SJan Svoboda
getUniqueFrameworkName(StringRef Framework)14639f93e38aSDouglas Gregor StringRef HeaderSearch::getUniqueFrameworkName(StringRef Framework) {
146413156b68SDavid Blaikie return FrameworkNames.insert(Framework).first->first();
14659f93e38aSDouglas Gregor }
1466718292f2SDouglas Gregor
getIncludeNameForHeader(const FileEntry * File) const1467b6c67c3cSCyndy Ishida StringRef HeaderSearch::getIncludeNameForHeader(const FileEntry *File) const {
1468b6c67c3cSCyndy Ishida auto It = IncludeNames.find(File);
1469b6c67c3cSCyndy Ishida if (It == IncludeNames.end())
1470b6c67c3cSCyndy Ishida return {};
1471b6c67c3cSCyndy Ishida return It->second;
1472b6c67c3cSCyndy Ishida }
1473b6c67c3cSCyndy Ishida
hasModuleMap(StringRef FileName,const DirectoryEntry * Root,bool IsSystem)1474718292f2SDouglas Gregor bool HeaderSearch::hasModuleMap(StringRef FileName,
1475963c5535SDouglas Gregor const DirectoryEntry *Root,
1476963c5535SDouglas Gregor bool IsSystem) {
147747972afdSRichard Smith if (!HSOpts->ImplicitModuleMaps)
14789955dbcaSArgyrios Kyrtzidis return false;
14799955dbcaSArgyrios Kyrtzidis
1480f857950dSDmitri Gribenko SmallVector<const DirectoryEntry *, 2> FixUpDirectories;
1481718292f2SDouglas Gregor
1482718292f2SDouglas Gregor StringRef DirName = FileName;
1483718292f2SDouglas Gregor do {
1484718292f2SDouglas Gregor // Get the parent directory name.
1485718292f2SDouglas Gregor DirName = llvm::sys::path::parent_path(DirName);
1486718292f2SDouglas Gregor if (DirName.empty())
1487718292f2SDouglas Gregor return false;
1488718292f2SDouglas Gregor
1489718292f2SDouglas Gregor // Determine whether this directory exists.
1490d9390b6aSJan Svoboda auto Dir = FileMgr.getOptionalDirectoryRef(DirName);
1491718292f2SDouglas Gregor if (!Dir)
1492718292f2SDouglas Gregor return false;
1493718292f2SDouglas Gregor
1494984e1df7SBen Langmuir // Try to load the module map file in this directory.
14958d323d15SHarlan Haskins switch (loadModuleMapFile(*Dir, IsSystem,
1496d9390b6aSJan Svoboda llvm::sys::path::extension(Dir->getName()) ==
14973c1a41adSRichard Smith ".framework")) {
149880b6904bSDouglas Gregor case LMM_NewlyLoaded:
149980b6904bSDouglas Gregor case LMM_AlreadyLoaded:
1500ca9f7381SDaniel Jasper // Success. All of the directories we stepped through inherit this module
1501ca9f7381SDaniel Jasper // map file.
1502ca9f7381SDaniel Jasper for (unsigned I = 0, N = FixUpDirectories.size(); I != N; ++I)
1503ca9f7381SDaniel Jasper DirectoryHasModuleMap[FixUpDirectories[I]] = true;
1504ca9f7381SDaniel Jasper return true;
150597da9178SDaniel Jasper
150697da9178SDaniel Jasper case LMM_NoDirectory:
150797da9178SDaniel Jasper case LMM_InvalidModuleMap:
150897da9178SDaniel Jasper break;
1509ca9f7381SDaniel Jasper }
1510ca9f7381SDaniel Jasper
1511af28ec80SDouglas Gregor // If we hit the top of our search, we're done.
15128d323d15SHarlan Haskins if (*Dir == Root)
1513718292f2SDouglas Gregor return false;
1514718292f2SDouglas Gregor
1515718292f2SDouglas Gregor // Keep track of all of the directories we checked, so we can mark them as
1516718292f2SDouglas Gregor // having module maps if we eventually do find a module map.
15178d323d15SHarlan Haskins FixUpDirectories.push_back(*Dir);
1518718292f2SDouglas Gregor } while (true);
1519718292f2SDouglas Gregor }
1520718292f2SDouglas Gregor
1521b53e5483SLawrence Crowl ModuleMap::KnownHeader
findModuleForHeader(const FileEntry * File,bool AllowTextual) const1522ed84df00SBruno Cardoso Lopes HeaderSearch::findModuleForHeader(const FileEntry *File,
1523ed84df00SBruno Cardoso Lopes bool AllowTextual) const {
1524b146baabSArgyrios Kyrtzidis if (ExternalSource) {
1525b146baabSArgyrios Kyrtzidis // Make sure the external source has handled header info about this file,
1526b146baabSArgyrios Kyrtzidis // which includes whether the file is part of a module.
1527386bb073SRichard Smith (void)getExistingFileInfo(File);
1528b146baabSArgyrios Kyrtzidis }
1529ed84df00SBruno Cardoso Lopes return ModMap.findModuleForHeader(File, AllowTextual);
1530ed84df00SBruno Cardoso Lopes }
1531ed84df00SBruno Cardoso Lopes
15320a088eadSRichard Smith ArrayRef<ModuleMap::KnownHeader>
findAllModulesForHeader(const FileEntry * File) const15330a088eadSRichard Smith HeaderSearch::findAllModulesForHeader(const FileEntry *File) const {
15340a088eadSRichard Smith if (ExternalSource) {
15350a088eadSRichard Smith // Make sure the external source has handled header info about this file,
15360a088eadSRichard Smith // which includes whether the file is part of a module.
15370a088eadSRichard Smith (void)getExistingFileInfo(File);
15380a088eadSRichard Smith }
15390a088eadSRichard Smith return ModMap.findAllModulesForHeader(File);
15400a088eadSRichard Smith }
15410a088eadSRichard Smith
suggestModule(HeaderSearch & HS,const FileEntry * File,Module * RequestingModule,ModuleMap::KnownHeader * SuggestedModule)1542ed84df00SBruno Cardoso Lopes static bool suggestModule(HeaderSearch &HS, const FileEntry *File,
1543ed84df00SBruno Cardoso Lopes Module *RequestingModule,
1544ed84df00SBruno Cardoso Lopes ModuleMap::KnownHeader *SuggestedModule) {
1545ed84df00SBruno Cardoso Lopes ModuleMap::KnownHeader Module =
1546ed84df00SBruno Cardoso Lopes HS.findModuleForHeader(File, /*AllowTextual*/true);
1547ed84df00SBruno Cardoso Lopes
1548ed84df00SBruno Cardoso Lopes // If this module specifies [no_undeclared_includes], we cannot find any
1549ed84df00SBruno Cardoso Lopes // file that's in a non-dependency module.
1550ed84df00SBruno Cardoso Lopes if (RequestingModule && Module && RequestingModule->NoUndeclaredIncludes) {
1551ed84df00SBruno Cardoso Lopes HS.getModuleMap().resolveUses(RequestingModule, /*Complain*/ false);
1552ed84df00SBruno Cardoso Lopes if (!RequestingModule->directlyUses(Module.getModule())) {
15538d74de9dSMartin Boehme // Builtin headers are a special case. Multiple modules can use the same
15548d74de9dSMartin Boehme // builtin as a modular header (see also comment in
15558d74de9dSMartin Boehme // ShouldEnterIncludeFile()), so the builtin header may have been
15568d74de9dSMartin Boehme // "claimed" by an unrelated module. This shouldn't prevent us from
15578d74de9dSMartin Boehme // including the builtin header textually in this module.
15588d74de9dSMartin Boehme if (HS.getModuleMap().isBuiltinHeader(File)) {
15598d74de9dSMartin Boehme if (SuggestedModule)
15608d74de9dSMartin Boehme *SuggestedModule = ModuleMap::KnownHeader();
15618d74de9dSMartin Boehme return true;
15628d74de9dSMartin Boehme }
1563ed84df00SBruno Cardoso Lopes return false;
1564ed84df00SBruno Cardoso Lopes }
1565ed84df00SBruno Cardoso Lopes }
1566ed84df00SBruno Cardoso Lopes
15678d74de9dSMartin Boehme if (SuggestedModule)
15688d74de9dSMartin Boehme *SuggestedModule = (Module.getRole() & ModuleMap::TextualHeader)
15698d74de9dSMartin Boehme ? ModuleMap::KnownHeader()
15708d74de9dSMartin Boehme : Module;
15718d74de9dSMartin Boehme
1572ed84df00SBruno Cardoso Lopes return true;
1573718292f2SDouglas Gregor }
1574718292f2SDouglas Gregor
findUsableModuleForHeader(const FileEntry * File,const DirectoryEntry * Root,Module * RequestingModule,ModuleMap::KnownHeader * SuggestedModule,bool IsSystemHeaderDir)15753d5b48c4SRichard Smith bool HeaderSearch::findUsableModuleForHeader(
15763d5b48c4SRichard Smith const FileEntry *File, const DirectoryEntry *Root, Module *RequestingModule,
15773d5b48c4SRichard Smith ModuleMap::KnownHeader *SuggestedModule, bool IsSystemHeaderDir) {
1578ed84df00SBruno Cardoso Lopes if (File && needModuleLookup(RequestingModule, SuggestedModule)) {
15793d5b48c4SRichard Smith // If there is a module that corresponds to this header, suggest it.
15803d5b48c4SRichard Smith hasModuleMap(File->getName(), Root, IsSystemHeaderDir);
1581ed84df00SBruno Cardoso Lopes return suggestModule(*this, File, RequestingModule, SuggestedModule);
15823d5b48c4SRichard Smith }
15833d5b48c4SRichard Smith return true;
15843d5b48c4SRichard Smith }
15853d5b48c4SRichard Smith
findUsableModuleForFrameworkHeader(const FileEntry * File,StringRef FrameworkName,Module * RequestingModule,ModuleMap::KnownHeader * SuggestedModule,bool IsSystemFramework)15863d5b48c4SRichard Smith bool HeaderSearch::findUsableModuleForFrameworkHeader(
15873d5b48c4SRichard Smith const FileEntry *File, StringRef FrameworkName, Module *RequestingModule,
15883d5b48c4SRichard Smith ModuleMap::KnownHeader *SuggestedModule, bool IsSystemFramework) {
15893d5b48c4SRichard Smith // If we're supposed to suggest a module, look for one now.
1590ed84df00SBruno Cardoso Lopes if (needModuleLookup(RequestingModule, SuggestedModule)) {
15913d5b48c4SRichard Smith // Find the top-level framework based on this framework.
15923d5b48c4SRichard Smith SmallVector<std::string, 4> SubmodulePath;
1593d9390b6aSJan Svoboda Optional<DirectoryEntryRef> TopFrameworkDir =
1594d9390b6aSJan Svoboda ::getTopFrameworkDir(FileMgr, FrameworkName, SubmodulePath);
1595d9390b6aSJan Svoboda assert(TopFrameworkDir && "Could not find the top-most framework dir");
15963d5b48c4SRichard Smith
15973d5b48c4SRichard Smith // Determine the name of the top-level framework.
15983d5b48c4SRichard Smith StringRef ModuleName = llvm::sys::path::stem(TopFrameworkDir->getName());
15993d5b48c4SRichard Smith
16003d5b48c4SRichard Smith // Load this framework module. If that succeeds, find the suggested module
16013d5b48c4SRichard Smith // for this header, if any.
1602d9390b6aSJan Svoboda loadFrameworkModule(ModuleName, *TopFrameworkDir, IsSystemFramework);
16033d5b48c4SRichard Smith
16043d5b48c4SRichard Smith // FIXME: This can find a module not part of ModuleName, which is
16053d5b48c4SRichard Smith // important so that we're consistent about whether this header
16063d5b48c4SRichard Smith // corresponds to a module. Possibly we should lock down framework modules
16073d5b48c4SRichard Smith // so that this is not possible.
1608ed84df00SBruno Cardoso Lopes return suggestModule(*this, File, RequestingModule, SuggestedModule);
16093d5b48c4SRichard Smith }
16103d5b48c4SRichard Smith return true;
16113d5b48c4SRichard Smith }
16123d5b48c4SRichard Smith
getPrivateModuleMap(const FileEntry * File,FileManager & FileMgr)16137799ef71SNico Weber static const FileEntry *getPrivateModuleMap(const FileEntry *File,
1614984e1df7SBen Langmuir FileManager &FileMgr) {
16157799ef71SNico Weber StringRef Filename = llvm::sys::path::filename(File->getName());
16167799ef71SNico Weber SmallString<128> PrivateFilename(File->getDir()->getName());
1617984e1df7SBen Langmuir if (Filename == "module.map")
16188030677bSDouglas Gregor llvm::sys::path::append(PrivateFilename, "module_private.map");
1619984e1df7SBen Langmuir else if (Filename == "module.modulemap")
1620984e1df7SBen Langmuir llvm::sys::path::append(PrivateFilename, "module.private.modulemap");
1621984e1df7SBen Langmuir else
16227799ef71SNico Weber return nullptr;
16237799ef71SNico Weber if (auto File = FileMgr.getFile(PrivateFilename))
16247799ef71SNico Weber return *File;
16257799ef71SNico Weber return nullptr;
16268030677bSDouglas Gregor }
16278030677bSDouglas Gregor
loadModuleMapFile(const FileEntry * File,bool IsSystem,FileID ID,unsigned * Offset,StringRef OriginalModuleMapFile)16287799ef71SNico Weber bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem,
16298b706104SRichard Smith FileID ID, unsigned *Offset,
16308b706104SRichard Smith StringRef OriginalModuleMapFile) {
16319acb99e3SRichard Smith // Find the directory for the module. For frameworks, that may require going
16329acb99e3SRichard Smith // up from the 'Modules' directory.
1633d9390b6aSJan Svoboda Optional<DirectoryEntryRef> Dir;
16348d323d15SHarlan Haskins if (getHeaderSearchOpts().ModuleMapFileHomeIsCwd) {
1635d9390b6aSJan Svoboda Dir = FileMgr.getOptionalDirectoryRef(".");
16368d323d15SHarlan Haskins } else {
16378b706104SRichard Smith if (!OriginalModuleMapFile.empty()) {
16388b706104SRichard Smith // We're building a preprocessed module map. Find or invent the directory
16398b706104SRichard Smith // that it originally occupied.
1640d9390b6aSJan Svoboda Dir = FileMgr.getOptionalDirectoryRef(
16418b706104SRichard Smith llvm::sys::path::parent_path(OriginalModuleMapFile));
1642d9390b6aSJan Svoboda if (!Dir) {
1643d9390b6aSJan Svoboda auto FakeFile = FileMgr.getVirtualFileRef(OriginalModuleMapFile, 0, 0);
1644d9390b6aSJan Svoboda Dir = FakeFile.getDir();
16458b706104SRichard Smith }
16468b706104SRichard Smith } else {
1647d9390b6aSJan Svoboda // TODO: Replace with `Dir = File.getDir()` when `File` is switched to
1648d9390b6aSJan Svoboda // `FileEntryRef`.
1649d9390b6aSJan Svoboda Dir = FileMgr.getOptionalDirectoryRef(File->getDir()->getName());
16508b706104SRichard Smith }
16518b706104SRichard Smith
1652d9390b6aSJan Svoboda assert(Dir && "parent must exist");
16539acb99e3SRichard Smith StringRef DirName(Dir->getName());
16549acb99e3SRichard Smith if (llvm::sys::path::filename(DirName) == "Modules") {
16559acb99e3SRichard Smith DirName = llvm::sys::path::parent_path(DirName);
16569acb99e3SRichard Smith if (DirName.endswith(".framework"))
1657d9390b6aSJan Svoboda if (auto MaybeDir = FileMgr.getOptionalDirectoryRef(DirName))
1658d9390b6aSJan Svoboda Dir = *MaybeDir;
16599acb99e3SRichard Smith // FIXME: This assert can fail if there's a race between the above check
16609acb99e3SRichard Smith // and the removal of the directory.
16619acb99e3SRichard Smith assert(Dir && "parent must exist");
16629acb99e3SRichard Smith }
16639acb99e3SRichard Smith }
16649acb99e3SRichard Smith
1665d9390b6aSJan Svoboda assert(Dir && "module map home directory must exist");
1666d9390b6aSJan Svoboda switch (loadModuleMapFileImpl(File, IsSystem, *Dir, ID, Offset)) {
1667984e1df7SBen Langmuir case LMM_AlreadyLoaded:
1668984e1df7SBen Langmuir case LMM_NewlyLoaded:
1669984e1df7SBen Langmuir return false;
1670984e1df7SBen Langmuir case LMM_NoDirectory:
1671984e1df7SBen Langmuir case LMM_InvalidModuleMap:
1672984e1df7SBen Langmuir return true;
1673984e1df7SBen Langmuir }
1674d8de5b68SAaron Ballman llvm_unreachable("Unknown load module map result");
1675984e1df7SBen Langmuir }
1676984e1df7SBen Langmuir
1677c192d194SBruno Cardoso Lopes HeaderSearch::LoadModuleMapResult
loadModuleMapFileImpl(const FileEntry * File,bool IsSystem,DirectoryEntryRef Dir,FileID ID,unsigned * Offset)16787799ef71SNico Weber HeaderSearch::loadModuleMapFileImpl(const FileEntry *File, bool IsSystem,
1679d9390b6aSJan Svoboda DirectoryEntryRef Dir, FileID ID,
1680c192d194SBruno Cardoso Lopes unsigned *Offset) {
16817799ef71SNico Weber assert(File && "expected FileEntry");
16827799ef71SNico Weber
16839887d79aSRichard Smith // Check whether we've already loaded this module map, and mark it as being
16849887d79aSRichard Smith // loaded in case we recursively try to load it from itself.
16859887d79aSRichard Smith auto AddResult = LoadedModuleMaps.insert(std::make_pair(File, true));
16869887d79aSRichard Smith if (!AddResult.second)
16879887d79aSRichard Smith return AddResult.first->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
1688984e1df7SBen Langmuir
1689c192d194SBruno Cardoso Lopes if (ModMap.parseModuleMapFile(File, IsSystem, Dir, ID, Offset)) {
16909887d79aSRichard Smith LoadedModuleMaps[File] = false;
1691984e1df7SBen Langmuir return LMM_InvalidModuleMap;
1692984e1df7SBen Langmuir }
1693984e1df7SBen Langmuir
1694984e1df7SBen Langmuir // Try to load a corresponding private module map.
16957799ef71SNico Weber if (const FileEntry *PMMFile = getPrivateModuleMap(File, FileMgr)) {
16967799ef71SNico Weber if (ModMap.parseModuleMapFile(PMMFile, IsSystem, Dir)) {
16979887d79aSRichard Smith LoadedModuleMaps[File] = false;
1698984e1df7SBen Langmuir return LMM_InvalidModuleMap;
1699984e1df7SBen Langmuir }
1700984e1df7SBen Langmuir }
1701984e1df7SBen Langmuir
1702984e1df7SBen Langmuir // This directory has a module map.
1703984e1df7SBen Langmuir return LMM_NewlyLoaded;
1704984e1df7SBen Langmuir }
1705984e1df7SBen Langmuir
17067799ef71SNico Weber const FileEntry *
lookupModuleMapFile(const DirectoryEntry * Dir,bool IsFramework)1707984e1df7SBen Langmuir HeaderSearch::lookupModuleMapFile(const DirectoryEntry *Dir, bool IsFramework) {
170847972afdSRichard Smith if (!HSOpts->ImplicitModuleMaps)
17097799ef71SNico Weber return nullptr;
1710984e1df7SBen Langmuir // For frameworks, the preferred spelling is Modules/module.modulemap, but
1711984e1df7SBen Langmuir // module.map at the framework root is also accepted.
1712984e1df7SBen Langmuir SmallString<128> ModuleMapFileName(Dir->getName());
1713984e1df7SBen Langmuir if (IsFramework)
1714984e1df7SBen Langmuir llvm::sys::path::append(ModuleMapFileName, "Modules");
1715984e1df7SBen Langmuir llvm::sys::path::append(ModuleMapFileName, "module.modulemap");
17167799ef71SNico Weber if (auto F = FileMgr.getFile(ModuleMapFileName))
17177799ef71SNico Weber return *F;
1718984e1df7SBen Langmuir
1719984e1df7SBen Langmuir // Continue to allow module.map
1720984e1df7SBen Langmuir ModuleMapFileName = Dir->getName();
1721984e1df7SBen Langmuir llvm::sys::path::append(ModuleMapFileName, "module.map");
17227799ef71SNico Weber if (auto F = FileMgr.getFile(ModuleMapFileName))
17237799ef71SNico Weber return *F;
17244069dd14SVolodymyr Sapsai
17254069dd14SVolodymyr Sapsai // For frameworks, allow to have a private module map with a preferred
17264069dd14SVolodymyr Sapsai // spelling when a public module map is absent.
17274069dd14SVolodymyr Sapsai if (IsFramework) {
17284069dd14SVolodymyr Sapsai ModuleMapFileName = Dir->getName();
17294069dd14SVolodymyr Sapsai llvm::sys::path::append(ModuleMapFileName, "Modules",
17304069dd14SVolodymyr Sapsai "module.private.modulemap");
17317799ef71SNico Weber if (auto F = FileMgr.getFile(ModuleMapFileName))
17327799ef71SNico Weber return *F;
17334069dd14SVolodymyr Sapsai }
17347799ef71SNico Weber return nullptr;
17352b20cb87SDouglas Gregor }
17362b20cb87SDouglas Gregor
loadFrameworkModule(StringRef Name,DirectoryEntryRef Dir,bool IsSystem)1737d9390b6aSJan Svoboda Module *HeaderSearch::loadFrameworkModule(StringRef Name, DirectoryEntryRef Dir,
1738a686e1b0SDouglas Gregor bool IsSystem) {
1739de3ef502SDouglas Gregor if (Module *Module = ModMap.findModule(Name))
174056c64013SDouglas Gregor return Module;
174156c64013SDouglas Gregor
174256c64013SDouglas Gregor // Try to load a module map file.
1743984e1df7SBen Langmuir switch (loadModuleMapFile(Dir, IsSystem, /*IsFramework*/true)) {
174456c64013SDouglas Gregor case LMM_InvalidModuleMap:
1745a525400dSBen Langmuir // Try to infer a module map from the framework directory.
1746a525400dSBen Langmuir if (HSOpts->ImplicitModuleMaps)
1747a525400dSBen Langmuir ModMap.inferFrameworkModule(Dir, IsSystem, /*Parent=*/nullptr);
174856c64013SDouglas Gregor break;
174956c64013SDouglas Gregor
175056c64013SDouglas Gregor case LMM_AlreadyLoaded:
175156c64013SDouglas Gregor case LMM_NoDirectory:
1752d2d442caSCraig Topper return nullptr;
175356c64013SDouglas Gregor
175456c64013SDouglas Gregor case LMM_NewlyLoaded:
1755a525400dSBen Langmuir break;
175656c64013SDouglas Gregor }
175756c64013SDouglas Gregor
1758a525400dSBen Langmuir return ModMap.findModule(Name);
175956c64013SDouglas Gregor }
176056c64013SDouglas Gregor
176180b6904bSDouglas Gregor HeaderSearch::LoadModuleMapResult
loadModuleMapFile(StringRef DirName,bool IsSystem,bool IsFramework)1762984e1df7SBen Langmuir HeaderSearch::loadModuleMapFile(StringRef DirName, bool IsSystem,
1763984e1df7SBen Langmuir bool IsFramework) {
1764d9390b6aSJan Svoboda if (auto Dir = FileMgr.getOptionalDirectoryRef(DirName))
17658d323d15SHarlan Haskins return loadModuleMapFile(*Dir, IsSystem, IsFramework);
1766af28ec80SDouglas Gregor
176780b6904bSDouglas Gregor return LMM_NoDirectory;
1768af28ec80SDouglas Gregor }
1769af28ec80SDouglas Gregor
177080b6904bSDouglas Gregor HeaderSearch::LoadModuleMapResult
loadModuleMapFile(DirectoryEntryRef Dir,bool IsSystem,bool IsFramework)1771d9390b6aSJan Svoboda HeaderSearch::loadModuleMapFile(DirectoryEntryRef Dir, bool IsSystem,
1772984e1df7SBen Langmuir bool IsFramework) {
1773984e1df7SBen Langmuir auto KnownDir = DirectoryHasModuleMap.find(Dir);
1774af28ec80SDouglas Gregor if (KnownDir != DirectoryHasModuleMap.end())
177580b6904bSDouglas Gregor return KnownDir->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
1776af28ec80SDouglas Gregor
17777799ef71SNico Weber if (const FileEntry *ModuleMapFile = lookupModuleMapFile(Dir, IsFramework)) {
1778c192d194SBruno Cardoso Lopes LoadModuleMapResult Result =
17797799ef71SNico Weber loadModuleMapFileImpl(ModuleMapFile, IsSystem, Dir);
1780984e1df7SBen Langmuir // Add Dir explicitly in case ModuleMapFile is in a subdirectory.
1781984e1df7SBen Langmuir // E.g. Foo.framework/Modules/module.modulemap
1782984e1df7SBen Langmuir // ^Dir ^ModuleMapFile
1783984e1df7SBen Langmuir if (Result == LMM_NewlyLoaded)
1784af28ec80SDouglas Gregor DirectoryHasModuleMap[Dir] = true;
17859887d79aSRichard Smith else if (Result == LMM_InvalidModuleMap)
17869887d79aSRichard Smith DirectoryHasModuleMap[Dir] = false;
1787984e1df7SBen Langmuir return Result;
1788af28ec80SDouglas Gregor }
178980b6904bSDouglas Gregor return LMM_InvalidModuleMap;
1790af28ec80SDouglas Gregor }
1791718292f2SDouglas Gregor
collectAllModules(SmallVectorImpl<Module * > & Modules)1792f857950dSDmitri Gribenko void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
179307f4357bSDouglas Gregor Modules.clear();
179407f4357bSDouglas Gregor
179547972afdSRichard Smith if (HSOpts->ImplicitModuleMaps) {
179607f4357bSDouglas Gregor // Load module maps for each of the header search directories.
1797e7dcf09fSJan Svoboda for (DirectoryLookup &DL : search_dir_range()) {
1798e7dcf09fSJan Svoboda bool IsSystem = DL.isSystemHeaderDirectory();
1799e7dcf09fSJan Svoboda if (DL.isFramework()) {
1800c080917eSRafael Espindola std::error_code EC;
18012c1dd271SDylan Noblesmith SmallString<128> DirNative;
1802e7dcf09fSJan Svoboda llvm::sys::path::native(DL.getFrameworkDir()->getName(), DirNative);
180307f4357bSDouglas Gregor
180407f4357bSDouglas Gregor // Search each of the ".framework" directories to load them as modules.
1805db8a7422SDuncan P. N. Exon Smith llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem();
1806fc51490bSJonas Devlieghere for (llvm::vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC),
1807fc51490bSJonas Devlieghere DirEnd;
180807f4357bSDouglas Gregor Dir != DirEnd && !EC; Dir.increment(EC)) {
18090ae00567SSam McCall if (llvm::sys::path::extension(Dir->path()) != ".framework")
181007f4357bSDouglas Gregor continue;
181107f4357bSDouglas Gregor
1812d9390b6aSJan Svoboda auto FrameworkDir = FileMgr.getOptionalDirectoryRef(Dir->path());
181307f4357bSDouglas Gregor if (!FrameworkDir)
181407f4357bSDouglas Gregor continue;
181507f4357bSDouglas Gregor
181607f4357bSDouglas Gregor // Load this framework module.
18178d323d15SHarlan Haskins loadFrameworkModule(llvm::sys::path::stem(Dir->path()), *FrameworkDir,
18180ae00567SSam McCall IsSystem);
181907f4357bSDouglas Gregor }
182007f4357bSDouglas Gregor continue;
182107f4357bSDouglas Gregor }
182207f4357bSDouglas Gregor
182307f4357bSDouglas Gregor // FIXME: Deal with header maps.
1824e7dcf09fSJan Svoboda if (DL.isHeaderMap())
182507f4357bSDouglas Gregor continue;
182607f4357bSDouglas Gregor
182707f4357bSDouglas Gregor // Try to load a module map file for the search directory.
1828d9390b6aSJan Svoboda loadModuleMapFile(*DL.getDirRef(), IsSystem, /*IsFramework*/ false);
182907f4357bSDouglas Gregor
183021a0f557SDaniel Jasper // Try to load module map files for immediate subdirectories of this
183121a0f557SDaniel Jasper // search directory.
1832e7dcf09fSJan Svoboda loadSubdirectoryModuleMaps(DL);
183307f4357bSDouglas Gregor }
183421a0f557SDaniel Jasper }
183507f4357bSDouglas Gregor
183607f4357bSDouglas Gregor // Populate the list of modules.
183732c2ea5cSJan Svoboda llvm::transform(ModMap.modules(), std::back_inserter(Modules),
183832c2ea5cSJan Svoboda [](const auto &NameAndMod) { return NameAndMod.second; });
183907f4357bSDouglas Gregor }
18400339a64aSDouglas Gregor
loadTopLevelSystemModules()184164a1fa5cSDouglas Gregor void HeaderSearch::loadTopLevelSystemModules() {
184247972afdSRichard Smith if (!HSOpts->ImplicitModuleMaps)
184321a0f557SDaniel Jasper return;
184421a0f557SDaniel Jasper
184564a1fa5cSDouglas Gregor // Load module maps for each of the header search directories.
1846e7dcf09fSJan Svoboda for (const DirectoryLookup &DL : search_dir_range()) {
1847299787f7SDouglas Gregor // We only care about normal header directories.
1848e7dcf09fSJan Svoboda if (!DL.isNormalDir())
184964a1fa5cSDouglas Gregor continue;
185064a1fa5cSDouglas Gregor
185164a1fa5cSDouglas Gregor // Try to load a module map file for the search directory.
1852d9390b6aSJan Svoboda loadModuleMapFile(*DL.getDirRef(), DL.isSystemHeaderDirectory(),
1853e7dcf09fSJan Svoboda DL.isFramework());
185464a1fa5cSDouglas Gregor }
185564a1fa5cSDouglas Gregor }
185664a1fa5cSDouglas Gregor
loadSubdirectoryModuleMaps(DirectoryLookup & SearchDir)18570339a64aSDouglas Gregor void HeaderSearch::loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir) {
185847972afdSRichard Smith assert(HSOpts->ImplicitModuleMaps &&
185921a0f557SDaniel Jasper "Should not be loading subdirectory module maps");
186021a0f557SDaniel Jasper
18610339a64aSDouglas Gregor if (SearchDir.haveSearchedAllModuleMaps())
18620339a64aSDouglas Gregor return;
18630339a64aSDouglas Gregor
1864c080917eSRafael Espindola std::error_code EC;
18657d76ef9bSAlex Lorenz SmallString<128> Dir = SearchDir.getDir()->getName();
18667d76ef9bSAlex Lorenz FileMgr.makeAbsolutePath(Dir);
18670339a64aSDouglas Gregor SmallString<128> DirNative;
18687d76ef9bSAlex Lorenz llvm::sys::path::native(Dir, DirNative);
1869db8a7422SDuncan P. N. Exon Smith llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem();
1870fc51490bSJonas Devlieghere for (llvm::vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd;
18710339a64aSDouglas Gregor Dir != DirEnd && !EC; Dir.increment(EC)) {
18720ae00567SSam McCall bool IsFramework = llvm::sys::path::extension(Dir->path()) == ".framework";
18731f6a32b3SBen Langmuir if (IsFramework == SearchDir.isFramework())
18740ae00567SSam McCall loadModuleMapFile(Dir->path(), SearchDir.isSystemHeaderDirectory(),
1875984e1df7SBen Langmuir SearchDir.isFramework());
18760339a64aSDouglas Gregor }
18770339a64aSDouglas Gregor
18780339a64aSDouglas Gregor SearchDir.setSearchedAllModuleMaps(true);
18790339a64aSDouglas Gregor }
18804eb8393cSRichard Smith
suggestPathToFileForDiagnostics(const FileEntry * File,llvm::StringRef MainFile,bool * IsSystem)18811f6d9845SKadir Cetinkaya std::string HeaderSearch::suggestPathToFileForDiagnostics(
18821f6d9845SKadir Cetinkaya const FileEntry *File, llvm::StringRef MainFile, bool *IsSystem) {
18834eb8393cSRichard Smith // FIXME: We assume that the path name currently cached in the FileEntry is
1884dffb1a80SEric Liu // the most appropriate one for this analysis (and that it's spelled the
1885dffb1a80SEric Liu // same way as the corresponding header search path).
18861f6d9845SKadir Cetinkaya return suggestPathToFileForDiagnostics(File->getName(), /*WorkingDir=*/"",
18871f6d9845SKadir Cetinkaya MainFile, IsSystem);
1888dffb1a80SEric Liu }
1889dffb1a80SEric Liu
suggestPathToFileForDiagnostics(llvm::StringRef File,llvm::StringRef WorkingDir,llvm::StringRef MainFile,bool * IsSystem)1890dffb1a80SEric Liu std::string HeaderSearch::suggestPathToFileForDiagnostics(
18911f6d9845SKadir Cetinkaya llvm::StringRef File, llvm::StringRef WorkingDir, llvm::StringRef MainFile,
18921f6d9845SKadir Cetinkaya bool *IsSystem) {
1893dffb1a80SEric Liu using namespace llvm::sys;
18944eb8393cSRichard Smith
18954eb8393cSRichard Smith unsigned BestPrefixLength = 0;
18960cf7e61aSDavid Goldman // Checks whether `Dir` is a strict path prefix of `File`. If so and that's
18970cf7e61aSDavid Goldman // the longest prefix we've seen so for it, returns true and updates the
18980cf7e61aSDavid Goldman // `BestPrefixLength` accordingly.
18991f6d9845SKadir Cetinkaya auto CheckDir = [&](llvm::StringRef Dir) -> bool {
1900dffb1a80SEric Liu llvm::SmallString<32> DirPath(Dir.begin(), Dir.end());
1901936c67d3SKadir Cetinkaya if (!WorkingDir.empty() && !path::is_absolute(Dir))
19021ad53ca2SPavel Labath fs::make_absolute(WorkingDir, DirPath);
1903dffb1a80SEric Liu path::remove_dots(DirPath, /*remove_dot_dot=*/true);
1904dffb1a80SEric Liu Dir = DirPath;
1905dffb1a80SEric Liu for (auto NI = path::begin(File), NE = path::end(File),
1906dffb1a80SEric Liu DI = path::begin(Dir), DE = path::end(Dir);
19074eb8393cSRichard Smith /*termination condition in loop*/; ++NI, ++DI) {
1908dffb1a80SEric Liu // '.' components in File are ignored.
19094eb8393cSRichard Smith while (NI != NE && *NI == ".")
19104eb8393cSRichard Smith ++NI;
19114eb8393cSRichard Smith if (NI == NE)
19124eb8393cSRichard Smith break;
19134eb8393cSRichard Smith
19144eb8393cSRichard Smith // '.' components in Dir are ignored.
19154eb8393cSRichard Smith while (DI != DE && *DI == ".")
19164eb8393cSRichard Smith ++DI;
19174eb8393cSRichard Smith if (DI == DE) {
1918dffb1a80SEric Liu // Dir is a prefix of File, up to '.' components and choice of path
19194eb8393cSRichard Smith // separators.
1920dffb1a80SEric Liu unsigned PrefixLength = NI - path::begin(File);
19214eb8393cSRichard Smith if (PrefixLength > BestPrefixLength) {
19224eb8393cSRichard Smith BestPrefixLength = PrefixLength;
19231f6d9845SKadir Cetinkaya return true;
19244eb8393cSRichard Smith }
19254eb8393cSRichard Smith break;
19264eb8393cSRichard Smith }
19274eb8393cSRichard Smith
192851f85b40SKadir Cetinkaya // Consider all path separators equal.
192951f85b40SKadir Cetinkaya if (NI->size() == 1 && DI->size() == 1 &&
193051f85b40SKadir Cetinkaya path::is_separator(NI->front()) && path::is_separator(DI->front()))
193151f85b40SKadir Cetinkaya continue;
193251f85b40SKadir Cetinkaya
19330cf7e61aSDavid Goldman // Special case Apple .sdk folders since the search path is typically a
19340cf7e61aSDavid Goldman // symlink like `iPhoneSimulator14.5.sdk` while the file is instead
19350cf7e61aSDavid Goldman // located in `iPhoneSimulator.sdk` (the real folder).
19360cf7e61aSDavid Goldman if (NI->endswith(".sdk") && DI->endswith(".sdk")) {
19370cf7e61aSDavid Goldman StringRef NBasename = path::stem(*NI);
19380cf7e61aSDavid Goldman StringRef DBasename = path::stem(*DI);
19390cf7e61aSDavid Goldman if (DBasename.startswith(NBasename))
19400cf7e61aSDavid Goldman continue;
19410cf7e61aSDavid Goldman }
19420cf7e61aSDavid Goldman
19434eb8393cSRichard Smith if (*NI != *DI)
19444eb8393cSRichard Smith break;
19454eb8393cSRichard Smith }
19461f6d9845SKadir Cetinkaya return false;
19471f6d9845SKadir Cetinkaya };
19481f6d9845SKadir Cetinkaya
19490cf7e61aSDavid Goldman bool BestPrefixIsFramework = false;
1950e7dcf09fSJan Svoboda for (const DirectoryLookup &DL : search_dir_range()) {
1951e7dcf09fSJan Svoboda if (DL.isNormalDir()) {
1952e7dcf09fSJan Svoboda StringRef Dir = DL.getDir()->getName();
19530cf7e61aSDavid Goldman if (CheckDir(Dir)) {
19540cf7e61aSDavid Goldman if (IsSystem)
1955e7dcf09fSJan Svoboda *IsSystem = BestPrefixLength && isSystem(DL.getDirCharacteristic());
19560cf7e61aSDavid Goldman BestPrefixIsFramework = false;
19570cf7e61aSDavid Goldman }
1958e7dcf09fSJan Svoboda } else if (DL.isFramework()) {
1959e7dcf09fSJan Svoboda StringRef Dir = DL.getFrameworkDir()->getName();
19600cf7e61aSDavid Goldman if (CheckDir(Dir)) {
19610cf7e61aSDavid Goldman if (IsSystem)
1962e7dcf09fSJan Svoboda *IsSystem = BestPrefixLength && isSystem(DL.getDirCharacteristic());
19630cf7e61aSDavid Goldman BestPrefixIsFramework = true;
19640cf7e61aSDavid Goldman }
19650cf7e61aSDavid Goldman }
19664eb8393cSRichard Smith }
19674eb8393cSRichard Smith
19681f6d9845SKadir Cetinkaya // Try to shorten include path using TUs directory, if we couldn't find any
19691f6d9845SKadir Cetinkaya // suitable prefix in include search paths.
19700cf7e61aSDavid Goldman if (!BestPrefixLength && CheckDir(path::parent_path(MainFile))) {
19710cf7e61aSDavid Goldman if (IsSystem)
19721f6d9845SKadir Cetinkaya *IsSystem = false;
19730cf7e61aSDavid Goldman BestPrefixIsFramework = false;
19740cf7e61aSDavid Goldman }
19751f6d9845SKadir Cetinkaya
1976178ad93eSDmitry Polukhin // Try resolving resulting filename via reverse search in header maps,
19775f57ca20SNico Weber // key from header name is user preferred name for the include file.
1978178ad93eSDmitry Polukhin StringRef Filename = File.drop_front(BestPrefixLength);
1979e7dcf09fSJan Svoboda for (const DirectoryLookup &DL : search_dir_range()) {
1980e7dcf09fSJan Svoboda if (!DL.isHeaderMap())
1981178ad93eSDmitry Polukhin continue;
19821f6d9845SKadir Cetinkaya
1983178ad93eSDmitry Polukhin StringRef SpelledFilename =
1984e7dcf09fSJan Svoboda DL.getHeaderMap()->reverseLookupFilename(Filename);
1985178ad93eSDmitry Polukhin if (!SpelledFilename.empty()) {
1986178ad93eSDmitry Polukhin Filename = SpelledFilename;
19870cf7e61aSDavid Goldman BestPrefixIsFramework = false;
1988178ad93eSDmitry Polukhin break;
1989178ad93eSDmitry Polukhin }
1990178ad93eSDmitry Polukhin }
19910cf7e61aSDavid Goldman
19920cf7e61aSDavid Goldman // If the best prefix is a framework path, we need to compute the proper
19930cf7e61aSDavid Goldman // include spelling for the framework header.
19940cf7e61aSDavid Goldman bool IsPrivateHeader;
19950cf7e61aSDavid Goldman SmallString<128> FrameworkName, IncludeSpelling;
19960cf7e61aSDavid Goldman if (BestPrefixIsFramework &&
19970cf7e61aSDavid Goldman isFrameworkStylePath(Filename, IsPrivateHeader, FrameworkName,
19980cf7e61aSDavid Goldman IncludeSpelling)) {
19990cf7e61aSDavid Goldman Filename = IncludeSpelling;
20000cf7e61aSDavid Goldman }
2001178ad93eSDmitry Polukhin return path::convert_to_slash(Filename);
20024eb8393cSRichard Smith }
2003