]> granicus.if.org Git - clang/commitdiff
Introduce the "-index-header-map" option, to give special semantics
authorDouglas Gregor <dgregor@apple.com>
Thu, 28 Jul 2011 04:45:53 +0000 (04:45 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 28 Jul 2011 04:45:53 +0000 (04:45 +0000)
for quoted header lookup when dealing with not-yet-installed
frameworks. Fixes <rdar://problem/9824020>.

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

include/clang/Driver/CC1Options.td
include/clang/Driver/Options.td
include/clang/Frontend/HeaderSearchOptions.h
include/clang/Lex/DirectoryLookup.h
include/clang/Lex/HeaderSearch.h
lib/Driver/Tools.cpp
lib/Frontend/CompilerInvocation.cpp
lib/Frontend/InitHeaderSearch.cpp
lib/Lex/HeaderSearch.cpp
test/Driver/index-header-map.c [new file with mode: 0644]

index 7eddc013933683fafc9344eb76a020d77b9b8d5d..1017daeda1ea6f066f071978dc3b3bb619b61ed2 100644 (file)
@@ -609,6 +609,8 @@ def I : JoinedOrSeparate<"-I">, MetaVarName<"<directory>">,
   HelpText<"Add directory to include search path">;
 def idirafter : JoinedOrSeparate<"-idirafter">, MetaVarName<"<directory>">,
   HelpText<"Add directory to AFTER include search path">;
+def index_header_map : Flag<"-index-header-map">, 
+  HelpText<"Make the next included directory (-I or -F) an indexer header map">;
 def iquote : JoinedOrSeparate<"-iquote">, MetaVarName<"<directory>">,
   HelpText<"Add directory to QUOTE include search path">;
 def cxx_isystem : JoinedOrSeparate<"-cxx-isystem">, MetaVarName<"<directory>">,
index ff75aa90f33293891edc334c1e4c9e0369eeace3..3ea43c7f6df5426a14cbfa4f6a7ebc4f35c0e2a3 100644 (file)
@@ -500,6 +500,7 @@ def gused : Joined<"-gused">, Group<g_Group>;
 def g_Flag : Flag<"-g">, Group<g_Group>;
 def g_Joined : Joined<"-g">, Group<g_Group>;
 def headerpad__max__install__names : Joined<"-headerpad_max_install_names">;
+def index_header_map : Flag<"-index-header-map">;
 def idirafter : JoinedOrSeparate<"-idirafter">, Group<clang_i_Group>;
 def iframework : JoinedOrSeparate<"-iframework">, Group<clang_i_Group>;
 def imacros : JoinedOrSeparate<"-imacros">, Group<clang_i_Group>;
index 949dfe11957e10ab44999022b4bc5ede611661ad..e1b1273ff4d1cc973249baa51ed340d47f712ad3 100644 (file)
@@ -23,6 +23,8 @@ namespace frontend {
   enum IncludeDirGroup {
     Quoted = 0,     ///< '#include ""' paths, added by'gcc -iquote'.
     Angled,         ///< Paths for '#include <>' added by '-I'.
+    IndexHeaderMap, ///< Like Angled, but marks header maps used when
+                       ///  building frameworks.
     System,         ///< Like Angled, but marks system directories.
     CXXSystem,      ///< Like System, but only used for C++.
     After           ///< Like System, but searched after the system directories.
index ca116df9de22f2248875a013e56e9e0860a80edf..ae5eabc690b55a7d9e9f85581428e41e12f4ef66 100644 (file)
@@ -56,21 +56,27 @@ private:
   /// LookupType - This indicates whether this DirectoryLookup object is a
   /// normal directory, a framework, or a headermap.
   unsigned LookupType : 2;
+  
+  /// \brief Whether this is a header map used when building a framework.
+  unsigned IsIndexHeaderMap : 1;
+  
 public:
   /// DirectoryLookup ctor - Note that this ctor *does not take ownership* of
   /// 'dir'.
   DirectoryLookup(const DirectoryEntry *dir, SrcMgr::CharacteristicKind DT,
                   bool isUser, bool isFramework)
-    : DirCharacteristic(DT), UserSupplied(isUser),
-     LookupType(isFramework ? LT_Framework : LT_NormalDir) {
+    : DirCharacteristic(DT), UserSupplied(isUser), 
+      LookupType(isFramework ? LT_Framework : LT_NormalDir),
+      IsIndexHeaderMap(false) {
     u.Dir = dir;
   }
 
   /// DirectoryLookup ctor - Note that this ctor *does not take ownership* of
   /// 'map'.
   DirectoryLookup(const HeaderMap *map, SrcMgr::CharacteristicKind DT,
-                  bool isUser)
-    : DirCharacteristic(DT), UserSupplied(isUser), LookupType(LT_HeaderMap) {
+                  bool isUser, bool isIndexHeaderMap)
+    : DirCharacteristic(DT), UserSupplied(isUser), LookupType(LT_HeaderMap),
+      IsIndexHeaderMap(isIndexHeaderMap) {
     u.Map = map;
   }
 
@@ -116,7 +122,11 @@ public:
   ///
   bool isUserSupplied() const { return UserSupplied; }
 
-
+  /// \brief Whether this header map is building a framework or not.
+  bool isIndexHeaderMap() const { 
+    return isHeaderMap() && IsIndexHeaderMap; 
+  }
+  
   /// LookupFile - Lookup the specified file in this search path, returning it
   /// if it exists or returning null if not.
   ///
index b61471d6088d2ab7f52af659a8e745c47305ae30..676a245305d3125079662a8a880cd5c649322fb1 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "clang/Lex/DirectoryLookup.h"
 #include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/Support/Allocator.h"
 #include <vector>
 
@@ -48,6 +49,15 @@ struct HeaderFileInfo {
   /// "resolved", meaning that it was loaded from the external source.
   unsigned Resolved : 1;
   
+  /// \brief Whether this is a header inside a framework that is currently
+  /// being built. 
+  ///
+  /// When a framework is being built, the headers have not yet been placed
+  /// into the appropriate framework subdirectories, and therefore are
+  /// provided via a header map. This bit indicates when this is one of
+  /// those framework headers.
+  unsigned IndexHeaderMapHeader : 1;
+  
   /// NumIncludes - This is the number of times the file has been included
   /// already.
   unsigned short NumIncludes;
@@ -69,10 +79,14 @@ struct HeaderFileInfo {
   /// external storage.
   const IdentifierInfo *ControllingMacro;
 
+  /// \brief If this header came from a framework include, this is the name
+  /// of the framework.
+  StringRef Framework;
+  
   HeaderFileInfo()
     : isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User), 
-      External(false), Resolved(false), NumIncludes(0), ControllingMacroID(0), 
-      ControllingMacro(0)  {}
+      External(false), Resolved(false), IndexHeaderMapHeader(false),
+      NumIncludes(0), ControllingMacroID(0), ControllingMacro(0)  {}
 
   /// \brief Retrieve the controlling macro for this header file, if
   /// any.
@@ -139,6 +153,10 @@ class HeaderSearch {
   /// headermaps.  This vector owns the headermap.
   std::vector<std::pair<const FileEntry*, const HeaderMap*> > HeaderMaps;
 
+  /// \brief Uniqued set of framework names, which is used to track which 
+  /// headers were included as framework headers.
+  llvm::StringSet<llvm::BumpPtrAllocator> FrameworkNames;
+  
   /// \brief Entity used to resolve the identifier IDs of controlling
   /// macros into IdentifierInfo pointers, as needed.
   ExternalIdentifierLookup *ExternalLookup;
@@ -325,6 +343,9 @@ public:
   }
   search_dir_iterator system_dir_end() const { return SearchDirs.end(); }
 
+  /// \brief Retrieve a uniqued framework name.
+  StringRef getUniqueFrameworkName(StringRef Framework);
+  
   void PrintStats();
   
   size_t getTotalMemory() const;
index 31413c7cf975b7bd7700fa8b77e6118bcbebd567..5fd2b9b48646d9f883b84a87cace2c2946ceb124 100644 (file)
@@ -341,7 +341,8 @@ void Clang::AddPreprocessingOptions(const Driver &D,
   }
 
   Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U);
-  Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F);
+  Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F,
+                  options::OPT_index_header_map);
 
   // Add C++ include arguments, if needed.
   types::ID InputType = Inputs[0].getType();
index 8967d5280bbd9804534656986efb28a090f37130..47e9590f47d2e63b9a1527a8ebb3be16d8d87616 100644 (file)
@@ -520,17 +520,31 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
     if (E.IsFramework && (E.Group != frontend::Angled || !E.IsUserSupplied))
       llvm::report_fatal_error("Invalid option set!");
     if (E.IsUserSupplied) {
-      if (E.Group == frontend::After) {
+      switch (E.Group) {
+      case frontend::After:
         Res.push_back("-idirafter");
-      } else if (E.Group == frontend::Quoted) {
+        break;
+        
+      case frontend::Quoted:
         Res.push_back("-iquote");
-      } else if (E.Group == frontend::System) {
+        break;
+        
+      case frontend::System:
         Res.push_back("-isystem");
-      } else if (E.Group == frontend::CXXSystem) {
+        break;
+        
+      case frontend::IndexHeaderMap:
+        Res.push_back("-index-header-map");
+        Res.push_back(E.IsFramework? "-F" : "-I");
+        break;
+        
+      case frontend::CXXSystem:
         Res.push_back("-cxx-isystem");
-      } else {
-        assert(E.Group == frontend::Angled && "Invalid group!");
+        break;
+        
+      case frontend::Angled:
         Res.push_back(E.IsFramework ? "-F" : "-I");
+        break;
       }
     } else {
       if (E.Group != frontend::Angled && E.Group != frontend::System)
@@ -1364,11 +1378,24 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
     Opts.UseLibcxx = (strcmp(A->getValue(Args), "libc++") == 0);
   Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir);
 
-  // Add -I... and -F... options in order.
-  for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F),
-         ie = Args.filtered_end(); it != ie; ++it)
-    Opts.AddPath((*it)->getValue(Args), frontend::Angled, true,
+  // Add -I..., -F..., and -index-header-map options in order.
+  bool IsIndexHeaderMap = false;
+  for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F, 
+                                             OPT_index_header_map),
+       ie = Args.filtered_end(); it != ie; ++it) {
+    if ((*it)->getOption().matches(OPT_index_header_map)) {
+      // -index-header-map applies to the next -I or -F.
+      IsIndexHeaderMap = true;
+      continue;
+    }
+        
+    frontend::IncludeDirGroup Group 
+      = IsIndexHeaderMap? frontend::IndexHeaderMap : frontend::Angled;
+    
+    Opts.AddPath((*it)->getValue(Args), Group, true,
                  /*IsFramework=*/ (*it)->getOption().matches(OPT_F), false);
+    IsIndexHeaderMap = false;
+  }
 
   // Add -iprefix/-iwith-prefix/-iwithprefixbefore options.
   StringRef Prefix = ""; // FIXME: This isn't the correct default prefix.
