]> granicus.if.org Git - clang/commitdiff
Implement modules support for subframeworks (aka embedded
authorDouglas Gregor <dgregor@apple.com>
Tue, 6 Dec 2011 17:16:41 +0000 (17:16 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 6 Dec 2011 17:16:41 +0000 (17:16 +0000)
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

include/clang/Basic/DiagnosticLexKinds.td
lib/Lex/ModuleMap.cpp
test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/Other.h [new file with mode: 0644]
test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/SubFramework.h [new file with mode: 0644]
test/Modules/Inputs/DependsOnModule.framework/module.map
test/Modules/subframeworks.m [new file with mode: 0644]

index 286a7ef40ed46bc2a0db7ad56b9cc890242ce870..e0bf38c102a79b0a4b8d6dd804a4852f03eeaf7d 100644 (file)
@@ -395,8 +395,6 @@ def err_mmap_header_not_found : Error<
   "%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<
index 198544dd5176e2616b76cfdf4ed75f9acb1c3037..5f3379bf965224a93b8154d6b5d9186074f52db3 100644 (file)
@@ -251,6 +251,8 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
   Result->InferSubmodules = true;
   Result->InferExportWildcard = true;
   
+  // FIXME: Look for subframeworks.
+  
   Modules[ModuleName] = Result;
   return Result;
 }
@@ -559,19 +561,21 @@ void ModuleMapParser::parseModuleDecl() {
   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;
 
-  if (Tok.is(MMToken::FrameworkKeyword)) {
-    consumeToken();
-    Framework = true;
-  } 
   // Parse 'explicit' keyword, if present.
-  else if (Tok.is(MMToken::ExplicitKeyword)) {
+  if (Tok.is(MMToken::ExplicitKeyword)) {
     consumeToken();
     Explicit = true;
   }
+
+  // Parse 'framework' keyword, if present.
+  if (Tok.is(MMToken::FrameworkKeyword)) {
+    consumeToken();
+    Framework = true;
+  } 
   
   // Parse 'module' keyword.
   if (!Tok.is(MMToken::ModuleKeyword)) {
@@ -640,6 +644,7 @@ void ModuleMapParser::parseModuleDecl() {
       break;
         
     case MMToken::ExplicitKeyword:
+    case MMToken::FrameworkKeyword:
     case MMToken::ModuleKeyword:
       parseModuleDecl();
       break;
@@ -674,7 +679,27 @@ void ModuleMapParser::parseModuleDecl() {
   // 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 @@ void ModuleMapParser::parseUmbrellaDecl() {
     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 @@ void ModuleMapParser::parseUmbrellaDecl() {
     // 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 @@ void ModuleMapParser::parseUmbrellaDecl() {
         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 @@ void ModuleMapParser::parseHeaderDecl() {
     // 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 (file)
index 0000000..69f9e8e
--- /dev/null
@@ -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 (file)
index 0000000..e6e835e
--- /dev/null
@@ -0,0 +1,2 @@
+#include "SubFramework/Other.h"
+float *sub_framework;
index d4c2a67061796a0b43b731a59559372de8529b94..d77127528544ca973ec44fde46f67b032f386ce8 100644 (file)
@@ -4,4 +4,7 @@ framework module DependsOnModule {
   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 (file)
index 0000000..44b6746
--- /dev/null
@@ -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;
+}
+