]> granicus.if.org Git - clang/commitdiff
Implement the notion of umbrella directories, which implicity cover
authorDouglas Gregor <dgregor@apple.com>
Fri, 9 Dec 2011 02:04:43 +0000 (02:04 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 9 Dec 2011 02:04:43 +0000 (02:04 +0000)
all of the headers below that particular directory. Use umbrella
directories as a clean way to deal with (1) directories/frameworks
that don't have an umbrella header, but don't want to enumerate all of
their headers, and (2) PrivateHeaders, which we never want to
enumerate and want to keep separate from the main umbrella header.

This also eliminates a little more of the "magic" for private headers,
and frameworks in general.

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

include/clang/Basic/Module.h
lib/Lex/ModuleMap.cpp
test/Modules/Inputs/NoUmbrella.framework/Headers/A.h [new file with mode: 0644]
test/Modules/Inputs/NoUmbrella.framework/Headers/B.h [new file with mode: 0644]
test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/A_Private.h [new file with mode: 0644]
test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/B_Private.h [new file with mode: 0644]
test/Modules/Inputs/NoUmbrella.framework/module.map [new file with mode: 0644]
test/Modules/Inputs/NoUmbrella.framework/module_private.map [new file with mode: 0644]
test/Modules/auto-module-import.m

index 0f2a9a7b3d222b5752d2a6f312131ddd516b126a..aef2db0feda2a77f1c413185d3642924c3e7c16d 100644 (file)
@@ -194,6 +194,12 @@ public:
     return Umbrella.dyn_cast<const FileEntry *>();
   }
 
+  /// \brief Determine whether this module has an umbrella directory that is
+  /// not based on an umbrella header.
+  bool hasUmbrellaDir() const {
+    return Umbrella && Umbrella.is<const DirectoryEntry *>();
+  }
+  
   /// \brief Print the module map for this module to the given stream. 
   ///
   void print(llvm::raw_ostream &OS, unsigned Indent = 0) const;
index c9efbf0b53f8508ea0c1fa49c203c3b710bc2761..12e636c1beb836a6bc4aabdf95a81c51765f0361 100644 (file)
@@ -115,27 +115,9 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
         // Infer submodules for each of the directories we found between
         // the directory of the umbrella header and the directory where 
         // the actual header is located.
-        
-        // For a framework module, the umbrella directory is the framework 
-        // directory, so strip off the "Headers" or "PrivateHeaders".
         bool Explicit = UmbrellaModule->InferExplicitSubmodules;
-        unsigned LastSkippedDir = SkippedDirs.size();
-        if (LastSkippedDir && UmbrellaModule->IsFramework) {
-          if (llvm::sys::path::filename(SkippedDirs.back()->getName())
-                == "PrivateHeaders") {
-            // For private headers, add an explicit "Private" module.
-            // FIXME: This feels somewhat hackish. Do we want to introduce
-            // some kind of "umbrella directory" here?
-            Result = findOrCreateModule("Private", Result, 
-                                        /*IsFramework=*/false,
-                                        /*IsExplicit=*/true).first;
-            Explicit = true;
-          }
-          
-          --LastSkippedDir;
-        }
         