index ed763e27c7752273ff34024dbab7316147fe693c..f596b992f5468cc92440e64754dc298c25d03c09 100644 (file)
@@ -134,7 +134,7 @@ void InitHeaderSearch::AddPath(const Twine &Path,
 
   // Compute the DirectoryLookup type.
   SrcMgr::CharacteristicKind Type;
-  if (Group == Quoted || Group == Angled)
+  if (Group == Quoted || Group == Angled || Group == IndexHeaderMap)
     Type = SrcMgr::C_User;
   else if (isCXXAware)
     Type = SrcMgr::C_System;
@@ -156,7 +156,7 @@ void InitHeaderSearch::AddPath(const Twine &Path,
       if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) {
         // It is a headermap, add it to the search path.
         IncludePath.push_back(std::make_pair(Group, DirectoryLookup(HM, Type,
-                              isUserSupplied)));
+                              isUserSupplied, Group == IndexHeaderMap)));
         return;
       }
     }
@@ -1054,7 +1054,7 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) {
 
   for (path_iterator it = IncludePath.begin(), ie = IncludePath.end();
        it != ie; ++it) {
-    if (it->first == Angled)
+    if (it->first == Angled || it->first == IndexHeaderMap)
       SearchList.push_back(it->second);
   }
 
index 11cb1ecd8cd83e052c5c6220d49295df3b1bad94..2592ada676a1a0dfaf2b8bfd70d9cea68964157c 100644 (file)
@@ -280,7 +280,23 @@ const FileEntry *HeaderSearch::LookupFile(
     return FileMgr.getFile(Filename, /*openFile=*/true);
   }
 
-  // Step #0, unless disabled, check to see if the file is in the #includer's
+  // If we are including a file with a quoted include "foo.h" from inside
+  // a header in a framework that is currently being built, change the include
+  // to <Foo/foo.h>, where "Foo" is the name of the framework in which the
+  // including header was found.
+  llvm::SmallString<128> ScratchFilename;
+  if (CurFileEnt && !isAngled && Filename.find('/') == StringRef::npos) {
+    HeaderFileInfo &IncludingHFI = getFileInfo(CurFileEnt);
+    if (IncludingHFI.IndexHeaderMapHeader) {
+      isAngled = true;
+      ScratchFilename += IncludingHFI.Framework;
+      ScratchFilename += '/';
+      ScratchFilename += Filename;
+      Filename = ScratchFilename;
+    }
+  }
+
+  // Unless disabled, check to see if the file is in the #includer's
   // directory.  This has to be based on CurFileEnt, not CurDir, because
   // CurFileEnt could be a #include of a subdirectory (#include "foo/bar.h") and
   // a subsequent include of "baz.h" should resolve to "whatever/foo/baz.h".
@@ -353,8 +369,20 @@ const FileEntry *HeaderSearch::LookupFile(
     CurDir = &SearchDirs[i];
 
     // This file is a system header or C++ unfriendly if the dir is.
-    getFileInfo(FE).DirInfo = CurDir->getDirCharacteristic();
-
+    HeaderFileInfo &HFI = getFileInfo(FE);
+    HFI.DirInfo = CurDir->getDirCharacteristic();
+
+    // If this file is found in a header map and uses the framework style of
+    // includes, then this header is part of a framework we're building.
+    if (CurDir->isIndexHeaderMap()) {
+      size_t SlashPos = Filename.find('/');
+      if (SlashPos != StringRef::npos) {
+        HFI.IndexHeaderMapHeader = 1;
+        HFI.Framework = getUniqueFrameworkName(StringRef(Filename.begin(), 
+                                                         SlashPos));
+      }
+    }
+    
     // Remember this location for the next lookup we do.
     CacheLookup.second = i;
     return FE;
@@ -550,3 +578,7 @@ size_t HeaderSearch::getTotalMemory() const {
     + LookupFileCache.getAllocator().getTotalMemory()
     + FrameworkMap.getAllocator().getTotalMemory();
 }
+
+StringRef HeaderSearch::getUniqueFrameworkName(StringRef Framework) {
+  return FrameworkNames.GetOrCreateValue(Framework).getKey();
+}
diff --git a/test/Driver/index-header-map.c b/test/Driver/index-header-map.c
new file mode 100644 (file)
index 0000000..8bd677a
--- /dev/null
@@ -0,0 +1,4 @@
+// RUN: %clang -I%S/Before -index-header-map -I%S/Index -I%S/After %s -### 2>> %t.log
+// RUN: FileCheck %s < %t.log
+
+// CHECK: {{-I.*Before.*-index-header-map.*-I.*Index.*-I.*After}}