]> granicus.if.org Git - clang/commitdiff
Allow preprocessor callbacks to recover from a "file not found" error,
authorDouglas Gregor <dgregor@apple.com>
Sun, 20 Nov 2011 17:46:46 +0000 (17:46 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sun, 20 Nov 2011 17:46:46 +0000 (17:46 +0000)
from Jason Haslam!

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

include/clang/Lex/HeaderSearch.h
include/clang/Lex/PPCallbacks.h
include/clang/Lex/Preprocessor.h
lib/Lex/HeaderSearch.cpp
lib/Lex/PPDirectives.cpp

index b56fba538a5e2e91d2eec8420220f30f10e655be..a6d7520f2902b54787b3c580219b8affbf03bc74 100644 (file)
@@ -207,6 +207,15 @@ public:
     //LookupFileCache.clear();
   }
 
+  /// AddSearchPath - Add an additional search path.
+  void AddSearchPath(const DirectoryLookup &dir, bool isAngled) {
+    unsigned idx = isAngled ? SystemDirIdx : AngledDirIdx;
+    SearchDirs.insert(SearchDirs.begin() + idx, dir);
+    if (!isAngled)
+      AngledDirIdx++;
+    SystemDirIdx++;
+  }
+
   /// \brief Set the path to the module cache and the name of the module
   /// we're building
   void configureModules(StringRef CachePath, StringRef BuildingModule) {
@@ -266,7 +275,8 @@ public:
                               const FileEntry *CurFileEnt,
                               SmallVectorImpl<char> *SearchPath,
                               SmallVectorImpl<char> *RelativePath,
-                              ModuleMap::Module **SuggestedModule);
+                              ModuleMap::Module **SuggestedModule,
+                              bool SkipCache = false);
 
   /// LookupSubframeworkHeader - Look up a subframework for the specified
   /// #include file.  For example, if #include'ing <HIToolbox/HIToolbox.h> from
index 1fc1a05db646240f1c7b7c75a46ac99bc5057bab..0c783d474dfd38bc91e214b2c4343b40e3471aad 100644 (file)
@@ -58,6 +58,23 @@ public:
                            SrcMgr::CharacteristicKind FileType) {
   }
 
+  /// FileNotFound - This callback is invoked whenever an inclusion directive
+  /// results in a file-not-found error.
+  ///
+  /// \param FileName The name of the file being included, as written in the 
+  /// source code.
+  ///
+  /// \param RecoveryPath If this client indicates that it can recover from 
+  /// this missing file, the client should set this as an additional header
+  /// search patch.
+  ///
+  /// \returns true to indicate that the preprocessor should attempt to recover
+  /// by adding \p RecoveryPath as a header search path.
+  virtual bool FileNotFound(StringRef FileName,
+                            SmallVectorImpl<char> &RecoveryPath) {
+    return false;
+  }
+
   /// \brief This callback is invoked whenever an inclusion directive of
   /// any kind (\c #include, \c #import, etc.) has been processed, regardless
   /// of whether the inclusion will actually result in an inclusion.
@@ -231,6 +248,12 @@ public:
     Second->FileSkipped(ParentFile, FilenameTok, FileType);
   }
 
+  virtual bool FileNotFound(StringRef FileName,
+                            SmallVectorImpl<char> &RecoveryPath) {
+    return First->FileNotFound(FileName, RecoveryPath) ||
+           Second->FileNotFound(FileName, RecoveryPath);
+  }
+
   virtual void InclusionDirective(SourceLocation HashLoc,
                                   const Token &IncludeTok,
                                   StringRef FileName,
index 90f64c45542836abe951335081a4638662d6c32c..cf77824120830f0a7e256a42f4530d1236f0e579 100644 (file)
@@ -1008,7 +1008,8 @@ public:
                               const DirectoryLookup *&CurDir,
                               SmallVectorImpl<char> *SearchPath,
                               SmallVectorImpl<char> *RelativePath,
-                              ModuleMap::Module **SuggestedModule);
+                              ModuleMap::Module **SuggestedModule,
+                              bool SkipCache = false);
 
   /// GetCurLookup - The DirectoryLookup structure used to find the current
   /// FileEntry, if CurLexer is non-null and if applicable.  This allows us to
index 4deba60b9d34584cba601b646c4d975301cedeae..318e57dc01a0619fba9c053b18d9d7b1c8e20c30 100644 (file)
@@ -408,7 +408,8 @@ const FileEntry *HeaderSearch::LookupFile(
     const FileEntry *CurFileEnt,
     SmallVectorImpl<char> *SearchPath,
     SmallVectorImpl<char> *RelativePath,
-    ModuleMap::Module **SuggestedModule) 
+    ModuleMap::Module **SuggestedModule,
+    bool SkipCache)
 {
   if (SuggestedModule)
     *SuggestedModule = 0;
@@ -484,7 +485,7 @@ const FileEntry *HeaderSearch::LookupFile(
   // If the entry has been previously looked up, the first value will be
   // non-zero.  If the value is equal to i (the start point of our search), then
   // this is a matching hit.
-  if (CacheLookup.first == i+1) {
+  if (!SkipCache && CacheLookup.first == i+1) {
     // Skip querying potentially lots of directories for this lookup.
     i = CacheLookup.second;
   } else {
index 2444364f358f0d787c6e2970eb3057e5b6128d39..88d9429f0012a0661a184a71acee04d8af7023ca 100644 (file)
@@ -486,7 +486,8 @@ const FileEntry *Preprocessor::LookupFile(
     const DirectoryLookup *&CurDir,
     SmallVectorImpl<char> *SearchPath,
     SmallVectorImpl<char> *RelativePath,
-    ModuleMap::Module **SuggestedModule) {
+    ModuleMap::Module **SuggestedModule,
+    bool SkipCache) {
   // If the header lookup mechanism may be relative to the current file, pass in
   // info about where the current file is.
   const FileEntry *CurFileEnt = 0;
@@ -510,7 +511,7 @@ const FileEntry *Preprocessor::LookupFile(
   CurDir = CurDirLookup;
   const FileEntry *FE = HeaderInfo.LookupFile(
       Filename, isAngled, FromDir, CurDir, CurFileEnt,
-      SearchPath, RelativePath, SuggestedModule);
+      SearchPath, RelativePath, SuggestedModule, SkipCache);
   if (FE) return FE;
 
   // Otherwise, see if this is a subframework header.  If so, this is relative
@@ -1288,10 +1289,28 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
     return;
   }
   
-  // Notify the callback object that we've seen an inclusion directive.
-  if (Callbacks)
+  if (Callbacks) {
+    if (!File) {
+      // Give the clients a chance to recover.
+      llvm::SmallString<128> RecoveryPath;
+      if (Callbacks->FileNotFound(Filename, RecoveryPath)) {
+        if (const DirectoryEntry *DE = FileMgr.getDirectory(RecoveryPath)) {
+          // Add the recovery path to the list of search paths.
+          DirectoryLookup DL(DE, SrcMgr::C_User, true, false);
+          HeaderInfo.AddSearchPath(DL, isAngled);
+
+          // Try the lookup again, skipping the cache.
+          File = LookupFile(Filename, isAngled, LookupFrom, CurDir, 0, 0,
+                            AutoModuleImport ? &SuggestedModule : 0,
+                            /*SkipCache*/true);
+        }
+      }
+    }
+
+    // Notify the callback object that we've seen an inclusion directive.
     Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled, File,
                                   End, SearchPath, RelativePath);
+  }
 
   if (File == 0) {
     if (!SuppressIncludeNotFoundError)