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