-        for (unsigned I = LastSkippedDir; I != 0; --I) {
+        for (unsigned I = SkippedDirs.size(); I != 0; --I) {
           // Find or create the module that corresponds to this directory name.
           StringRef Name = llvm::sys::path::stem(SkippedDirs[I-1]->getName());
           Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
@@ -294,41 +276,16 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
   }
   
   // Look for private headers.
-  Module *ModulePrivate = 0;
   llvm::SmallString<128> PrivateHeadersDirName(FrameworkDir->getName());
   llvm::sys::path::append(PrivateHeadersDirName, "PrivateHeaders");
-  llvm::SmallString<128> PrivateHeadersDirNameNative;
-  llvm::sys::path::native(PrivateHeadersDirName.str(),
-                          PrivateHeadersDirNameNative);
-  for (llvm::sys::fs::directory_iterator 
-         Dir(PrivateHeadersDirNameNative.str(), EC), DirEnd;
-       Dir != DirEnd && !EC; Dir.increment(EC)) {
-    // Check whether this entry has an extension typically associated with 
-    // headers.
-    if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->path()))
-           .Cases(".h", ".H", ".hh", ".hpp", true)
-           .Default(false))
-      continue;
-
-    if (const FileEntry *PrivateHeader = FileMgr.getFile(Dir->path())) {
-      // Create the "private" submodule, if we haven't done so already.
-      if (!ModulePrivate) {
-        ModulePrivate = findOrCreateModule("Private", Result, 
-                                           /*IsFramework=*/false, 
-                                           /*IsExplicit=*/true).first;
-      }
-      
-      Module *Sub = findOrCreateModule(llvm::sys::path::stem(Dir->path()),
-                                       ModulePrivate, /*IsFramework=*/false,
-                                       /*IsExplicit=*/true).first;
-      // header "the private header"
-      Sub->Headers.push_back(PrivateHeader);
-      
-      // export *
-      Sub->Exports.push_back(Module::ExportDecl(0, true));
-      
-      Headers[PrivateHeader] = Sub;
-    }
+  if (const DirectoryEntry *Dir = FileMgr.getDirectory(PrivateHeadersDirName)) {
+    Module *Private = findOrCreateModule("Private", Result, 
+                                         /*IsFramework=*/false, 
+                                         /*IsExplicit=*/true).first;
+    setUmbrellaDir(Private, Dir);
+    Private->InferSubmodules = true;
+    Private->InferExplicitSubmodules = true;
+    Private->InferExportWildcard = true;
   }
   
   return Result;
