Implement modules support for subframeworks (aka embedded
frameworks). A submodule can now be labeled as a "framework", and
header search will look into the appropriate Headers/PrivateHeaders
subdirectories for named headers.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145941 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index 286a7ef..e0bf38c 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -395,8 +395,6 @@
   "%select{|umbrella }0header '%1' not found">;
 def err_mmap_umbrella_header_conflict : Error<
   "module '%0' already has an umbrella header ('%1')">;
-def err_mmap_umbrella_header_submodule : Error<
-  "submodule '%0' can not have an umbrella header">;
 def err_mmap_umbrella_clash : Error<
   "umbrella header for module '%0' already covers this directory">;
 def err_mmap_export_module_id : Error<
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index 198544d..5f3379b 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -251,6 +251,8 @@
   Result->InferSubmodules = true;
   Result->InferExportWildcard = true;
   
+  // FIXME: Look for subframeworks.
+  
   Modules[ModuleName] = Result;
   return Result;
 }
@@ -559,19 +561,21 @@
   assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) ||
          Tok.is(MMToken::FrameworkKeyword));
 
-  // Parse 'framework' or 'explicit' keyword, if present.
-  bool Framework = false;
+  // Parse 'explicit' or 'framework' keyword, if present.
   bool Explicit = false;
+  bool Framework = false;
 
+  // Parse 'explicit' keyword, if present.
+  if (Tok.is(MMToken::ExplicitKeyword)) {
+    consumeToken();
+    Explicit = true;
+  }
+
+  // Parse 'framework' keyword, if present.
   if (Tok.is(MMToken::FrameworkKeyword)) {
     consumeToken();
     Framework = true;
   } 
-  // Parse 'explicit' keyword, if present.
-  else if (Tok.is(MMToken::ExplicitKeyword)) {
-    consumeToken();
-    Explicit = true;
-  }
   
   // Parse 'module' keyword.
   if (!Tok.is(MMToken::ModuleKeyword)) {
@@ -640,6 +644,7 @@
       break;
         
     case MMToken::ExplicitKeyword:
+    case MMToken::FrameworkKeyword:
     case MMToken::ModuleKeyword:
       parseModuleDecl();
       break;
@@ -674,7 +679,27 @@
   // We're done parsing this module. Pop back to our parent scope.
   ActiveModule = ActiveModule->Parent;
 }
- 
+
+/// \brief Append to \p Paths the set of paths needed to get to the 
+/// subframework in which the given module lives.
+void appendSubframeworkPaths(Module *Mod, llvm::SmallVectorImpl<char> &Path) {
+  // Collect the framework names from the given module to the top-level module.
+  llvm::SmallVector<StringRef, 2> Paths;
+  for (; Mod; Mod = Mod->Parent) {
+    if (Mod->IsFramework)
+      Paths.push_back(Mod->Name);
+  }
+  
+  if (Paths.empty())
+    return;
+  
+  // Add Frameworks/Name.framework for each subframework.
+  for (unsigned I = Paths.size() - 1; I != 0; --I) {
+    llvm::sys::path::append(Path, "Frameworks");
+    llvm::sys::path::append(Path, Paths[I-1] + ".framework");
+  }
+}
+
 /// \brief Parse an umbrella header declaration.
 ///
 ///   umbrella-declaration:
@@ -702,14 +727,6 @@
     return;
   }
   
-  // Only top-level modules can have umbrella headers.
-  if (ActiveModule->Parent) {
-    Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_header_submodule)
-      << ActiveModule->getFullModuleName();
-    HadError = true;
-    return;
-  }
-  
   // Look for this file.
   llvm::SmallString<128> PathName;
   const FileEntry *File = 0;
@@ -721,7 +738,10 @@
     // Search for the header file within the search directory.
     PathName += Directory->getName();
     unsigned PathLength = PathName.size();
+    
     if (ActiveModule->isPartOfFramework()) {
+      appendSubframeworkPaths(ActiveModule, PathName);
+      
       // Check whether this file is in the public headers.
       llvm::sys::path::append(PathName, "Headers");
       llvm::sys::path::append(PathName, FileName);
@@ -734,8 +754,6 @@
         llvm::sys::path::append(PathName, FileName);
         File = SourceMgr.getFileManager().getFile(PathName);
       }
-      
-      // FIXME: Deal with subframeworks.
     } else {
       // Lookup for normal headers.
       llvm::sys::path::append(PathName, FileName);
@@ -797,8 +815,10 @@
     // FIXME: Change this search to also look for private headers!
     PathName += Directory->getName();
     
-    if (ActiveModule->isPartOfFramework())
+    if (ActiveModule->isPartOfFramework()) {
+      appendSubframeworkPaths(ActiveModule, PathName);
       llvm::sys::path::append(PathName, "Headers");
+    }
   }
   
   llvm::sys::path::append(PathName, FileName);
diff --git a/test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/Other.h b/test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/Other.h
new file mode 100644
index 0000000..69f9e8e
--- /dev/null
+++ b/test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/Other.h
@@ -0,0 +1 @@
+double *sub_framework_other;
diff --git a/test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/SubFramework.h b/test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/SubFramework.h
new file mode 100644
index 0000000..e6e835e
--- /dev/null
+++ b/test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/SubFramework.h
@@ -0,0 +1,2 @@
+#include "SubFramework/Other.h"
+float *sub_framework;
diff --git a/test/Modules/Inputs/DependsOnModule.framework/module.map b/test/Modules/Inputs/DependsOnModule.framework/module.map
index d4c2a67..d771275 100644
--- a/test/Modules/Inputs/DependsOnModule.framework/module.map
+++ b/test/Modules/Inputs/DependsOnModule.framework/module.map
@@ -4,4 +4,7 @@
   module * {
     export *
   }
+  explicit framework module SubFramework {
+    umbrella "SubFramework.h"
+  }
 }
diff --git a/test/Modules/subframeworks.m b/test/Modules/subframeworks.m
new file mode 100644
index 0000000..44b6746
--- /dev/null
+++ b/test/Modules/subframeworks.m
@@ -0,0 +1,16 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fauto-module-import -F %S/Inputs %s -verify
+
+__import_module__ DependsOnModule;
+
+void testSubFramework() {
+  float *sf1 = sub_framework; // expected-error{{use of undeclared identifier 'sub_framework'}}
+}
+
+__import_module__ DependsOnModule.SubFramework;
+
+void testSubFrameworkAgain() {
+  float *sf2 = sub_framework;
+  double *sfo1 = sub_framework_other;
+}
+