From 2821c7f8870629b56b9c41e1c50c7a091edd544d Mon Sep 17 00:00:00 2001 From: Douglas Gregor <dgregor@apple.com> Date: Thu, 17 Nov 2011 01:41:17 +0000 Subject: [PATCH] When we're loading a framework header, first try to turn the framework into a module. This module can either be loaded from a module map in the framework directory (which isn't quite working yet) or inferred from an umbrella header (which does work, and replaces the existing hack). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@144877 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Lex/HeaderSearch.h | 14 +++++++++ include/clang/Lex/ModuleMap.h | 5 ++++ lib/Lex/HeaderSearch.cpp | 48 +++++++++++++++++++++++++++---- lib/Lex/ModuleMap.cpp | 28 ++++++++++++++++++ test/Modules/auto-module-import.c | 2 +- 5 files changed, 90 insertions(+), 7 deletions(-) diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h index 07cdc551808..21654c16cc2 100644 --- a/include/clang/Lex/HeaderSearch.h +++ b/include/clang/Lex/HeaderSearch.h @@ -389,6 +389,20 @@ public: /// /// \returns The module, if found; otherwise, null. ModuleMap::Module *getModule(StringRef Name, bool AllowSearch = true); + + /// \brief Retrieve a module with the given name, which may be part of the + /// given framework. + /// + /// \param Name The name of the module to retrieve. + /// + /// \param Dir The framework directory (e.g., ModuleName.framework). + /// + /// \returns The module, if found; otherwise, null. + ModuleMap::Module *getFrameworkModule(StringRef Name, + const DirectoryEntry *Dir); + + /// \brief Retrieve the module map. + ModuleMap &getModuleMap() { return ModMap; } unsigned header_file_size() const { return FileInfo.size(); } diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h index 74cca6b8816..e9bf1b35c14 100644 --- a/include/clang/Lex/ModuleMap.h +++ b/include/clang/Lex/ModuleMap.h @@ -137,6 +137,11 @@ public: /// \returns The named module, if known; otherwise, returns null. Module *findModule(StringRef Name); + /// \brief Infer the contents of a framework module map from the given + /// framework directory. + Module *inferFrameworkModule(StringRef ModuleName, + const DirectoryEntry *FrameworkDir); + /// \brief Parse the given module map file, and record any modules we /// encounter. /// diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp index 161c4b6d14b..cc9c8c16f74 100644 --- a/lib/Lex/HeaderSearch.cpp +++ b/lib/Lex/HeaderSearch.cpp @@ -311,7 +311,8 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup( FrameworkName.push_back('/'); // FrameworkName = "/System/Library/Frameworks/Cocoa" - FrameworkName.append(Filename.begin(), Filename.begin()+SlashPos); + StringRef ModuleName(Filename.begin(), SlashPos); + FrameworkName += ModuleName; // FrameworkName = "/System/Library/Frameworks/Cocoa.framework/" FrameworkName += ".framework/"; @@ -337,6 +338,18 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup( RelativePath->append(Filename.begin()+SlashPos+1, Filename.end()); } + // If we're allowed to look for modules, try to load or create the module + // corresponding to this framework. + ModuleMap::Module *Module = 0; + if (SuggestedModule) { + if (const DirectoryEntry *FrameworkDir + = FileMgr.getDirectory(FrameworkName)) { + if ((Module = HS.getFrameworkModule(ModuleName, FrameworkDir)) && + Module->Name == BuildingModule) + Module = 0; + } + } + // Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h" unsigned OrigSize = FrameworkName.size(); @@ -348,16 +361,16 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup( SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1); } - /// Determine whether this is the module we're building or not. - bool AutomaticImport = SuggestedModule && - (BuildingModule != StringRef(Filename.begin(), SlashPos)) && + // Determine whether this is the module we're building or not. + // FIXME: Do we still need the ".." hack? + bool AutomaticImport = Module && !Filename.substr(SlashPos + 1).startswith(".."); FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end()); if (const FileEntry *FE = FileMgr.getFile(FrameworkName.str(), /*openFile=*/!AutomaticImport)) { if (AutomaticImport) - *SuggestedModule = StringRef(Filename.begin(), SlashPos); + *SuggestedModule = Module->Name; return FE; } @@ -372,7 +385,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup( const FileEntry *FE = FileMgr.getFile(FrameworkName.str(), /*openFile=*/!AutomaticImport); if (FE && AutomaticImport) - *SuggestedModule = StringRef(Filename.begin(), SlashPos); + *SuggestedModule = Module->Name; return FE; } @@ -839,6 +852,29 @@ ModuleMap::Module *HeaderSearch::getModule(StringRef Name, bool AllowSearch) { return 0; } + +ModuleMap::Module *HeaderSearch::getFrameworkModule(StringRef Name, + const DirectoryEntry *Dir) { + if (ModuleMap::Module *Module = ModMap.findModule(Name)) + return Module; + + // Try to load a module map file. + switch (loadModuleMapFile(Dir)) { + case LMM_InvalidModuleMap: + break; + + case LMM_AlreadyLoaded: + case LMM_NoDirectory: + return 0; + + case LMM_NewlyLoaded: + return ModMap.findModule(Name); + } + + // Try to infer a module map. + return ModMap.inferFrameworkModule(Name, Dir); +} + HeaderSearch::LoadModuleMapResult HeaderSearch::loadModuleMapFile(StringRef DirName) { diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index f6751b78f1e..0c51659cab8 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -127,6 +127,34 @@ ModuleMap::Module *ModuleMap::findModule(StringRef Name) { return 0; } +ModuleMap::Module * +ModuleMap::inferFrameworkModule(StringRef ModuleName, + const DirectoryEntry *FrameworkDir) { + // Check whether we've already found this module. + if (Module *Module = findModule(ModuleName)) + return Module; + + // Look for an umbrella header. + llvm::SmallString<128> UmbrellaName = StringRef(FrameworkDir->getName()); + llvm::sys::path::append(UmbrellaName, "Headers"); + llvm::sys::path::append(UmbrellaName, ModuleName + ".h"); + const FileEntry *UmbrellaHeader + = SourceMgr->getFileManager().getFile(UmbrellaName); + + // FIXME: If there's no umbrella header, we could probably scan the + // framework to load *everything*. But, it's not clear that this is a good + // idea. + if (!UmbrellaHeader) + return 0; + + Module *Result = new Module(ModuleName, SourceLocation()); + Result->UmbrellaHeader = UmbrellaHeader; + Headers[UmbrellaHeader] = Result; + UmbrellaDirs[FrameworkDir] = Result; + Modules[ModuleName] = Result; + return Result; +} + static void indent(llvm::raw_ostream &OS, unsigned Spaces) { OS << std::string(' ', Spaces); } diff --git a/test/Modules/auto-module-import.c b/test/Modules/auto-module-import.c index 01871742387..1dda6425932 100644 --- a/test/Modules/auto-module-import.c +++ b/test/Modules/auto-module-import.c @@ -1,6 +1,6 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fauto-module-import -F %S/Inputs -verify %s +// RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fauto-module-import -F %S/Inputs %s -verify #include <DependsOnModule/DependsOnModule.h> -- GitLab