@@ -337,13 +294,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
 void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){
   Headers[UmbrellaHeader] = Mod;
   Mod->Umbrella = UmbrellaHeader;
-  
-  const DirectoryEntry *UmbrellaDir = UmbrellaHeader->getDir();
-  if (Mod->IsFramework)
-    UmbrellaDir = SourceMgr->getFileManager().getDirectory(
-                    llvm::sys::path::parent_path(UmbrellaDir->getName()));
-    
-  UmbrellaDirs[UmbrellaDir] = Mod;
+  UmbrellaDirs[UmbrellaHeader->getDir()] = Mod;
 }
 
 void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) {
@@ -503,6 +454,8 @@ namespace clang {
     void parseExportDecl();
     void parseInferredSubmoduleDecl(bool Explicit);
     
+    const DirectoryEntry *getOverriddenHeaderSearchDir();
+    
   public:
     explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr, 
                              DiagnosticsEngine &Diags,
@@ -888,9 +841,13 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
   if (llvm::sys::path::is_absolute(FileName)) {
     PathName = FileName;
     File = SourceMgr.getFileManager().getFile(PathName);
+  } else if (const DirectoryEntry *Dir = getOverriddenHeaderSearchDir()) {
+    PathName = Dir->getName();
+    llvm::sys::path::append(PathName, FileName);
+    File = SourceMgr.getFileManager().getFile(PathName);
   } else {
     // Search for the header file within the search directory.
-    PathName += Directory->getName();
+    PathName = Directory->getName();
     unsigned PathLength = PathName.size();
     
     if (ActiveModule->isPartOfFramework()) {
@@ -924,13 +881,6 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
       HadError = true;
     } else if (Umbrella) {
       const DirectoryEntry *UmbrellaDir = File->getDir();
-      if (ActiveModule->IsFramework) {
-        // For framework modules, use the framework directory as the umbrella
-        // directory.
-        UmbrellaDir = SourceMgr.getFileManager().getDirectory(
-                        llvm::sys::path::parent_path(UmbrellaDir->getName()));
-      } 
-      
       if ((OwningModule = Map.UmbrellaDirs[UmbrellaDir])) {
         Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)
           << OwningModule->getFullModuleName();
@@ -1141,6 +1091,22 @@ void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) {
   }
 }
 
+/// \brief If there is a specific header search directory due the presence
+/// of an umbrella directory, retrieve that directory. Otherwise, returns null.
+const DirectoryEntry *ModuleMapParser::getOverriddenHeaderSearchDir() {
+  for (Module *Mod = ActiveModule; Mod; Mod = Mod->Parent) {
+    // If we have an umbrella directory, use that.
+    if (Mod->hasUmbrellaDir())
+      return Mod->getUmbrellaDir();
+    
+    // If we have a framework directory, stop looking.
+    if (Mod->IsFramework)
+      return 0;
+  }
+  
+  return 0;
+}
+
 /// \brief Parse a module map file.
 ///
 ///   module-map-file:
diff --git a/test/Modules/Inputs/NoUmbrella.framework/Headers/A.h b/test/Modules/Inputs/NoUmbrella.framework/Headers/A.h
new file mode 100644 (file)
index 0000000..0de118c
--- /dev/null
@@ -0,0 +1 @@
+int no_umbrella_A;
diff --git a/test/Modules/Inputs/NoUmbrella.framework/Headers/B.h b/test/Modules/Inputs/NoUmbrella.framework/Headers/B.h
new file mode 100644 (file)
index 0000000..dc6770f
--- /dev/null
@@ -0,0 +1 @@
+int no_umbrella_B;
diff --git a/test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/A_Private.h b/test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/A_Private.h
new file mode 100644 (file)
index 0000000..bd606d2
--- /dev/null
@@ -0,0 +1 @@
+int no_umbrella_A_private;
diff --git a/test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/B_Private.h b/test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/B_Private.h
new file mode 100644 (file)
index 0000000..442be2d
--- /dev/null
@@ -0,0 +1 @@
+int no_umbrella_B_private;
diff --git a/test/Modules/Inputs/NoUmbrella.framework/module.map b/test/Modules/Inputs/NoUmbrella.framework/module.map
new file mode 100644 (file)
index 0000000..9441501
--- /dev/null
@@ -0,0 +1,4 @@
+framework module NoUmbrella {
+  umbrella "Headers"
+  module * { }
+}
\ No newline at end of file
diff --git a/test/Modules/Inputs/NoUmbrella.framework/module_private.map b/test/Modules/Inputs/NoUmbrella.framework/module_private.map
new file mode 100644 (file)
index 0000000..0507ba0
--- /dev/null
@@ -0,0 +1,4 @@
+explicit module NoUmbrella.Private {
+  umbrella "PrivateHeaders"
+  explicit module * { }
+}
index 3703127f34acc7ebb9dbc9c8c547b21c1f3af03c..d59099f5de11d607a0f405a165f17b73009f9705 100644 (file)
@@ -1,3 +1,4 @@
+// other file: expected-note{{'no_umbrella_A_private' declared here}}
 
 // RUN: rm -rf %t
 // RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fauto-module-import -F %S/Inputs %s -verify
@@ -23,6 +24,10 @@ void testSubframeworkOther() {
   double *sfo1 = sub_framework_other; // expected-error{{use of undeclared identifier 'sub_framework_other'}}
 }
 
+// Test umbrella-less submodule includes
+#include <NoUmbrella/A.h> // expected-warning{{treating #include as an import of module 'NoUmbrella.A'}}
+int getNoUmbrellaA() { return no_umbrella_A; } 
+
 // Test header cross-subframework include pattern.
 #include <DependsOnModule/../Frameworks/SubFramework.framework/Headers/Other.h> // expected-warning{{treating #include as an import of module 'DependsOnModule.SubFramework.Other'}}
 
@@ -48,3 +53,8 @@ int getDependsOnModulePrivate() { return depends_on_module_private; }
 #include <Module/ModulePrivate.h> // expected-warning{{treating #include as an import of module 'Module.Private.ModulePrivate'}}
 
 int getModulePrivate() { return module_private; }
+
+#include <NoUmbrella/A_Private.h> // expected-warning{{treating #include as an import of module 'NoUmbrella.Private.A_Private'}}
+int getNoUmbrellaAPrivate() { return no_umbrella_A_private; }
+
+int getNoUmbrellaBPrivateFail() { return no_umbrella_B_private; } // expected-error{{use of undeclared identifier 'no_umbrella_B_private'; did you mean 'no_umbrella_A_private'?}}