From 1c2e9332fa69727425a3a2b912e36e2ab62083f8 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sun, 20 Nov 2011 17:46:46 +0000 Subject: [PATCH] Allow preprocessor callbacks to recover from a "file not found" error, 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 | 12 +++++++++++- include/clang/Lex/PPCallbacks.h | 23 +++++++++++++++++++++++ include/clang/Lex/Preprocessor.h | 3 ++- lib/Lex/HeaderSearch.cpp | 5 +++-- lib/Lex/PPDirectives.cpp | 27 +++++++++++++++++++++++---- 5 files changed, 62 insertions(+), 8 deletions(-) diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h index b56fba538a..a6d7520f29 100644 --- a/include/clang/Lex/HeaderSearch.h +++ b/include/clang/Lex/HeaderSearch.h @@ -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 *SearchPath, SmallVectorImpl *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 from diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h index 1fc1a05db6..0c783d474d 100644 --- a/include/clang/Lex/PPCallbacks.h +++ b/include/clang/Lex/PPCallbacks.h @@ -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 &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 &RecoveryPath) { + return First->FileNotFound(FileName, RecoveryPath) || + Second->FileNotFound(FileName, RecoveryPath); + } + virtual void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 90f64c4554..cf77824120 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -1008,7 +1008,8 @@ public: const DirectoryLookup *&CurDir, SmallVectorImpl *SearchPath, SmallVectorImpl *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 diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp index 4deba60b9d..318e57dc01 100644 --- a/lib/Lex/HeaderSearch.cpp +++ b/lib/Lex/HeaderSearch.cpp @@ -408,7 +408,8 @@ const FileEntry *HeaderSearch::LookupFile( const FileEntry *CurFileEnt, SmallVectorImpl *SearchPath, SmallVectorImpl *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 { diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 2444364f35..88d9429f00 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -486,7 +486,8 @@ const FileEntry *Preprocessor::LookupFile( const DirectoryLookup *&CurDir, SmallVectorImpl *SearchPath, SmallVectorImpl *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) -- 2.40.0