]> granicus.if.org Git - clang/commitdiff
When inferring a module for a framework, first determine whether that
authorDouglas Gregor <dgregor@apple.com>
Fri, 13 Jan 2012 22:31:52 +0000 (22:31 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 13 Jan 2012 22:31:52 +0000 (22:31 +0000)
framework is actually a subframework within a top-level framework. If
so, only infer a module for the top-level framework and then dig out
the appropriate submodule.

This helps us cope with an amusing subframeworks anti-pattern, where
one uses -F <framework>/Frameworks to get direct include access to the
subframeworks of a framework (which otherwise would not be
permitted).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148148 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Lex/HeaderSearch.cpp
test/Modules/subframeworks.m

index 070daa0cd12627762eec5abee5ce8fc8d922ef3e..6d2d72fc22d68fed4ecbc7f039ec1ba981d0cb36 100644 (file)
@@ -860,7 +860,7 @@ Module *HeaderSearch::getModule(StringRef Name, bool AllowSearch) {
 }
   
 Module *HeaderSearch::getFrameworkModule(StringRef Name, 
-                                                    const DirectoryEntry *Dir) {
+                                         const DirectoryEntry *Dir) {
   if (Module *Module = ModMap.findModule(Name))
     return Module;
   
@@ -876,9 +876,50 @@ Module *HeaderSearch::getFrameworkModule(StringRef Name,
   case LMM_NewlyLoaded:
     return ModMap.findModule(Name);
   }
+
+  // The top-level framework directory, from which we'll infer a framework
+  // module.
+  const DirectoryEntry *TopFrameworkDir = Dir;
+  
+  // The path from the module we're actually looking for back to the top-level
+  // framework name.
+  llvm::SmallVector<StringRef, 2> SubmodulePath;
+  SubmodulePath.push_back(Name);
   
-  // Try to infer a module map.
-  return ModMap.inferFrameworkModule(Name, Dir, /*Parent=*/0);
+  // Walk the directory structure to find any enclosing frameworks.
+  StringRef DirName = Dir->getName();
+  do {
+    // Get the parent directory name.
+    DirName = llvm::sys::path::parent_path(DirName);
+    if (DirName.empty())
+      break;
+    
+    // Determine whether this directory exists.
+    Dir = FileMgr.getDirectory(DirName);
+    if (!Dir)
+      break;
+    
+    // If this is a framework directory, then we're a subframework of this
+    // framework.
+    if (llvm::sys::path::extension(DirName) == ".framework") {
+      SubmodulePath.push_back(llvm::sys::path::stem(DirName));
+      TopFrameworkDir = Dir;
+    }
+  } while (true);
+  
+  // Try to infer a module map from the top-level framework directory.
+  Module *Result = ModMap.inferFrameworkModule(SubmodulePath.back(), 
+                                               TopFrameworkDir, 
+                                               /*Parent=*/0);
+  
+  // Follow the submodule path to find the requested (sub)framework module
+  // within the top-level framework module.
+  SubmodulePath.pop_back();
+  while (!SubmodulePath.empty() && Result) {
+    Result = ModMap.lookupModuleQualified(SubmodulePath.back(), Result);
+    SubmodulePath.pop_back();
+  }
+  return Result;
 }
 
 
index 82c4a4bbf2757b424f4b73a5f0189ee456032805..e87bc6bac33a53b0fcf49c583998d6657464405b 100644 (file)
@@ -1,6 +1,6 @@
 // RUN: rm -rf %t
-// RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs %s -verify
-// RUN: %clang_cc1 -x objective-c++ -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs %s -verify
+// RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs -F %S/Inputs/DependsOnModule.framework/Frameworks %s -verify
+// RUN: %clang_cc1 -x objective-c++ -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs -F %S/Inputs/DependsOnModule.framework/Frameworks %s -verify
 
 @import DependsOnModule;