#include "clang/Lex/HeaderSearch.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
+#include "clang/Lex/ExternalPreprocessorSource.h"
#include "clang/Lex/HeaderMap.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
+#include <utility>
#if defined(LLVM_ON_UNIX)
#include <limits.h>
#endif
using namespace clang;
const IdentifierInfo *
-HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) {
- if (ControllingMacro)
+HeaderFileInfo::getControllingMacro(ExternalPreprocessorSource *External) {
+ if (ControllingMacro) {
+ if (ControllingMacro->isOutOfDate())
+ External->updateOutOfDateIdentifier(
+ *const_cast<IdentifierInfo *>(ControllingMacro));
return ControllingMacro;
+ }
if (!ControllingMacroID || !External)
return nullptr;
SourceManager &SourceMgr, DiagnosticsEngine &Diags,
const LangOptions &LangOpts,
const TargetInfo *Target)
- : HSOpts(HSOpts), Diags(Diags), FileMgr(SourceMgr.getFileManager()),
- FrameworkMap(64), ModMap(SourceMgr, Diags, LangOpts, Target, *this),
- LangOpts(LangOpts) {
+ : HSOpts(std::move(HSOpts)), Diags(Diags),
+ FileMgr(SourceMgr.getFileManager()), FrameworkMap(64),
+ ModMap(SourceMgr, Diags, LangOpts, Target, *this) {
AngledDirIdx = 0;
SystemDirIdx = 0;
NoCurDirSearch = false;
std::string HeaderSearch::getModuleFileName(Module *Module) {
const FileEntry *ModuleMap =
getModuleMap().getModuleMapFileForUniquing(Module);
- return getModuleFileName(Module->Name, ModuleMap->getName(),
- Module->IsSystem);
+ return getModuleFileName(Module->Name, ModuleMap->getName());
}
std::string HeaderSearch::getModuleFileName(StringRef ModuleName,
- StringRef ModuleMapPath,
- bool IsSystem) {
- // If we don't have a module cache path, we can't do anything.
- if (ModuleCachePath.empty())
+ StringRef ModuleMapPath) {
+ // If we don't have a module cache path or aren't supposed to use one, we
+ // can't do anything.
+ if (getModuleCachePath().empty())
return std::string();
- SmallString<256> Result(ModuleCachePath);
+ SmallString<256> Result(getModuleCachePath());
llvm::sys::fs::make_absolute(Result);
if (HSOpts->DisableModuleHash) {
auto FileName = llvm::sys::path::filename(ModuleMapPath);
llvm::hash_code Hash =
- llvm::hash_combine(DirName.lower(), FileName.lower());
-
- // Hash the IsSystem bit, since changing search paths can change whether a
- // module is considered 'system' or not.
- Hash = llvm::hash_combine(Hash, IsSystem);
+ llvm::hash_combine(DirName.lower(), FileName.lower());
SmallString<128> HashStr;
llvm::APInt(64, size_t(Hash)).toStringUnsigned(HashStr, /*Radix*/36);
- llvm::sys::path::append(Result, ModuleName + "-" + HashStr.str() + ".pcm");
+ llvm::sys::path::append(Result, ModuleName + "-" + HashStr + ".pcm");
}
return Result.str().str();
}
Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
// Look in the module map to determine if there is a module by this name.
Module *Module = ModMap.findModule(ModuleName);
- if (Module || !AllowSearch || !LangOpts.ModulesImplicitMaps)
+ if (Module || !AllowSearch || !HSOpts->ImplicitModuleMaps)
return Module;
// Look through the various header search paths to load any available module
return getHeaderMap()->getFileName();
}
-static const FileEntry *
-getFileAndSuggestModule(HeaderSearch &HS, StringRef FileName,
- const DirectoryEntry *Dir, bool IsSystemHeaderDir,
- ModuleMap::KnownHeader *SuggestedModule) {
+const FileEntry *HeaderSearch::getFileAndSuggestModule(
+ StringRef FileName, const DirectoryEntry *Dir, bool IsSystemHeaderDir,
+ Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule) {
// If we have a module map that might map this header, load it and
// check whether we'll have a suggestion for a module.
- HS.hasModuleMap(FileName, Dir, IsSystemHeaderDir);
- if (SuggestedModule) {
- const FileEntry *File = HS.getFileMgr().getFile(FileName,
- /*OpenFile=*/false);
- if (File) {
- // If there is a module that corresponds to this header, suggest it.
- *SuggestedModule = HS.findModuleForHeader(File);
-
- // FIXME: This appears to be a no-op. We loaded the module map for this
- // directory at the start of this function.
- if (!SuggestedModule->getModule() &&
- HS.hasModuleMap(FileName, Dir, IsSystemHeaderDir))
- *SuggestedModule = HS.findModuleForHeader(File);
- }
+ const FileEntry *File = getFileMgr().getFile(FileName, /*OpenFile=*/true);
+ if (!File)
+ return nullptr;
- return File;
- }
+ // If there is a module that corresponds to this header, suggest it.
+ if (!findUsableModuleForHeader(File, Dir ? Dir : File->getDir(),
+ RequestingModule, SuggestedModule,
+ IsSystemHeaderDir))
+ return nullptr;
- return HS.getFileMgr().getFile(FileName, /*openFile=*/true);
+ return File;
}
/// LookupFile - Lookup the specified file in this search path, returning it
HeaderSearch &HS,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
+ Module *RequestingModule,
ModuleMap::KnownHeader *SuggestedModule,
bool &InUserSpecifiedSystemFramework,
bool &HasBeenMapped,
RelativePath->append(Filename.begin(), Filename.end());
}
- return getFileAndSuggestModule(HS, TmpDir.str(), getDir(),
- isSystemHeaderDirectory(),
- SuggestedModule);
+ return HS.getFileAndSuggestModule(TmpDir, getDir(),
+ isSystemHeaderDirectory(),
+ RequestingModule, SuggestedModule);
}
if (isFramework())
return DoFrameworkLookup(Filename, HS, SearchPath, RelativePath,
- SuggestedModule, InUserSpecifiedSystemFramework);
+ RequestingModule, SuggestedModule,
+ InUserSpecifiedSystemFramework);
assert(isHeaderMap() && "Unknown directory lookup");
const HeaderMap *HM = getHeaderMap();
/// DoFrameworkLookup - Do a lookup of the specified file in the current
/// DirectoryLookup, which is a framework directory.
const FileEntry *DirectoryLookup::DoFrameworkLookup(
- StringRef Filename,
- HeaderSearch &HS,
- SmallVectorImpl<char> *SearchPath,
- SmallVectorImpl<char> *RelativePath,
+ StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath,
+ SmallVectorImpl<char> *RelativePath, Module *RequestingModule,
ModuleMap::KnownHeader *SuggestedModule,
- bool &InUserSpecifiedSystemFramework) const
-{
+ bool &InUserSpecifiedSystemFramework) const {
FileManager &FileMgr = HS.getFileMgr();
// Framework names must have a '/' in the filename.
HS.IncrementFrameworkLookupCount();
// If the framework dir doesn't exist, we fail.
- const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.str());
+ const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName);
if (!Dir) return nullptr;
// Otherwise, if it does, remember that this is the right direntry for this
if (getDirCharacteristic() == SrcMgr::C_User) {
SmallString<1024> SystemFrameworkMarker(FrameworkName);
SystemFrameworkMarker += ".system_framework";
- if (llvm::sys::fs::exists(SystemFrameworkMarker.str())) {
+ if (llvm::sys::fs::exists(SystemFrameworkMarker)) {
CacheEntry.IsUserSpecifiedSystemFramework = true;
}
}
}
FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
- const FileEntry *FE = FileMgr.getFile(FrameworkName.str(),
+ const FileEntry *FE = FileMgr.getFile(FrameworkName,
/*openFile=*/!SuggestedModule);
if (!FE) {
// Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
SearchPath->insert(SearchPath->begin()+OrigSize, Private,
Private+strlen(Private));
- FE = FileMgr.getFile(FrameworkName.str(), /*openFile=*/!SuggestedModule);
+ FE = FileMgr.getFile(FrameworkName, /*openFile=*/!SuggestedModule);
}
// If we found the header and are allowed to suggest a module, do so now.
break;
} while (true);
+ bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
if (FoundFramework) {
- // Find the top-level framework based on this framework.
- SmallVector<std::string, 4> SubmodulePath;
- const DirectoryEntry *TopFrameworkDir
- = ::getTopFrameworkDir(FileMgr, FrameworkPath, SubmodulePath);
-
- // Determine the name of the top-level framework.
- StringRef ModuleName = llvm::sys::path::stem(TopFrameworkDir->getName());
-
- // Load this framework module. If that succeeds, find the suggested module
- // for this header, if any.
- bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
- if (HS.loadFrameworkModule(ModuleName, TopFrameworkDir, IsSystem)) {
- *SuggestedModule = HS.findModuleForHeader(FE);
- }
+ if (!HS.findUsableModuleForFrameworkHeader(
+ FE, FrameworkPath, RequestingModule, SuggestedModule, IsSystem))
+ return nullptr;
} else {
- *SuggestedModule = HS.findModuleForHeader(FE);
+ if (!HS.findUsableModuleForHeader(FE, getDir(), RequestingModule,
+ SuggestedModule, IsSystem))
+ return nullptr;
}
}
return FE;
const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
- ModuleMap::KnownHeader *SuggestedModule, bool SkipCache) {
+ Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
+ bool SkipCache, bool BuildSystemModule) {
if (SuggestedModule)
*SuggestedModule = ModuleMap::KnownHeader();
RelativePath->append(Filename.begin(), Filename.end());
}
// Otherwise, just return the file.
- return FileMgr.getFile(Filename, /*openFile=*/true);
+ return getFileAndSuggestModule(Filename, nullptr,
+ /*IsSystemHeaderDir*/false,
+ RequestingModule, SuggestedModule);
}
// This is the header that MSVC's header search would have found.
// getFileAndSuggestModule, because it's a reference to an element of
// a container that could be reallocated across this call.
//
- // FIXME: If we have no includer, that means we're processing a #include
+ // If we have no includer, that means we're processing a #include
// from a module build. We should treat this as a system header if we're
// building a [system] module.
bool IncluderIsSystemHeader =
- Includer && getFileInfo(Includer).DirInfo != SrcMgr::C_User;
+ Includer ? getFileInfo(Includer).DirInfo != SrcMgr::C_User :
+ BuildSystemModule;
if (const FileEntry *FE = getFileAndSuggestModule(
- *this, TmpDir.str(), IncluderAndDir.second,
- IncluderIsSystemHeader, SuggestedModule)) {
+ TmpDir, IncluderAndDir.second, IncluderIsSystemHeader,
+ RequestingModule, SuggestedModule)) {
if (!Includer) {
assert(First && "only first includer can have no file");
return FE;
for (; i != SearchDirs.size(); ++i) {
bool InUserSpecifiedSystemFramework = false;
bool HasBeenMapped = false;
- const FileEntry *FE =
- SearchDirs[i].LookupFile(Filename, *this, SearchPath, RelativePath,
- SuggestedModule, InUserSpecifiedSystemFramework,
- HasBeenMapped, MappedName);
+ const FileEntry *FE = SearchDirs[i].LookupFile(
+ Filename, *this, SearchPath, RelativePath, RequestingModule,
+ SuggestedModule, InUserSpecifiedSystemFramework, HasBeenMapped,
+ MappedName);
if (HasBeenMapped) {
CacheLookup.MappedName =
copyString(Filename, LookupFileCache.getAllocator());
ScratchFilename += '/';
ScratchFilename += Filename;
- const FileEntry *FE = LookupFile(
- ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, CurDir,
- Includers.front(), SearchPath, RelativePath, SuggestedModule);
+ const FileEntry *FE =
+ LookupFile(ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir,
+ CurDir, Includers.front(), SearchPath, RelativePath,
+ RequestingModule, SuggestedModule);
if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) {
if (SuggestedModule)
const FileEntry *ContextFileEnt,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
+ Module *RequestingModule,
ModuleMap::KnownHeader *SuggestedModule) {
assert(ContextFileEnt && "No context file?");
++NumSubFrameworkLookups;
// If the framework dir doesn't exist, we fail.
- const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.str());
+ const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName);
if (!Dir) return nullptr;
// Otherwise, if it does, remember that this is the right direntry for this
}
HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
- if (!(FE = FileMgr.getFile(HeadersFilename.str(), /*openFile=*/true))) {
+ if (!(FE = FileMgr.getFile(HeadersFilename, /*openFile=*/true))) {
// Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
HeadersFilename = FrameworkName;
}
HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
- if (!(FE = FileMgr.getFile(HeadersFilename.str(), /*openFile=*/true)))
+ if (!(FE = FileMgr.getFile(HeadersFilename, /*openFile=*/true)))
return nullptr;
}
unsigned DirInfo = getFileInfo(ContextFileEnt).DirInfo;
getFileInfo(FE).DirInfo = DirInfo;
- // If we're supposed to suggest a module, look for one now.
- if (SuggestedModule) {
- // Find the top-level framework based on this framework.
- FrameworkName.pop_back(); // remove the trailing '/'
- SmallVector<std::string, 4> SubmodulePath;
- const DirectoryEntry *TopFrameworkDir
- = ::getTopFrameworkDir(FileMgr, FrameworkName, SubmodulePath);
-
- // Determine the name of the top-level framework.
- StringRef ModuleName = llvm::sys::path::stem(TopFrameworkDir->getName());
-
- // Load this framework module. If that succeeds, find the suggested module
- // for this header, if any.
- bool IsSystem = false;
- if (loadFrameworkModule(ModuleName, TopFrameworkDir, IsSystem)) {
- *SuggestedModule = findModuleForHeader(FE);
- }
- }
+ FrameworkName.pop_back(); // remove the trailing '/'
+ if (!findUsableModuleForFrameworkHeader(FE, FrameworkName, RequestingModule,
+ SuggestedModule, /*IsSystem*/ false))
+ return nullptr;
return FE;
}
/// header file info (\p HFI)
static void mergeHeaderFileInfo(HeaderFileInfo &HFI,
const HeaderFileInfo &OtherHFI) {
+ assert(OtherHFI.External && "expected to merge external HFI");
+
HFI.isImport |= OtherHFI.isImport;
HFI.isPragmaOnce |= OtherHFI.isPragmaOnce;
HFI.isModuleHeader |= OtherHFI.isModuleHeader;
HFI.NumIncludes += OtherHFI.NumIncludes;
-
+
if (!HFI.ControllingMacro && !HFI.ControllingMacroID) {
HFI.ControllingMacro = OtherHFI.ControllingMacro;
HFI.ControllingMacroID = OtherHFI.ControllingMacroID;
}
-
- if (OtherHFI.External) {
- HFI.DirInfo = OtherHFI.DirInfo;
- HFI.External = OtherHFI.External;
- HFI.IndexHeaderMapHeader = OtherHFI.IndexHeaderMapHeader;
- }
+
+ HFI.DirInfo = OtherHFI.DirInfo;
+ HFI.External = (!HFI.IsValid || HFI.External);
+ HFI.IsValid = true;
+ HFI.IndexHeaderMapHeader = OtherHFI.IndexHeaderMapHeader;
if (HFI.Framework.empty())
HFI.Framework = OtherHFI.Framework;
-
- HFI.Resolved = true;
}
/// getFileInfo - Return the HeaderFileInfo structure for the specified
/// FileEntry.
HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
if (FE->getUID() >= FileInfo.size())
- FileInfo.resize(FE->getUID()+1);
-
- HeaderFileInfo &HFI = FileInfo[FE->getUID()];
- if (ExternalSource && !HFI.Resolved)
- mergeHeaderFileInfo(HFI, ExternalSource->GetHeaderFileInfo(FE));
- HFI.IsValid = 1;
- return HFI;
+ FileInfo.resize(FE->getUID() + 1);
+
+ HeaderFileInfo *HFI = &FileInfo[FE->getUID()];
+ // FIXME: Use a generation count to check whether this is really up to date.
+ if (ExternalSource && !HFI->Resolved) {
+ HFI->Resolved = true;
+ auto ExternalHFI = ExternalSource->GetHeaderFileInfo(FE);
+
+ HFI = &FileInfo[FE->getUID()];
+ if (ExternalHFI.External)
+ mergeHeaderFileInfo(*HFI, ExternalHFI);
+ }
+
+ HFI->IsValid = true;
+ // We have local information about this header file, so it's no longer
+ // strictly external.
+ HFI->External = false;
+ return *HFI;
}
-bool HeaderSearch::tryGetFileInfo(const FileEntry *FE, HeaderFileInfo &Result) const {
- if (FE->getUID() >= FileInfo.size())
- return false;
- const HeaderFileInfo &HFI = FileInfo[FE->getUID()];
- if (HFI.IsValid) {
- Result = HFI;
- return true;
+const HeaderFileInfo *
+HeaderSearch::getExistingFileInfo(const FileEntry *FE,
+ bool WantExternal) const {
+ // If we have an external source, ensure we have the latest information.
+ // FIXME: Use a generation count to check whether this is really up to date.
+ HeaderFileInfo *HFI;
+ if (ExternalSource) {
+ if (FE->getUID() >= FileInfo.size()) {
+ if (!WantExternal)
+ return nullptr;
+ FileInfo.resize(FE->getUID() + 1);
+ }
+
+ HFI = &FileInfo[FE->getUID()];
+ if (!WantExternal && (!HFI->IsValid || HFI->External))
+ return nullptr;
+ if (!HFI->Resolved) {
+ HFI->Resolved = true;
+ auto ExternalHFI = ExternalSource->GetHeaderFileInfo(FE);
+
+ HFI = &FileInfo[FE->getUID()];
+ if (ExternalHFI.External)
+ mergeHeaderFileInfo(*HFI, ExternalHFI);
+ }
+ } else if (FE->getUID() >= FileInfo.size()) {
+ return nullptr;
+ } else {
+ HFI = &FileInfo[FE->getUID()];
}
- return false;
+
+ if (!HFI->IsValid || (HFI->External && !WantExternal))
+ return nullptr;
+
+ return HFI;
}
bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) {
// Check if we've ever seen this file as a header.
- if (File->getUID() >= FileInfo.size())
- return false;
-
- // Resolve header file info from the external source, if needed.
- HeaderFileInfo &HFI = FileInfo[File->getUID()];
- if (ExternalSource && !HFI.Resolved)
- mergeHeaderFileInfo(HFI, ExternalSource->GetHeaderFileInfo(File));
-
- return HFI.isPragmaOnce || HFI.isImport ||
- HFI.ControllingMacro || HFI.ControllingMacroID;
+ if (auto *HFI = getExistingFileInfo(File))
+ return HFI->isPragmaOnce || HFI->isImport || HFI->ControllingMacro ||
+ HFI->ControllingMacroID;
+ return false;
}
void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE,
ModuleMap::ModuleHeaderRole Role,
bool isCompilingModuleHeader) {
- if (FE->getUID() >= FileInfo.size())
- FileInfo.resize(FE->getUID()+1);
+ bool isModularHeader = !(Role & ModuleMap::TextualHeader);
+
+ // Don't mark the file info as non-external if there's nothing to change.
+ if (!isCompilingModuleHeader) {
+ if (!isModularHeader)
+ return;
+ auto *HFI = getExistingFileInfo(FE);
+ if (HFI && HFI->isModuleHeader)
+ return;
+ }
- HeaderFileInfo &HFI = FileInfo[FE->getUID()];
- HFI.isModuleHeader = true;
- HFI.isCompilingModuleHeader = isCompilingModuleHeader;
- HFI.setHeaderRole(Role);
+ auto &HFI = getFileInfo(FE);
+ HFI.isModuleHeader |= isModularHeader;
+ HFI.isCompilingModuleHeader |= isCompilingModuleHeader;
}
-bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){
+bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
+ const FileEntry *File,
+ bool isImport, Module *M) {
++NumIncluded; // Count # of attempted #includes.
// Get information about this file.
// Next, check to see if the file is wrapped with #ifndef guards. If so, and
// if the macro that guards it is defined, we know the #include has no effect.
if (const IdentifierInfo *ControllingMacro
- = FileInfo.getControllingMacro(ExternalLookup))
- if (ControllingMacro->hasMacroDefinition()) {
+ = FileInfo.getControllingMacro(ExternalLookup)) {
+ // If the header corresponds to a module, check whether the macro is already
+ // defined in that module rather than checking in the current set of visible
+ // modules.
+ if (M ? PP.isMacroDefinedInLocalModule(ControllingMacro, M)
+ : PP.isMacroDefined(ControllingMacro)) {
++NumMultiIncludeFileOptzn;
return false;
}
+ }
// Increment the number of times this file has been included.
++FileInfo.NumIncludes;
bool HeaderSearch::hasModuleMap(StringRef FileName,
const DirectoryEntry *Root,
bool IsSystem) {
- if (!enabledModules() || !LangOpts.ModulesImplicitMaps)
+ if (!HSOpts->ImplicitModuleMaps)
return false;
SmallVector<const DirectoryEntry *, 2> FixUpDirectories;
if (ExternalSource) {
// Make sure the external source has handled header info about this file,
// which includes whether the file is part of a module.
- (void)getFileInfo(File);
+ (void)getExistingFileInfo(File);
}
return ModMap.findModuleForHeader(File);
}
+bool HeaderSearch::findUsableModuleForHeader(
+ const FileEntry *File, const DirectoryEntry *Root, Module *RequestingModule,
+ ModuleMap::KnownHeader *SuggestedModule, bool IsSystemHeaderDir) {
+ if (File && SuggestedModule) {
+ // If there is a module that corresponds to this header, suggest it.
+ hasModuleMap(File->getName(), Root, IsSystemHeaderDir);
+ *SuggestedModule = findModuleForHeader(File);
+ }
+ return true;
+}
+
+bool HeaderSearch::findUsableModuleForFrameworkHeader(
+ const FileEntry *File, StringRef FrameworkName, Module *RequestingModule,
+ ModuleMap::KnownHeader *SuggestedModule, bool IsSystemFramework) {
+ // If we're supposed to suggest a module, look for one now.
+ if (SuggestedModule) {
+ // Find the top-level framework based on this framework.
+ SmallVector<std::string, 4> SubmodulePath;
+ const DirectoryEntry *TopFrameworkDir
+ = ::getTopFrameworkDir(FileMgr, FrameworkName, SubmodulePath);
+
+ // Determine the name of the top-level framework.
+ StringRef ModuleName = llvm::sys::path::stem(TopFrameworkDir->getName());
+
+ // Load this framework module. If that succeeds, find the suggested module
+ // for this header, if any.
+ loadFrameworkModule(ModuleName, TopFrameworkDir, IsSystemFramework);
+
+ // FIXME: This can find a module not part of ModuleName, which is
+ // important so that we're consistent about whether this header
+ // corresponds to a module. Possibly we should lock down framework modules
+ // so that this is not possible.
+ *SuggestedModule = findModuleForHeader(File);
+ }
+ return true;
+}
+
static const FileEntry *getPrivateModuleMap(const FileEntry *File,
FileManager &FileMgr) {
StringRef Filename = llvm::sys::path::filename(File->getName());
const FileEntry *
HeaderSearch::lookupModuleMapFile(const DirectoryEntry *Dir, bool IsFramework) {
- if (!LangOpts.ModulesImplicitMaps)
+ if (!HSOpts->ImplicitModuleMaps)
return nullptr;
// For frameworks, the preferred spelling is Modules/module.modulemap, but
// module.map at the framework root is also accepted.
// Try to load a module map file.
switch (loadModuleMapFile(Dir, IsSystem, /*IsFramework*/true)) {
case LMM_InvalidModuleMap:
+ // Try to infer a module map from the framework directory.
+ if (HSOpts->ImplicitModuleMaps)
+ ModMap.inferFrameworkModule(Dir, IsSystem, /*Parent=*/nullptr);
break;
case LMM_AlreadyLoaded:
return nullptr;
case LMM_NewlyLoaded:
- return ModMap.findModule(Name);
+ break;
}
-
- // Try to infer a module map from the framework directory.
- if (LangOpts.ModulesImplicitMaps)
- return ModMap.inferFrameworkModule(Name, Dir, IsSystem, /*Parent=*/nullptr);
-
- return nullptr;
+ return ModMap.findModule(Name);
}
void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
Modules.clear();
- if (LangOpts.ModulesImplicitMaps) {
+ if (HSOpts->ImplicitModuleMaps) {
// Load module maps for each of the header search directories.
for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
bool IsSystem = SearchDirs[Idx].isSystemHeaderDirectory();
DirNative);
// Search each of the ".framework" directories to load them as modules.
- for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
+ vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
+ for (vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
- if (llvm::sys::path::extension(Dir->path()) != ".framework")
+ if (llvm::sys::path::extension(Dir->getName()) != ".framework")
continue;
const DirectoryEntry *FrameworkDir =
- FileMgr.getDirectory(Dir->path());
+ FileMgr.getDirectory(Dir->getName());
if (!FrameworkDir)
continue;
// Load this framework module.
- loadFrameworkModule(llvm::sys::path::stem(Dir->path()), FrameworkDir,
- IsSystem);
+ loadFrameworkModule(llvm::sys::path::stem(Dir->getName()),
+ FrameworkDir, IsSystem);
}
continue;
}
}
void HeaderSearch::loadTopLevelSystemModules() {
- if (!LangOpts.ModulesImplicitMaps)
+ if (!HSOpts->ImplicitModuleMaps)
return;
// Load module maps for each of the header search directories.
}
void HeaderSearch::loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir) {
- assert(LangOpts.ModulesImplicitMaps &&
+ assert(HSOpts->ImplicitModuleMaps &&
"Should not be loading subdirectory module maps");
if (SearchDir.haveSearchedAllModuleMaps())
std::error_code EC;
SmallString<128> DirNative;
llvm::sys::path::native(SearchDir.getDir()->getName(), DirNative);
- for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
+ vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
+ for (vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
- loadModuleMapFile(Dir->path(), SearchDir.isSystemHeaderDirectory(),
- SearchDir.isFramework());
+ bool IsFramework =
+ llvm::sys::path::extension(Dir->getName()) == ".framework";
+ if (IsFramework == SearchDir.isFramework())
+ loadModuleMapFile(Dir->getName(), SearchDir.isSystemHeaderDirectory(),
+ SearchDir.isFramework());
}
SearchDir.setSearchedAllModuleMaps(true);
}
+
+std::string HeaderSearch::suggestPathToFileForDiagnostics(const FileEntry *File,
+ bool *IsSystem) {
+ // FIXME: We assume that the path name currently cached in the FileEntry is
+ // the most appropriate one for this analysis (and that it's spelled the same
+ // way as the corresponding header search path).
+ const char *Name = File->getName();
+
+ unsigned BestPrefixLength = 0;
+ unsigned BestSearchDir;
+
+ for (unsigned I = 0; I != SearchDirs.size(); ++I) {
+ // FIXME: Support this search within frameworks and header maps.
+ if (!SearchDirs[I].isNormalDir())
+ continue;
+
+ const char *Dir = SearchDirs[I].getDir()->getName();
+ for (auto NI = llvm::sys::path::begin(Name),
+ NE = llvm::sys::path::end(Name),
+ DI = llvm::sys::path::begin(Dir),
+ DE = llvm::sys::path::end(Dir);
+ /*termination condition in loop*/; ++NI, ++DI) {
+ // '.' components in Name are ignored.
+ while (NI != NE && *NI == ".")
+ ++NI;
+ if (NI == NE)
+ break;
+
+ // '.' components in Dir are ignored.
+ while (DI != DE && *DI == ".")
+ ++DI;
+ if (DI == DE) {
+ // Dir is a prefix of Name, up to '.' components and choice of path
+ // separators.
+ unsigned PrefixLength = NI - llvm::sys::path::begin(Name);
+ if (PrefixLength > BestPrefixLength) {
+ BestPrefixLength = PrefixLength;
+ BestSearchDir = I;
+ }
+ break;
+ }
+
+ if (*NI != *DI)
+ break;
+ }
+ }
+
+ if (IsSystem)
+ *IsSystem = BestPrefixLength ? BestSearchDir >= SystemDirIdx : false;
+ return Name + BestPrefixLength;
+}