]> granicus.if.org Git - clang/commitdiff
Introduce FileEntryRef and use it when handling includes to report correct dependencies
authorAlex Lorenz <arphaman@gmail.com>
Thu, 22 Aug 2019 18:15:50 +0000 (18:15 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Thu, 22 Aug 2019 18:15:50 +0000 (18:15 +0000)
when the FileManager is reused across invocations

This commit introduces a parallel API to FileManager's getFile: getFileEntryRef, which returns
a reference to the FileEntry, and the name that was used to access the file. In the case of
a VFS with 'use-external-names', the FileEntyRef contains the external name of the file,
not the filename that was used to access it.

The new API is adopted only in the HeaderSearch and Preprocessor for include file lookup, so that the
accessed path can be propagated to SourceManager's FileInfo. SourceManager's FileInfo now can report this accessed path, using
the new getName method. This API is then adopted in the dependency collector, which now correctly reports dependencies when a file
is included both using a symlink and a real path in the case when the FileManager is reused across multiple Preprocessor invocations.

Note that this patch does not fix all dependency collector issues, as the same problem is still present in other cases when dependencies
are obtained using FileSkipped, InclusionDirective, and HasInclude. This will be fixed in follow-up commits.

Differential Revision: https://reviews.llvm.org/D65907

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

24 files changed:
include/clang/Basic/FileManager.h
include/clang/Basic/SourceManager.h
include/clang/Lex/DirectoryLookup.h
include/clang/Lex/HeaderMap.h
include/clang/Lex/HeaderSearch.h
include/clang/Lex/Preprocessor.h
lib/Basic/FileManager.cpp
lib/Basic/SourceManager.cpp
lib/Frontend/CompilerInstance.cpp
lib/Frontend/DependencyFile.cpp
lib/Frontend/FrontendActions.cpp
lib/Frontend/Rewrite/InclusionRewriter.cpp
lib/Frontend/VerifyDiagnosticConsumer.cpp
lib/Lex/HeaderMap.cpp
lib/Lex/HeaderSearch.cpp
lib/Lex/PPDirectives.cpp
lib/Lex/PPMacroExpansion.cpp
lib/Lex/Pragma.cpp
lib/Lex/Preprocessor.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
test/VFS/external-names.c
unittests/Tooling/CMakeLists.txt
unittests/Tooling/DependencyScannerTest.cpp [new file with mode: 0644]

index b6ead7d7053c24177b0eb2ba151728f94ddcd71a..0c9a9adedaf226a8e212401a7362f14ce5ac6344 100644 (file)
@@ -106,6 +106,32 @@ public:
   bool isOpenForTests() const { return File != nullptr; }
 };
 
+/// A reference to a \c FileEntry that includes the name of the file as it was
+/// accessed by the FileManager's client.
+class FileEntryRef {
+public:
+  FileEntryRef(StringRef Name, const FileEntry &Entry)
+      : Name(Name), Entry(Entry) {}
+
+  const StringRef getName() const { return Name; }
+
+  const FileEntry &getFileEntry() const { return Entry; }
+
+  off_t getSize() const { return Entry.getSize(); }
+
+  unsigned getUID() const { return Entry.getUID(); }
+
+  const llvm::sys::fs::UniqueID &getUniqueID() const {
+    return Entry.getUniqueID();
+  }
+
+  time_t getModificationTime() const { return Entry.getModificationTime(); }
+
+private:
+  StringRef Name;
+  const FileEntry &Entry;
+};
+
 /// Implements support for file system lookup, file system caching,
 /// and directory search management.
 ///
@@ -143,13 +169,25 @@ class FileManager : public RefCountedBase<FileManager> {
   llvm::StringMap<llvm::ErrorOr<DirectoryEntry &>, llvm::BumpPtrAllocator>
   SeenDirEntries;
 
+  /// A reference to the file entry that is associated with a particular
+  /// filename, or a reference to another filename that should be looked up
+  /// instead of the accessed filename.
+  ///
+  /// The reference to another filename is specifically useful for Redirecting
+  /// VFSs that use external names. In that case, the \c FileEntryRef returned
+  /// by the \c FileManager will have the external name, and not the name that
+  /// was used to lookup the file.
+  using SeenFileEntryOrRedirect =
+      llvm::PointerUnion<FileEntry *, const StringRef *>;
+
   /// A cache that maps paths to file entries (either real or
   /// virtual) we have looked up, or an error that occurred when we looked up
   /// the file.
   ///
   /// \see SeenDirEntries
-  llvm::StringMap<llvm::ErrorOr<FileEntry &>, llvm::BumpPtrAllocator>
-  SeenFileEntries;
+  llvm::StringMap<llvm::ErrorOr<SeenFileEntryOrRedirect>,
+                  llvm::BumpPtrAllocator>
+      SeenFileEntries;
 
   /// The canonical names of directories.
   llvm::DenseMap<const DirectoryEntry *, llvm::StringRef> CanonicalDirNames;
@@ -200,6 +238,9 @@ public:
   /// Removes the FileSystemStatCache object from the manager.
   void clearStatCache();
 
+  /// Returns the number of unique real file entries cached by the file manager.
+  size_t getNumUniqueRealFiles() const { return UniqueRealFiles.size(); }
+
   /// Lookup, cache, and verify the specified directory (real or
   /// virtual).
   ///
@@ -215,6 +256,10 @@ public:
   /// Lookup, cache, and verify the specified file (real or
   /// virtual).
   ///
+  /// This function is deprecated and will be removed at some point in the
+  /// future, new clients should use
+  ///  \c getFileRef.
+  ///
   /// This returns a \c std::error_code if there was an error loading the file.
   /// If there is no error, the FileEntry is guaranteed to be non-NULL.
   ///
@@ -225,6 +270,24 @@ public:
   llvm::ErrorOr<const FileEntry *>
   getFile(StringRef Filename, bool OpenFile = false, bool CacheFailure = true);
 
+  /// Lookup, cache, and verify the specified file (real or virtual). Return the
+  /// reference to the file entry together with the exact path that was used to
+  /// access a file by a particular call to getFileRef. If the underlying VFS is
+  /// a redirecting VFS that uses external file names, the returned FileEntryRef
+  /// will use the external name instead of the filename that was passed to this
+  /// method.
+  ///
+  /// This returns a \c std::error_code if there was an error loading the file,
+  /// or a \c FileEntryRef otherwise.
+  ///
+  /// \param OpenFile if true and the file exists, it will be opened.
+  ///
+  /// \param CacheFailure If true and the file does not exist, we'll cache
+  /// the failure to find this file.
+  llvm::ErrorOr<FileEntryRef> getFileRef(StringRef Filename,
+                                         bool OpenFile = false,
+                                         bool CacheFailure = true);
+
   /// Returns the current file system options
   FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; }
   const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; }
index e32f749ae6abdf639eac4e0f8aabc282dbafebf1..48b25de7c59e94991000a5bf17c822e9db5b9539 100644 (file)
@@ -265,16 +265,21 @@ namespace SrcMgr {
     llvm::PointerIntPair<const ContentCache*, 3, CharacteristicKind>
         ContentAndKind;
 
+    /// The filename that is used to access the file entry represented by the
+    /// content cache.
+    StringRef Filename;
+
   public:
     /// Return a FileInfo object.
     static FileInfo get(SourceLocation IL, const ContentCache *Con,
-                        CharacteristicKind FileCharacter) {
+                        CharacteristicKind FileCharacter, StringRef Filename) {
       FileInfo X;
       X.IncludeLoc = IL.getRawEncoding();
       X.NumCreatedFIDs = 0;
       X.HasLineDirectives = false;
       X.ContentAndKind.setPointer(Con);
       X.ContentAndKind.setInt(FileCharacter);
+      X.Filename = Filename;
       return X;
     }
 
@@ -299,6 +304,10 @@ namespace SrcMgr {
     void setHasLineDirectives() {
       HasLineDirectives = true;
     }
+
+    /// Returns the name of the file that was used when the file was loaded from
+    /// the underlying file system.
+    StringRef getName() const { return Filename; }
   };
 
   /// Each ExpansionInfo encodes the expansion location - where
@@ -821,7 +830,18 @@ public:
     const SrcMgr::ContentCache *IR =
         getOrCreateContentCache(SourceFile, isSystem(FileCharacter));
     assert(IR && "getOrCreateContentCache() cannot return NULL");
-    return createFileID(IR, IncludePos, FileCharacter, LoadedID, LoadedOffset);
+    return createFileID(IR, SourceFile->getName(), IncludePos, FileCharacter,
+                        LoadedID, LoadedOffset);
+  }
+
+  FileID createFileID(FileEntryRef SourceFile, SourceLocation IncludePos,
+                      SrcMgr::CharacteristicKind FileCharacter,
+                      int LoadedID = 0, unsigned LoadedOffset = 0) {
+    const SrcMgr::ContentCache *IR = getOrCreateContentCache(
+        &SourceFile.getFileEntry(), isSystem(FileCharacter));
+    assert(IR && "getOrCreateContentCache() cannot return NULL");
+    return createFileID(IR, SourceFile.getName(), IncludePos, FileCharacter,
+                        LoadedID, LoadedOffset);
   }
 
   /// Create a new FileID that represents the specified memory buffer.
@@ -832,9 +852,10 @@ public:
                       SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User,
                       int LoadedID = 0, unsigned LoadedOffset = 0,
                       SourceLocation IncludeLoc = SourceLocation()) {
+    StringRef Name = Buffer->getBufferIdentifier();
     return createFileID(
         createMemBufferContentCache(Buffer.release(), /*DoNotFree*/ false),
-        IncludeLoc, FileCharacter, LoadedID, LoadedOffset);
+        Name, IncludeLoc, FileCharacter, LoadedID, LoadedOffset);
   }
 
   enum UnownedTag { Unowned };
@@ -847,8 +868,9 @@ public:
                       SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User,
                       int LoadedID = 0, unsigned LoadedOffset = 0,
                       SourceLocation IncludeLoc = SourceLocation()) {
-    return createFileID(createMemBufferContentCache(Buffer, /*DoNotFree*/true),
-                        IncludeLoc, FileCharacter, LoadedID, LoadedOffset);
+    return createFileID(createMemBufferContentCache(Buffer, /*DoNotFree*/ true),
+                        Buffer->getBufferIdentifier(), IncludeLoc,
+                        FileCharacter, LoadedID, LoadedOffset);
   }
 
   /// Get the FileID for \p SourceFile if it exists. Otherwise, create a
@@ -997,6 +1019,19 @@ public:
     return Content->OrigEntry;
   }
 
+  /// Returns the FileEntryRef for the provided FileID.
+  Optional<FileEntryRef> getFileEntryRefForID(FileID FID) const {
+    bool Invalid = false;
+    const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
+    if (Invalid || !Entry.isFile())
+      return None;
+
+    const SrcMgr::ContentCache *Content = Entry.getFile().getContentCache();
+    if (!Content || !Content->OrigEntry)
+      return None;
+    return FileEntryRef(Entry.getFile().getName(), *Content->OrigEntry);
+  }
+
   /// Returns the FileEntry record for the provided SLocEntry.
   const FileEntry *getFileEntryForSLocEntry(const SrcMgr::SLocEntry &sloc) const
   {
@@ -1785,10 +1820,10 @@ private:
   ///
   /// This works regardless of whether the ContentCache corresponds to a
   /// file or some other input source.
-  FileID createFileID(const SrcMgr::ContentCache* File,
+  FileID createFileID(const SrcMgr::ContentCache *File, StringRef Filename,
                       SourceLocation IncludePos,
-                      SrcMgr::CharacteristicKind DirCharacter,
-                      int LoadedID, unsigned LoadedOffset);
+                      SrcMgr::CharacteristicKind DirCharacter, int LoadedID,
+                      unsigned LoadedOffset);
 
   const SrcMgr::ContentCache *
     getOrCreateContentCache(const FileEntry *SourceFile,
index 7c556ac3517585e57d98310d2af6389188bd5068..c05fc42af2aa1b82abeebdf00786c9c07c3bdde7 100644 (file)
@@ -176,27 +176,20 @@ public:
   /// \param [out] MappedName if this is a headermap which maps the filename to
   /// a framework include ("Foo.h" -> "Foo/Foo.h"), set the new name to this
   /// vector and point Filename to it.
-  const FileEntry *LookupFile(StringRef &Filename, HeaderSearch &HS,
-                              SourceLocation IncludeLoc,
-                              SmallVectorImpl<char> *SearchPath,
-                              SmallVectorImpl<char> *RelativePath,
-                              Module *RequestingModule,
-                              ModuleMap::KnownHeader *SuggestedModule,
-                              bool &InUserSpecifiedSystemFramework,
-                              bool &IsFrameworkFound,
-                              bool &HasBeenMapped,
-                              SmallVectorImpl<char> &MappedName) const;
+  Optional<FileEntryRef>
+  LookupFile(StringRef &Filename, HeaderSearch &HS, SourceLocation IncludeLoc,
+             SmallVectorImpl<char> *SearchPath,
+             SmallVectorImpl<char> *RelativePath, Module *RequestingModule,
+             ModuleMap::KnownHeader *SuggestedModule,
+             bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound,
+             bool &HasBeenMapped, SmallVectorImpl<char> &MappedName) const;
 
 private:
-  const FileEntry *DoFrameworkLookup(
-      StringRef Filename, HeaderSearch &HS,
-      SmallVectorImpl<char> *SearchPath,
-      SmallVectorImpl<char> *RelativePath,
-      Module *RequestingModule,
+  Optional<FileEntryRef> DoFrameworkLookup(
+      StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath,
+      SmallVectorImpl<char> *RelativePath, Module *RequestingModule,
       ModuleMap::KnownHeader *SuggestedModule,
-      bool &InUserSpecifiedSystemFramework,
-      bool &IsFrameworkFound) const;
-
+      bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound) const;
 };
 
 }  // end namespace clang
index eca8755d4525466b6089934226b00cbc2aedcd53..accb061e51ba3aefacd7214ed4d0511c04fbd445 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef LLVM_CLANG_LEX_HEADERMAP_H
 #define LLVM_CLANG_LEX_HEADERMAP_H
 
+#include "clang/Basic/FileManager.h"
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/Support/Compiler.h"
@@ -21,8 +22,6 @@
 
 namespace clang {
 
-class FileEntry;
-class FileManager;
 struct HMapBucket;
 struct HMapHeader;
 
@@ -78,7 +77,7 @@ public:
   /// NULL and the file is found, RawPath will be set to the raw path at which
   /// the file was found in the file system. For example, for a search path
   /// ".." and a filename "../file.h" this would be "../../file.h".
-  const FileEntry *LookupFile(StringRef Filename, FileManager &FM) const;
+  Optional<FileEntryRef> LookupFile(StringRef Filename, FileManager &FM) const;
 
   using HeaderMapImpl::lookupFilename;
   using HeaderMapImpl::getFileName;
index c5e66242444a3b78e299341d78e94cccacde4592..c18d1916c653c23f1d1de441deb8ad0dcee86593 100644 (file)
@@ -395,7 +395,7 @@ public:
   /// found in any of searched SearchDirs. Will be set to false if a framework
   /// is found only through header maps. Doesn't guarantee the requested file is
   /// found.
-  const FileEntry *LookupFile(
+  Optional<FileEntryRef> LookupFile(
       StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
       const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
       ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
@@ -410,7 +410,7 @@ public:
   /// within ".../Carbon.framework/Headers/Carbon.h", check to see if
   /// HIToolbox is a subframework within Carbon.framework.  If so, return
   /// the FileEntry for the designated file, otherwise return null.
-  const FileEntry *LookupSubframeworkHeader(
+  Optional<FileEntryRef> LookupSubframeworkHeader(
       StringRef Filename, const FileEntry *ContextFileEnt,
       SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
       Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule);
@@ -649,7 +649,7 @@ private:
 
   /// Look up the file with the specified name and determine its owning
   /// module.
-  const FileEntry *
+  Optional<FileEntryRef>
   getFileAndSuggestModule(StringRef FileName, SourceLocation IncludeLoc,
                           const DirectoryEntry *Dir, bool IsSystemHeaderDir,
                           Module *RequestingModule,
index fdf4bebd87f5b8403a01ae92188205ee8237c9a8..bbde71834c0dd033d609ad0d043079c6910a4aa0 100644 (file)
@@ -1949,17 +1949,15 @@ public:
 
   /// Given a "foo" or \<foo> reference, look up the indicated file.
   ///
-  /// Returns null on failure.  \p isAngled indicates whether the file
+  /// Returns None on failure.  \p isAngled indicates whether the file
   /// reference is for system \#include's or not (i.e. using <> instead of "").
-  const FileEntry *LookupFile(SourceLocation FilenameLoc, StringRef Filename,
-                              bool isAngled, const DirectoryLookup *FromDir,
-                              const FileEntry *FromFile,
-                              const DirectoryLookup *&CurDir,
-                              SmallVectorImpl<char> *SearchPath,
-                              SmallVectorImpl<char> *RelativePath,
-                              ModuleMap::KnownHeader *SuggestedModule,
-                              bool *IsMapped, bool *IsFrameworkFound,
-                              bool SkipCache = false);
+  Optional<FileEntryRef>
+  LookupFile(SourceLocation FilenameLoc, StringRef Filename, bool isAngled,
+             const DirectoryLookup *FromDir, const FileEntry *FromFile,
+             const DirectoryLookup *&CurDir, SmallVectorImpl<char> *SearchPath,
+             SmallVectorImpl<char> *RelativePath,
+             ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped,
+             bool *IsFrameworkFound, bool SkipCache = false);
 
   /// Get the DirectoryLookup structure used to find the current
   /// FileEntry, if CurLexer is non-null and if applicable.
@@ -2202,6 +2200,15 @@ private:
     }
   };
 
+  Optional<FileEntryRef> LookupHeaderIncludeOrImport(
+      const DirectoryLookup *&CurDir, StringRef Filename,
+      SourceLocation FilenameLoc, CharSourceRange FilenameRange,
+      const Token &FilenameTok, bool &IsFrameworkFound, bool IsImportDecl,
+      bool &IsMapped, const DirectoryLookup *LookupFrom,
+      const FileEntry *LookupFromFile, SmallString<128> &NormalizedPath,
+      SmallVectorImpl<char> &RelativePath, SmallVectorImpl<char> &SearchPath,
+      ModuleMap::KnownHeader &SuggestedModule, bool isAngled);
+
   // File inclusion.
   void HandleIncludeDirective(SourceLocation HashLoc, Token &Tok,
                               const DirectoryLookup *LookupFrom = nullptr,
index 2666868bcf6c63ca152bcca8e87981d1e8944b16..3af27564b4c6c4466abd3d2b37efd709eba18fbb 100644 (file)
@@ -184,13 +184,30 @@ FileManager::getDirectory(StringRef DirName, bool CacheFailure) {
 
 llvm::ErrorOr<const FileEntry *>
 FileManager::getFile(StringRef Filename, bool openFile, bool CacheFailure) {
+  auto Result = getFileRef(Filename, openFile, CacheFailure);
+  if (Result)
+    return &Result->getFileEntry();
+  return Result.getError();
+}
+
+llvm::ErrorOr<FileEntryRef>
+FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
   ++NumFileLookups;
 
   // See if there is already an entry in the map.
   auto SeenFileInsertResult =
       SeenFileEntries.insert({Filename, std::errc::no_such_file_or_directory});
-  if (!SeenFileInsertResult.second)
-    return promoteInnerReference(SeenFileInsertResult.first->second);
+  if (!SeenFileInsertResult.second) {
+    if (!SeenFileInsertResult.first->second)
+      return SeenFileInsertResult.first->second.getError();
+    // Construct and return and FileEntryRef, unless it's a redirect to another
+    // filename.
+    SeenFileEntryOrRedirect Value = *SeenFileInsertResult.first->second;
+    FileEntry *FE;
+    if (LLVM_LIKELY(FE = Value.dyn_cast<FileEntry *>()))
+      return FileEntryRef(SeenFileInsertResult.first->first(), *FE);
+    return getFileRef(*Value.get<const StringRef *>(), openFile, CacheFailure);
+  }
 
   // We've not seen this before. Fill it in.
   ++NumFileCacheMisses;
@@ -241,16 +258,20 @@ FileManager::getFile(StringRef Filename, bool openFile, bool CacheFailure) {
   // This occurs when one dir is symlinked to another, for example.
   FileEntry &UFE = UniqueRealFiles[Status.getUniqueID()];
 
-  NamedFileEnt.second = UFE;
+  NamedFileEnt.second = &UFE;
 
   // If the name returned by getStatValue is different than Filename, re-intern
   // the name.
   if (Status.getName() != Filename) {
     auto &NamedFileEnt =
-      *SeenFileEntries.insert({Status.getName(), UFE}).first;
-    assert(&*NamedFileEnt.second == &UFE &&
+        *SeenFileEntries.insert({Status.getName(), &UFE}).first;
+    assert((*NamedFileEnt.second).get<FileEntry *>() == &UFE &&
            "filename from getStatValue() refers to wrong file");
     InterndFileName = NamedFileEnt.first().data();
+    // In addition to re-interning the name, construct a redirecting seen file
+    // entry, that will point to the name the filesystem actually wants to use.
+    StringRef *Redirect = new (CanonicalNameStorage) StringRef(InterndFileName);
+    SeenFileInsertResult.first->second = Redirect;
   }
 
   if (UFE.isValid()) { // Already have an entry with this inode, return it.
@@ -269,9 +290,11 @@ FileManager::getFile(StringRef Filename, bool openFile, bool CacheFailure) {
     // to switch towards a design where we return a FileName object that
     // encapsulates both the name by which the file was accessed and the
     // corresponding FileEntry.
+    // FIXME: The Name should be removed from FileEntry once all clients
+    // adopt FileEntryRef.
     UFE.Name = InterndFileName;
 
-    return &UFE;
+    return FileEntryRef(InterndFileName, UFE);
   }
 
   // Otherwise, we don't have this file yet, add it.
@@ -292,7 +315,7 @@ FileManager::getFile(StringRef Filename, bool openFile, bool CacheFailure) {
     // We should still fill the path even if we aren't opening the file.
     fillRealPathName(&UFE, InterndFileName);
   }
-  return &UFE;
+  return FileEntryRef(InterndFileName, UFE);
 }
 
 const FileEntry *
@@ -303,8 +326,14 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size,
   // See if there is already an entry in the map for an existing file.
   auto &NamedFileEnt = *SeenFileEntries.insert(
       {Filename, std::errc::no_such_file_or_directory}).first;
-  if (NamedFileEnt.second)
-    return &*NamedFileEnt.second;
+  if (NamedFileEnt.second) {
+    SeenFileEntryOrRedirect Value = *NamedFileEnt.second;
+    FileEntry *FE;
+    if (LLVM_LIKELY(FE = Value.dyn_cast<FileEntry *>()))
+      return FE;
+    return getVirtualFile(*Value.get<const StringRef *>(), Size,
+                          ModificationTime);
+  }
 
   // We've not seen this before, or the file is cached as non-existent.
   ++NumFileCacheMisses;
@@ -329,7 +358,7 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size,
       Status.getUser(), Status.getGroup(), Size,
       Status.getType(), Status.getPermissions());
 
-    NamedFileEnt.second = *UFE;
+    NamedFileEnt.second = UFE;
 
     // If we had already opened this file, close it now so we don't
     // leak the descriptor. We're not going to use the file
@@ -347,7 +376,7 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size,
   } else {
     VirtualFileEntries.push_back(std::make_unique<FileEntry>());
     UFE = VirtualFileEntries.back().get();
-    NamedFileEnt.second = *UFE;
+    NamedFileEnt.second = UFE;
   }
 
   UFE->Name    = InterndFileName;
@@ -493,12 +522,14 @@ void FileManager::GetUniqueIDMapping(
   UIDToFiles.resize(NextFileUID);
 
   // Map file entries
-  for (llvm::StringMap<llvm::ErrorOr<FileEntry &>,
+  for (llvm::StringMap<llvm::ErrorOr<SeenFileEntryOrRedirect>,
                        llvm::BumpPtrAllocator>::const_iterator
-         FE = SeenFileEntries.begin(), FEEnd = SeenFileEntries.end();
+           FE = SeenFileEntries.begin(),
+           FEEnd = SeenFileEntries.end();
        FE != FEEnd; ++FE)
-    if (auto Entry = FE->getValue()) {
-      UIDToFiles[Entry->getUID()] = &*Entry;
+    if (llvm::ErrorOr<SeenFileEntryOrRedirect> Entry = FE->getValue()) {
+      if (const auto *FE = (*Entry).dyn_cast<FileEntry *>())
+        UIDToFiles[FE->getUID()] = FE;
     }
 
   // Map virtual file entries
index 4f237b1a2b101abfb6f73346333efe9d0ae66eda..aea463aed7ac9d22e718e7f3f2845ed0f1e377f2 100644 (file)
@@ -466,10 +466,9 @@ const SrcMgr::SLocEntry &SourceManager::loadSLocEntry(unsigned Index,
     // If the file of the SLocEntry changed we could still have loaded it.
     if (!SLocEntryLoaded[Index]) {
       // Try to recover; create a SLocEntry so the rest of clang can handle it.
-      LoadedSLocEntryTable[Index] = SLocEntry::get(0,
-                                 FileInfo::get(SourceLocation(),
-                                               getFakeContentCacheForRecovery(),
-                                               SrcMgr::C_User));
+      LoadedSLocEntryTable[Index] = SLocEntry::get(
+          0, FileInfo::get(SourceLocation(), getFakeContentCacheForRecovery(),
+                           SrcMgr::C_User, ""));
     }
   }
 
@@ -556,7 +555,7 @@ FileID SourceManager::getNextFileID(FileID FID) const {
 /// createFileID - Create a new FileID for the specified ContentCache and
 /// include position.  This works regardless of whether the ContentCache
 /// corresponds to a file or some other input source.
-FileID SourceManager::createFileID(const ContentCache *File,
+FileID SourceManager::createFileID(const ContentCache *File, StringRef Filename,
                                    SourceLocation IncludePos,
                                    SrcMgr::CharacteristicKind FileCharacter,
                                    int LoadedID, unsigned LoadedOffset) {
@@ -565,14 +564,14 @@ FileID SourceManager::createFileID(const ContentCache *File,
     unsigned Index = unsigned(-LoadedID) - 2;
     assert(Index < LoadedSLocEntryTable.size() && "FileID out of range");
     assert(!SLocEntryLoaded[Index] && "FileID already loaded");
-    LoadedSLocEntryTable[Index] = SLocEntry::get(LoadedOffset,
-        FileInfo::get(IncludePos, File, FileCharacter));
+    LoadedSLocEntryTable[Index] = SLocEntry::get(
+        LoadedOffset, FileInfo::get(IncludePos, File, FileCharacter, Filename));
     SLocEntryLoaded[Index] = true;
     return FileID::get(LoadedID);
   }
-  LocalSLocEntryTable.push_back(SLocEntry::get(NextLocalOffset,
-                                               FileInfo::get(IncludePos, File,
-                                                             FileCharacter)));
+  LocalSLocEntryTable.push_back(
+      SLocEntry::get(NextLocalOffset,
+                     FileInfo::get(IncludePos, File, FileCharacter, Filename)));
   unsigned FileSize = File->getSize();
   assert(NextLocalOffset + FileSize + 1 > NextLocalOffset &&
          NextLocalOffset + FileSize + 1 <= CurrentLoadedOffset &&
index c7dedb78ed814d6dbd379a6778f704a95f8b582c..cbf519758ec33d1445a95660b6be702ba189c813 100644 (file)
@@ -831,33 +831,37 @@ bool CompilerInstance::InitializeSourceManager(
 
   // Figure out where to get and map in the main file.
   if (InputFile != "-") {
-    auto FileOrErr = FileMgr.getFile(InputFile, /*OpenFile=*/true);
+    auto FileOrErr = FileMgr.getFileRef(InputFile, /*OpenFile=*/true);
     if (!FileOrErr) {
       Diags.Report(diag::err_fe_error_reading) << InputFile;
       return false;
     }
-    auto File = *FileOrErr;
+    FileEntryRef File = *FileOrErr;
 
     // The natural SourceManager infrastructure can't currently handle named
     // pipes, but we would at least like to accept them for the main
     // file. Detect them here, read them with the volatile flag so FileMgr will
     // pick up the correct size, and simply override their contents as we do for
     // STDIN.
-    if (File->isNamedPipe()) {
-      auto MB = FileMgr.getBufferForFile(File, /*isVolatile=*/true);
+    if (File.getFileEntry().isNamedPipe()) {
+      auto MB =
+          FileMgr.getBufferForFile(&File.getFileEntry(), /*isVolatile=*/true);
       if (MB) {
         // Create a new virtual file that will have the correct size.
-        File = FileMgr.getVirtualFile(InputFile, (*MB)->getBufferSize(), 0);
-        SourceMgr.overrideFileContents(File, std::move(*MB));
+        const FileEntry *FE =
+            FileMgr.getVirtualFile(InputFile, (*MB)->getBufferSize(), 0);
+        SourceMgr.overrideFileContents(FE, std::move(*MB));
+        SourceMgr.setMainFileID(
+            SourceMgr.createFileID(FE, SourceLocation(), Kind));
       } else {
         Diags.Report(diag::err_cannot_open_file) << InputFile
                                                  << MB.getError().message();
         return false;
       }
+    } else {
+      SourceMgr.setMainFileID(
+          SourceMgr.createFileID(File, SourceLocation(), Kind));
     }
-
-    SourceMgr.setMainFileID(
-        SourceMgr.createFileID(File, SourceLocation(), Kind));
   } else {
     llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> SBOrErr =
         llvm::MemoryBuffer::getSTDIN();
index a80f9b9cdd1dbb328bafadcac98ba56b00a6d19d..aeff571c145b37f46503ae1758dbecc5fc95fb8c 100644 (file)
@@ -46,13 +46,13 @@ struct DepCollectorPPCallbacks : public PPCallbacks {
     // Dependency generation really does want to go all the way to the
     // file entry for a source location to find out what is depended on.
     // We do not want #line markers to affect dependency generation!
-    const FileEntry *FE =
-        SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc)));
-    if (!FE)
+    Optional<FileEntryRef> File =
+        SM.getFileEntryRefForID(SM.getFileID(SM.getExpansionLoc(Loc)));
+    if (!File)
       return;
 
     StringRef Filename =
-        llvm::sys::path::remove_leading_dotslash(FE->getName());
+        llvm::sys::path::remove_leading_dotslash(File->getName());
 
     DepCollector.maybeAddDependency(Filename, /*FromModule*/false,
                                     isSystem(FileType),
index 08826c2fea537817197dc643a28e48bcb20902bc..28416e722671284ad28d9edb172bf8c6f9a3ab32 100644 (file)
@@ -287,15 +287,15 @@ bool GenerateHeaderModuleAction::BeginSourceFileAction(
   SmallVector<Module::Header, 16> Headers;
   for (StringRef Name : ModuleHeaders) {
     const DirectoryLookup *CurDir = nullptr;
-    const FileEntry *FE = HS.LookupFile(
-        Name, SourceLocation(), /*Angled*/ false, nullptr, CurDir,
-        None, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+    Optional<FileEntryRef> FE = HS.LookupFile(
+        Name, SourceLocation(), /*Angled*/ false, nullptr, CurDir, None,
+        nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
     if (!FE) {
       CI.getDiagnostics().Report(diag::err_module_header_file_not_found)
         << Name;
       continue;
     }
-    Headers.push_back({Name, FE});
+    Headers.push_back({Name, &FE->getFileEntry()});
   }
   HS.getModuleMap().createHeaderModule(CI.getLangOpts().CurrentModule, Headers);
 
index cb4e773aca87a13ae12b90d357a99bae73f40900..f8388c506860dda43b2b61842bef25f1bb0dc204 100644 (file)
@@ -412,11 +412,11 @@ bool InclusionRewriter::HandleHasInclude(
       Includers;
   Includers.push_back(std::make_pair(FileEnt, FileEnt->getDir()));
   // FIXME: Why don't we call PP.LookupFile here?
-  const FileEntry *File = PP.getHeaderSearchInfo().LookupFile(
+  Optional<FileEntryRef> File = PP.getHeaderSearchInfo().LookupFile(
       Filename, SourceLocation(), isAngled, Lookup, CurDir, Includers, nullptr,
       nullptr, nullptr, nullptr, nullptr, nullptr);
 
-  FileExists = File != nullptr;
+  FileExists = File.hasValue();
   return true;
 }
 
index 47f2ae39b8f55c2fffd3701bd9c33a613f84abb7..82c2af87706eb785305baad2e9383e9779b9f026 100644 (file)
@@ -528,15 +528,16 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
 
         // Lookup file via Preprocessor, like a #include.
         const DirectoryLookup *CurDir;
-        const FileEntry *FE =
+        Optional<FileEntryRef> File =
             PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir,
                            nullptr, nullptr, nullptr, nullptr, nullptr);
-        if (!FE) {
+        if (!File) {
           Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
                        diag::err_verify_missing_file) << Filename << KindStr;
           continue;
         }
 
+        const FileEntry *FE = &File->getFileEntry();
         if (SM.translateFile(FE).isInvalid())
           SM.createFileID(FE, Pos, SrcMgr::C_User);
 
index 7a46fafafa08078504c9260981776d1cc0200860..1c7fb1a476465b8794b5e95b5f39fdc0e3ba17ee 100644 (file)
@@ -196,17 +196,17 @@ LLVM_DUMP_METHOD void HeaderMapImpl::dump() const {
 
 /// LookupFile - Check to see if the specified relative filename is located in
 /// this HeaderMap.  If so, open it and return its FileEntry.
-const FileEntry *HeaderMap::LookupFile(
-    StringRef Filename, FileManager &FM) const {
+Optional<FileEntryRef> HeaderMap::LookupFile(StringRef Filename,
+                                             FileManager &FM) const {
 
   SmallString<1024> Path;
   StringRef Dest = HeaderMapImpl::lookupFilename(Filename, Path);
   if (Dest.empty())
-    return nullptr;
+    return None;
 
-  if (auto File = FM.getFile(Dest))
+  if (auto File = FM.getFileRef(Dest))
     return *File;
-  return nullptr;
+  return None;
 }
 
 StringRef HeaderMapImpl::lookupFilename(StringRef Filename,
index 7bc953ba1aa5ba720c481d569aff2a327ccec35a..84af65c30d504f611036c0b0dd98b3e44445f005 100644 (file)
@@ -304,14 +304,13 @@ StringRef DirectoryLookup::getName() const {
   return getHeaderMap()->getFileName();
 }
 
-const FileEntry *HeaderSearch::getFileAndSuggestModule(
+Optional<FileEntryRef> HeaderSearch::getFileAndSuggestModule(
     StringRef FileName, SourceLocation IncludeLoc, const DirectoryEntry *Dir,
     bool IsSystemHeaderDir, Module *RequestingModule,
     ModuleMap::KnownHeader *SuggestedModule) {
   // If we have a module map that might map this header, load it and
   // check whether we'll have a suggestion for a module.
-  llvm::ErrorOr<const FileEntry *> File =
-      getFileMgr().getFile(FileName, /*OpenFile=*/true);
+  auto File = getFileMgr().getFileRef(FileName, /*OpenFile=*/true);
   if (!File) {
     // For rare, surprising errors (e.g. "out of file handles"), diag the EC
     // message.
@@ -322,32 +321,26 @@ const FileEntry *HeaderSearch::getFileAndSuggestModule(
       Diags.Report(IncludeLoc, diag::err_cannot_open_file)
           << FileName << EC.message();
     }
-    return nullptr;
+    return None;
   }
 
   // If there is a module that corresponds to this header, suggest it.
-  if (!findUsableModuleForHeader(*File, Dir ? Dir : (*File)->getDir(),
-                                 RequestingModule, SuggestedModule,
-                                 IsSystemHeaderDir))
-    return nullptr;
+  if (!findUsableModuleForHeader(
+          &File->getFileEntry(), Dir ? Dir : File->getFileEntry().getDir(),
+          RequestingModule, SuggestedModule, IsSystemHeaderDir))
+    return None;
 
   return *File;
 }
 
 /// LookupFile - Lookup the specified file in this search path, returning it
 /// if it exists or returning null if not.
-const FileEntry *DirectoryLookup::LookupFile(
-    StringRef &Filename,
-    HeaderSearch &HS,
-    SourceLocation IncludeLoc,
-    SmallVectorImpl<char> *SearchPath,
-    SmallVectorImpl<char> *RelativePath,
-    Module *RequestingModule,
-    ModuleMap::KnownHeader *SuggestedModule,
-    bool &InUserSpecifiedSystemFramework,
-    bool &IsFrameworkFound,
-    bool &HasBeenMapped,
-    SmallVectorImpl<char> &MappedName) const {
+Optional<FileEntryRef> DirectoryLookup::LookupFile(
+    StringRef &Filename, HeaderSearch &HS, SourceLocation IncludeLoc,
+    SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
+    Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
+    bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound,
+    bool &HasBeenMapped, SmallVectorImpl<char> &MappedName) const {
   InUserSpecifiedSystemFramework = false;
   HasBeenMapped = false;
 
@@ -381,9 +374,19 @@ const FileEntry *DirectoryLookup::LookupFile(
   SmallString<1024> Path;
   StringRef Dest = HM->lookupFilename(Filename, Path);
   if (Dest.empty())
-    return nullptr;
+    return None;
 
-  const FileEntry *Result;
+  auto FixupSearchPath = [&]() {
+    if (SearchPath) {
+      StringRef SearchPathRef(getName());
+      SearchPath->clear();
+      SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
+    }
+    if (RelativePath) {
+      RelativePath->clear();
+      RelativePath->append(Filename.begin(), Filename.end());
+    }
+  };
 
   // Check if the headermap maps the filename to a framework include
   // ("Foo.h" -> "Foo/Foo.h"), in which case continue header lookup using the
@@ -393,25 +396,17 @@ const FileEntry *DirectoryLookup::LookupFile(
     MappedName.append(Dest.begin(), Dest.end());
     Filename = StringRef(MappedName.begin(), MappedName.size());
     HasBeenMapped = true;
-    Result = HM->LookupFile(Filename, HS.getFileMgr());
-  } else if (auto Res = HS.getFileMgr().getFile(Dest)) {
-    Result = *Res;
-  } else {
-    Result = nullptr;
-  }
-
-  if (Result) {
-    if (SearchPath) {
-      StringRef SearchPathRef(getName());
-      SearchPath->clear();
-      SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
-    }
-    if (RelativePath) {
-      RelativePath->clear();
-      RelativePath->append(Filename.begin(), Filename.end());
+    Optional<FileEntryRef> Result = HM->LookupFile(Filename, HS.getFileMgr());
+    if (Result) {
+      FixupSearchPath();
+      return *Result;
     }
+  } else if (auto Res = HS.getFileMgr().getFileRef(Dest)) {
+    FixupSearchPath();
+    return *Res;
   }
-  return Result;
+
+  return None;
 }
 
 /// Given a framework directory, find the top-most framework directory.
@@ -476,7 +471,7 @@ static bool needModuleLookup(Module *RequestingModule,
 
 /// DoFrameworkLookup - Do a lookup of the specified file in the current
 /// DirectoryLookup, which is a framework directory.
-const FileEntry *DirectoryLookup::DoFrameworkLookup(
+Optional<FileEntryRef> DirectoryLookup::DoFrameworkLookup(
     StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath,
     SmallVectorImpl<char> *RelativePath, Module *RequestingModule,
     ModuleMap::KnownHeader *SuggestedModule,
@@ -485,7 +480,8 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
 
   // Framework names must have a '/' in the filename.
   size_t SlashPos = Filename.find('/');
-  if (SlashPos == StringRef::npos) return nullptr;
+  if (SlashPos == StringRef::npos)
+    return None;
 
   // Find out if this is the home for the specified framework, by checking
   // HeaderSearch.  Possible answers are yes/no and unknown.
@@ -494,7 +490,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
 
   // If it is known and in some other directory, fail.
   if (CacheEntry.Directory && CacheEntry.Directory != getFrameworkDir())
-    return nullptr;
+    return None;
 
   // Otherwise, construct the path to this framework dir.
 
@@ -517,7 +513,8 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
 
     // If the framework dir doesn't exist, we fail.
     auto Dir = FileMgr.getDirectory(FrameworkName);
-    if (!Dir) return nullptr;
+    if (!Dir)
+      return None;
 
     // Otherwise, if it does, remember that this is the right direntry for this
     // framework.
@@ -556,11 +553,10 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
 
   FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
 
-  const FileEntry *FE = nullptr;
-  if (auto File = FileMgr.getFile(FrameworkName, /*OpenFile=*/!SuggestedModule))
-    FE = *File;
+  llvm::ErrorOr<FileEntryRef> File =
+      FileMgr.getFileRef(FrameworkName, /*OpenFile=*/!SuggestedModule);
 
-  if (!FE) {
+  if (!File) {
     // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
     const char *Private = "Private";
     FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
@@ -569,15 +565,13 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
       SearchPath->insert(SearchPath->begin()+OrigSize, Private,
                          Private+strlen(Private));
 
-    if (auto File = FileMgr.getFile(FrameworkName, 
-                                    /*OpenFile=*/!SuggestedModule))
-      FE = *File;
+    File = FileMgr.getFileRef(FrameworkName, /*OpenFile=*/!SuggestedModule);
   }
 
   // If we found the header and are allowed to suggest a module, do so now.
-  if (FE && needModuleLookup(RequestingModule, SuggestedModule)) {
+  if (File && needModuleLookup(RequestingModule, SuggestedModule)) {
     // Find the framework in which this header occurs.
-    StringRef FrameworkPath = FE->getDir()->getName();
+    StringRef FrameworkPath = File->getFileEntry().getDir()->getName();
     bool FoundFramework = false;
     do {
       // Determine whether this directory exists.
@@ -601,15 +595,19 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
     bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
     if (FoundFramework) {
       if (!HS.findUsableModuleForFrameworkHeader(
-              FE, FrameworkPath, RequestingModule, SuggestedModule, IsSystem))
-        return nullptr;
+              &File->getFileEntry(), FrameworkPath, RequestingModule,
+              SuggestedModule, IsSystem))
+        return None;
     } else {
-      if (!HS.findUsableModuleForHeader(FE, getDir(), RequestingModule,
-                                        SuggestedModule, IsSystem))
-        return nullptr;
+      if (!HS.findUsableModuleForHeader(&File->getFileEntry(), getDir(),
+                                        RequestingModule, SuggestedModule,
+                                        IsSystem))
+        return None;
     }
   }
-  return FE;
+  if (File)
+    return *File;
+  return None;
 }
 
 void HeaderSearch::setTarget(const TargetInfo &Target) {
@@ -714,7 +712,7 @@ diagnoseFrameworkInclude(DiagnosticsEngine &Diags, SourceLocation IncludeLoc,
 /// for system \#include's or not (i.e. using <> instead of ""). Includers, if
 /// non-empty, indicates where the \#including file(s) are, in case a relative
 /// search is needed. Microsoft mode will pass all \#including files.
-const FileEntry *HeaderSearch::LookupFile(
+Optional<FileEntryRef> HeaderSearch::LookupFile(
     StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
     const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
     ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
@@ -736,7 +734,8 @@ const FileEntry *HeaderSearch::LookupFile(
     CurDir = nullptr;
 
     // If this was an #include_next "/absolute/file", fail.
-    if (FromDir) return nullptr;
+    if (FromDir)
+      return None;
 
     if (SearchPath)
       SearchPath->clear();
@@ -751,8 +750,9 @@ const FileEntry *HeaderSearch::LookupFile(
   }
 
   // This is the header that MSVC's header search would have found.
-  const FileEntry *MSFE = nullptr;
   ModuleMap::KnownHeader MSSuggestedModule;
+  const FileEntry *MSFE_FE = nullptr;
+  StringRef MSFE_Name;
 
   // Unless disabled, check to see if the file is in the #includer's
   // directory.  This cannot be based on CurDir, because each includer could be
@@ -781,7 +781,7 @@ const FileEntry *HeaderSearch::LookupFile(
       bool IncluderIsSystemHeader =
           Includer ? getFileInfo(Includer).DirInfo != SrcMgr::C_User :
           BuildSystemModule;
-      if (const FileEntry *FE = getFileAndSuggestModule(
+      if (Optional<FileEntryRef> FE = getFileAndSuggestModule(
               TmpDir, IncludeLoc, IncluderAndDir.second, IncluderIsSystemHeader,
               RequestingModule, SuggestedModule)) {
         if (!Includer) {
@@ -800,7 +800,7 @@ const FileEntry *HeaderSearch::LookupFile(
         bool IndexHeaderMapHeader = FromHFI.IndexHeaderMapHeader;
         StringRef Framework = FromHFI.Framework;
 
-        HeaderFileInfo &ToHFI = getFileInfo(FE);
+        HeaderFileInfo &ToHFI = getFileInfo(&FE->getFileEntry());
         ToHFI.DirInfo = DirInfo;
         ToHFI.IndexHeaderMapHeader = IndexHeaderMapHeader;
         ToHFI.Framework = Framework;
@@ -817,7 +817,7 @@ const FileEntry *HeaderSearch::LookupFile(
         if (First) {
           diagnoseFrameworkInclude(Diags, IncludeLoc,
                                    IncluderAndDir.second->getName(), Filename,
-                                   FE);
+                                   &FE->getFileEntry());
           return FE;
         }
 
@@ -827,7 +827,8 @@ const FileEntry *HeaderSearch::LookupFile(
         if (Diags.isIgnored(diag::ext_pp_include_search_ms, IncludeLoc)) {
           return FE;
         } else {
-          MSFE = FE;
+          MSFE_FE = &FE->getFileEntry();
+          MSFE_Name = FE->getName();
           if (SuggestedModule) {
             MSSuggestedModule = *SuggestedModule;
             *SuggestedModule = ModuleMap::KnownHeader();
@@ -839,6 +840,9 @@ const FileEntry *HeaderSearch::LookupFile(
     }
   }
 
+  Optional<FileEntryRef> MSFE(MSFE_FE ? FileEntryRef(MSFE_Name, *MSFE_FE)
+                                      : Optional<FileEntryRef>());
+
   CurDir = nullptr;
 
   // If this is a system #include, ignore the user #include locs.
@@ -880,7 +884,7 @@ const FileEntry *HeaderSearch::LookupFile(
     bool InUserSpecifiedSystemFramework = false;
     bool HasBeenMapped = false;
     bool IsFrameworkFoundInDir = false;
-    const FileEntry *FE = SearchDirs[i].LookupFile(
+    Optional<FileEntryRef> File = SearchDirs[i].LookupFile(
         Filename, *this, IncludeLoc, SearchPath, RelativePath, RequestingModule,
         SuggestedModule, InUserSpecifiedSystemFramework, IsFrameworkFoundInDir,
         HasBeenMapped, MappedName);
@@ -895,12 +899,13 @@ const FileEntry *HeaderSearch::LookupFile(
       // lookups, ignore IsFrameworkFoundInDir after the first remapping and not
       // just for remapping in a current search directory.
       *IsFrameworkFound |= (IsFrameworkFoundInDir && !CacheLookup.MappedName);
-    if (!FE) continue;
+    if (!File)
+      continue;
 
     CurDir = &SearchDirs[i];
 
     // This file is a system header or C++ unfriendly if the dir is.
-    HeaderFileInfo &HFI = getFileInfo(FE);
+    HeaderFileInfo &HFI = getFileInfo(&File->getFileEntry());
     HFI.DirInfo = CurDir->getDirCharacteristic();
 
     // If the directory characteristic is User but this framework was
@@ -930,7 +935,8 @@ const FileEntry *HeaderSearch::LookupFile(
       }
     }
 
-    if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) {
+    if (checkMSVCHeaderSearch(Diags, MSFE ? &MSFE->getFileEntry() : nullptr,
+                              &File->getFileEntry(), IncludeLoc)) {
       if (SuggestedModule)
         *SuggestedModule = MSSuggestedModule;
       return MSFE;
@@ -938,13 +944,13 @@ const FileEntry *HeaderSearch::LookupFile(
 
     bool FoundByHeaderMap = !IsMapped ? false : *IsMapped;
     if (!Includers.empty())
-      diagnoseFrameworkInclude(Diags, IncludeLoc,
-                               Includers.front().second->getName(), Filename,
-                               FE, isAngled, FoundByHeaderMap);
+      diagnoseFrameworkInclude(
+          Diags, IncludeLoc, Includers.front().second->getName(), Filename,
+          &File->getFileEntry(), isAngled, FoundByHeaderMap);
 
     // Remember this location for the next lookup we do.
     CacheLookup.HitIdx = i;
-    return FE;
+    return File;
   }
 
   // If we are including a file with a quoted include "foo.h" from inside
@@ -960,12 +966,14 @@ const FileEntry *HeaderSearch::LookupFile(
       ScratchFilename += '/';
       ScratchFilename += Filename;
 
-      const FileEntry *FE = LookupFile(
+      Optional<FileEntryRef> File = LookupFile(
           ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, CurDir,
           Includers.front(), SearchPath, RelativePath, RequestingModule,
           SuggestedModule, IsMapped, /*IsFrameworkFound=*/nullptr);
 
-      if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) {
+      if (checkMSVCHeaderSearch(Diags, MSFE ? &MSFE->getFileEntry() : nullptr,
+                                File ? &File->getFileEntry() : nullptr,
+                                IncludeLoc)) {
         if (SuggestedModule)
           *SuggestedModule = MSSuggestedModule;
         return MSFE;
@@ -974,11 +982,12 @@ const FileEntry *HeaderSearch::LookupFile(
       LookupFileCacheInfo &CacheLookup = LookupFileCache[Filename];
       CacheLookup.HitIdx = LookupFileCache[ScratchFilename].HitIdx;
       // FIXME: SuggestedModule.
-      return FE;
+      return File;
     }
   }
 
-  if (checkMSVCHeaderSearch(Diags, MSFE, nullptr, IncludeLoc)) {
+  if (checkMSVCHeaderSearch(Diags, MSFE ? &MSFE->getFileEntry() : nullptr,
+                            nullptr, IncludeLoc)) {
     if (SuggestedModule)
       *SuggestedModule = MSSuggestedModule;
     return MSFE;
@@ -986,7 +995,7 @@ const FileEntry *HeaderSearch::LookupFile(
 
   // Otherwise, didn't find it. Remember we didn't find this.
   CacheLookup.HitIdx = SearchDirs.size();
-  return nullptr;
+  return None;
 }
 
 /// LookupSubframeworkHeader - Look up a subframework for the specified
@@ -994,19 +1003,17 @@ const FileEntry *HeaderSearch::LookupFile(
 /// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox
 /// is a subframework within Carbon.framework.  If so, return the FileEntry
 /// for the designated file, otherwise return null.
-const FileEntry *HeaderSearch::
-LookupSubframeworkHeader(StringRef Filename,
-                         const FileEntry *ContextFileEnt,
-                         SmallVectorImpl<char> *SearchPath,
-                         SmallVectorImpl<char> *RelativePath,
-                         Module *RequestingModule,
-                         ModuleMap::KnownHeader *SuggestedModule) {
+Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
+    StringRef Filename, const FileEntry *ContextFileEnt,
+    SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
+    Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule) {
   assert(ContextFileEnt && "No context file?");
 
   // Framework names must have a '/' in the filename.  Find it.
   // FIXME: Should we permit '\' on Windows?
   size_t SlashPos = Filename.find('/');
-  if (SlashPos == StringRef::npos) return nullptr;
+  if (SlashPos == StringRef::npos)
+    return None;
 
   // Look up the base framework name of the ContextFileEnt.
   StringRef ContextName = ContextFileEnt->getName();
@@ -1017,7 +1024,7 @@ LookupSubframeworkHeader(StringRef Filename,
   if (FrameworkPos == StringRef::npos ||
       (ContextName[FrameworkPos + DotFrameworkLen] != '/' &&
        ContextName[FrameworkPos + DotFrameworkLen] != '\\'))
-    return nullptr;
+    return None;
 
   SmallString<1024> FrameworkName(ContextName.data(), ContextName.data() +
                                                           FrameworkPos +
@@ -1037,7 +1044,7 @@ LookupSubframeworkHeader(StringRef Filename,
       CacheLookup.first().size() == FrameworkName.size() &&
       memcmp(CacheLookup.first().data(), &FrameworkName[0],
              CacheLookup.first().size()) != 0)
-    return nullptr;
+    return None;
 
   // Cache subframework.
   if (!CacheLookup.second.Directory) {
@@ -1045,14 +1052,14 @@ LookupSubframeworkHeader(StringRef Filename,
 
     // If the framework dir doesn't exist, we fail.
     auto Dir = FileMgr.getDirectory(FrameworkName);
-    if (!Dir) return nullptr;
+    if (!Dir)
+      return None;
 
     // Otherwise, if it does, remember that this is the right direntry for this
     // framework.
     CacheLookup.second.Directory = *Dir;
   }
 
-  const FileEntry *FE = nullptr;
 
   if (RelativePath) {
     RelativePath->clear();
@@ -1069,10 +1076,10 @@ LookupSubframeworkHeader(StringRef Filename,
   }
 
   HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
-  if (auto File = FileMgr.getFile(HeadersFilename, /*OpenFile=*/true))
-    FE = *File;
+  llvm::ErrorOr<FileEntryRef> File =
+      FileMgr.getFileRef(HeadersFilename, /*OpenFile=*/true);
 
-  if (!FE) {
+  if (!File) {
     // Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
     HeadersFilename = FrameworkName;
     HeadersFilename += "PrivateHeaders/";
@@ -1083,11 +1090,10 @@ LookupSubframeworkHeader(StringRef Filename,
     }
 
     HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
-    if (auto File = FileMgr.getFile(HeadersFilename, /*OpenFile=*/true))
-      FE = *File;
-  
-    if (!FE)
-      return nullptr;
+    File = FileMgr.getFileRef(HeadersFilename, /*OpenFile=*/true);
+
+    if (!File)
+      return None;
   }
 
   // This file is a system header or C++ unfriendly if the old file is.
@@ -1096,14 +1102,15 @@ LookupSubframeworkHeader(StringRef Filename,
   // getFileInfo could resize the vector and we don't want to rely on order
   // of evaluation.
   unsigned DirInfo = getFileInfo(ContextFileEnt).DirInfo;
-  getFileInfo(FE).DirInfo = DirInfo;
+  getFileInfo(&File->getFileEntry()).DirInfo = DirInfo;
 
   FrameworkName.pop_back(); // remove the trailing '/'
-  if (!findUsableModuleForFrameworkHeader(FE, FrameworkName, RequestingModule,
-                                          SuggestedModule, /*IsSystem*/ false))
-    return nullptr;
+  if (!findUsableModuleForFrameworkHeader(&File->getFileEntry(), FrameworkName,
+                                          RequestingModule, SuggestedModule,
+                                          /*IsSystem*/ false))
+    return None;
 
-  return FE;
+  return *File;
 }
 
 //===----------------------------------------------------------------------===//
index 876090136d5842feb3a71aba9e16905bd207075b..2642807b7316b40713e94e822cc599852addc05b 100644 (file)
@@ -679,7 +679,7 @@ Preprocessor::getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
   return nullptr;
 }
 
-const FileEntry *Preprocessor::LookupFile(
+Optional<FileEntryRef> Preprocessor::LookupFile(
     SourceLocation FilenameLoc, StringRef Filename, bool isAngled,
     const DirectoryLookup *FromDir, const FileEntry *FromFile,
     const DirectoryLookup *&CurDir, SmallVectorImpl<char> *SearchPath,
@@ -740,7 +740,7 @@ const FileEntry *Preprocessor::LookupFile(
     // the include path until we find that file or run out of files.
     const DirectoryLookup *TmpCurDir = CurDir;
     const DirectoryLookup *TmpFromDir = nullptr;
-    while (const FileEntry *FE = HeaderInfo.LookupFile(
+    while (Optional<FileEntryRef> FE = HeaderInfo.LookupFile(
                Filename, FilenameLoc, isAngled, TmpFromDir, TmpCurDir,
                Includers, SearchPath, RelativePath, RequestingModule,
                SuggestedModule, /*IsMapped=*/nullptr,
@@ -748,7 +748,7 @@ const FileEntry *Preprocessor::LookupFile(
       // Keep looking as if this file did a #include_next.
       TmpFromDir = TmpCurDir;
       ++TmpFromDir;
-      if (FE == FromFile) {
+      if (&FE->getFileEntry() == FromFile) {
         // Found it.
         FromDir = TmpFromDir;
         CurDir = TmpCurDir;
@@ -758,7 +758,7 @@ const FileEntry *Preprocessor::LookupFile(
   }
 
   // Do a standard file entry lookup.
-  const FileEntry *FE = HeaderInfo.LookupFile(
+  Optional<FileEntryRef> FE = HeaderInfo.LookupFile(
       Filename, FilenameLoc, isAngled, FromDir, CurDir, Includers, SearchPath,
       RelativePath, RequestingModule, SuggestedModule, IsMapped,
       IsFrameworkFound, SkipCache, BuildSystemModule);
@@ -766,7 +766,7 @@ const FileEntry *Preprocessor::LookupFile(
     if (SuggestedModule && !LangOpts.AsmPreprocessor)
       HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
           RequestingModule, RequestingModuleIsModuleInterface, FilenameLoc,
-          Filename, FE);
+          Filename, &FE->getFileEntry());
     return FE;
   }
 
@@ -776,14 +776,13 @@ const FileEntry *Preprocessor::LookupFile(
   // headers on the #include stack and pass them to HeaderInfo.
   if (IsFileLexer()) {
     if ((CurFileEnt = CurPPLexer->getFileEntry())) {
-      if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt,
-                                                    SearchPath, RelativePath,
-                                                    RequestingModule,
-                                                    SuggestedModule))) {
+      if (Optional<FileEntryRef> FE = HeaderInfo.LookupSubframeworkHeader(
+              Filename, CurFileEnt, SearchPath, RelativePath, RequestingModule,
+              SuggestedModule)) {
         if (SuggestedModule && !LangOpts.AsmPreprocessor)
           HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
               RequestingModule, RequestingModuleIsModuleInterface, FilenameLoc,
-              Filename, FE);
+              Filename, &FE->getFileEntry());
         return FE;
       }
     }
@@ -792,13 +791,13 @@ const FileEntry *Preprocessor::LookupFile(
   for (IncludeStackInfo &ISEntry : llvm::reverse(IncludeMacroStack)) {
     if (IsFileLexer(ISEntry)) {
       if ((CurFileEnt = ISEntry.ThePPLexer->getFileEntry())) {
-        if ((FE = HeaderInfo.LookupSubframeworkHeader(
+        if (Optional<FileEntryRef> FE = HeaderInfo.LookupSubframeworkHeader(
                 Filename, CurFileEnt, SearchPath, RelativePath,
-                RequestingModule, SuggestedModule))) {
+                RequestingModule, SuggestedModule)) {
           if (SuggestedModule && !LangOpts.AsmPreprocessor)
             HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
                 RequestingModule, RequestingModuleIsModuleInterface,
-                FilenameLoc, Filename, FE);
+                FilenameLoc, Filename, &FE->getFileEntry());
           return FE;
         }
       }
@@ -806,7 +805,7 @@ const FileEntry *Preprocessor::LookupFile(
   }
 
   // Otherwise, we really couldn't find the file.
-  return nullptr;
+  return None;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1676,6 +1675,130 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
   }
 }
 
+Optional<FileEntryRef> Preprocessor::LookupHeaderIncludeOrImport(
+    const DirectoryLookup *&CurDir, StringRef Filename,
+    SourceLocation FilenameLoc, CharSourceRange FilenameRange,
+    const Token &FilenameTok, bool &IsFrameworkFound, bool IsImportDecl,
+    bool &IsMapped, const DirectoryLookup *LookupFrom,
+    const FileEntry *LookupFromFile, SmallString<128> &NormalizedPath,
+    SmallVectorImpl<char> &RelativePath, SmallVectorImpl<char> &SearchPath,
+    ModuleMap::KnownHeader &SuggestedModule, bool isAngled) {
+  Optional<FileEntryRef> File = LookupFile(
+      FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename,
+      isAngled, LookupFrom, LookupFromFile, CurDir,
+      Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr,
+      &SuggestedModule, &IsMapped, &IsFrameworkFound);
+  if (File)
+    return File;
+
+  if (Callbacks) {
+    // Give the clients a chance to recover.
+    SmallString<128> RecoveryPath;
+    if (Callbacks->FileNotFound(Filename, RecoveryPath)) {
+      if (auto DE = FileMgr.getDirectory(RecoveryPath)) {
+        // Add the recovery path to the list of search paths.
+        DirectoryLookup DL(*DE, SrcMgr::C_User, false);
+        HeaderInfo.AddSearchPath(DL, isAngled);
+
+        // Try the lookup again, skipping the cache.
+        Optional<FileEntryRef> File = LookupFile(
+            FilenameLoc,
+            LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled,
+            LookupFrom, LookupFromFile, CurDir, nullptr, nullptr,
+            &SuggestedModule, &IsMapped, /*IsFrameworkFound=*/nullptr,
+            /*SkipCache*/ true);
+        if (File)
+          return File;
+      }
+    }
+  }
+
+  if (SuppressIncludeNotFoundError)
+    return None;
+
+  // If the file could not be located and it was included via angle
+  // brackets, we can attempt a lookup as though it were a quoted path to
+  // provide the user with a possible fixit.
+  if (isAngled) {
+    Optional<FileEntryRef> File = LookupFile(
+        FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename,
+        false, LookupFrom, LookupFromFile, CurDir,
+        Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr,
+        &SuggestedModule, &IsMapped,
+        /*IsFrameworkFound=*/nullptr);
+    if (File) {
+      Diag(FilenameTok, diag::err_pp_file_not_found_angled_include_not_fatal)
+          << Filename << IsImportDecl
+          << FixItHint::CreateReplacement(FilenameRange,
+                                          "\"" + Filename.str() + "\"");
+      return File;
+    }
+  }
+
+  // Check for likely typos due to leading or trailing non-isAlphanumeric
+  // characters
+  StringRef OriginalFilename = Filename;
+  if (LangOpts.SpellChecking) {
+    // A heuristic to correct a typo file name by removing leading and
+    // trailing non-isAlphanumeric characters.
+    auto CorrectTypoFilename = [](llvm::StringRef Filename) {
+      Filename = Filename.drop_until(isAlphanumeric);
+      while (!Filename.empty() && !isAlphanumeric(Filename.back())) {
+        Filename = Filename.drop_back();
+      }
+      return Filename;
+    };
+    StringRef TypoCorrectionName = CorrectTypoFilename(Filename);
+    SmallString<128> NormalizedTypoCorrectionPath;
+    if (LangOpts.MSVCCompat) {
+      NormalizedTypoCorrectionPath = TypoCorrectionName.str();
+#ifndef _WIN32
+      llvm::sys::path::native(NormalizedTypoCorrectionPath);
+#endif
+    }
+    Optional<FileEntryRef> File = LookupFile(
+        FilenameLoc,
+        LangOpts.MSVCCompat ? NormalizedTypoCorrectionPath.c_str()
+                            : TypoCorrectionName,
+        isAngled, LookupFrom, LookupFromFile, CurDir,
+        Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr,
+        &SuggestedModule, &IsMapped,
+        /*IsFrameworkFound=*/nullptr);
+    if (File) {
+      auto Hint =
+          isAngled ? FixItHint::CreateReplacement(
+                         FilenameRange, "<" + TypoCorrectionName.str() + ">")
+                   : FixItHint::CreateReplacement(
+                         FilenameRange, "\"" + TypoCorrectionName.str() + "\"");
+      Diag(FilenameTok, diag::err_pp_file_not_found_typo_not_fatal)
+          << OriginalFilename << TypoCorrectionName << Hint;
+      // We found the file, so set the Filename to the name after typo
+      // correction.
+      Filename = TypoCorrectionName;
+      return File;
+    }
+  }
+
+  // If the file is still not found, just go with the vanilla diagnostic
+  assert(!File.hasValue() && "expected missing file");
+  Diag(FilenameTok, diag::err_pp_file_not_found)
+      << OriginalFilename << FilenameRange;
+  if (IsFrameworkFound) {
+    size_t SlashPos = OriginalFilename.find('/');
+    assert(SlashPos != StringRef::npos &&
+           "Include with framework name should have '/' in the filename");
+    StringRef FrameworkName = OriginalFilename.substr(0, SlashPos);
+    FrameworkCacheEntry &CacheEntry =
+        HeaderInfo.LookupFrameworkCache(FrameworkName);
+    assert(CacheEntry.Directory && "Found framework should be in cache");
+    Diag(FilenameTok, diag::note_pp_framework_without_header)
+        << OriginalFilename.substr(SlashPos + 1) << FrameworkName
+        << CacheEntry.Directory->getName();
+  }
+
+  return None;
+}
+
 /// Handle either a #include-like directive or an import declaration that names
 /// a header file.
 ///
@@ -1754,120 +1877,14 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
     llvm::sys::path::native(NormalizedPath);
 #endif
   }
-  const FileEntry *File = LookupFile(
-      FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename,
-      isAngled, LookupFrom, LookupFromFile, CurDir,
-      Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr,
-      &SuggestedModule, &IsMapped, &IsFrameworkFound);
-
-  if (!File) {
-    if (Callbacks) {
-      // Give the clients a chance to recover.
-      SmallString<128> RecoveryPath;
-      if (Callbacks->FileNotFound(Filename, RecoveryPath)) {
-        if (auto DE = FileMgr.getDirectory(RecoveryPath)) {
-          // Add the recovery path to the list of search paths.
-          DirectoryLookup DL(*DE, SrcMgr::C_User, false);
-          HeaderInfo.AddSearchPath(DL, isAngled);
-
-          // Try the lookup again, skipping the cache.
-          File = LookupFile(
-              FilenameLoc,
-              LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled,
-              LookupFrom, LookupFromFile, CurDir, nullptr, nullptr,
-              &SuggestedModule, &IsMapped, /*IsFrameworkFound=*/nullptr,
-              /*SkipCache*/ true);
-        }
-      }
-    }
-
-    if (!SuppressIncludeNotFoundError) {
-      // If the file could not be located and it was included via angle
-      // brackets, we can attempt a lookup as though it were a quoted path to
-      // provide the user with a possible fixit.
-      if (isAngled) {
-        File = LookupFile(
-            FilenameLoc,
-            LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, false,
-            LookupFrom, LookupFromFile, CurDir,
-            Callbacks ? &SearchPath : nullptr,
-            Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped,
-            /*IsFrameworkFound=*/nullptr);
-        if (File) {
-          Diag(FilenameTok,
-               diag::err_pp_file_not_found_angled_include_not_fatal)
-              << Filename << IsImportDecl
-              << FixItHint::CreateReplacement(FilenameRange,
-                                              "\"" + Filename.str() + "\"");
-        }
-      }
 
-      // Check for likely typos due to leading or trailing non-isAlphanumeric
-      // characters
-      StringRef OriginalFilename = Filename;
-      if (LangOpts.SpellChecking && !File) {
-        // A heuristic to correct a typo file name by removing leading and
-        // trailing non-isAlphanumeric characters.
-        auto CorrectTypoFilename = [](llvm::StringRef Filename) {
-          Filename = Filename.drop_until(isAlphanumeric);
-          while (!Filename.empty() && !isAlphanumeric(Filename.back())) {
-            Filename = Filename.drop_back();
-          }
-          return Filename;
-        };
-        StringRef TypoCorrectionName = CorrectTypoFilename(Filename);
-        SmallString<128> NormalizedTypoCorrectionPath;
-        if (LangOpts.MSVCCompat) {
-          NormalizedTypoCorrectionPath = TypoCorrectionName.str();
-#ifndef _WIN32
-          llvm::sys::path::native(NormalizedTypoCorrectionPath);
-#endif
-        }
-        File = LookupFile(
-            FilenameLoc,
-            LangOpts.MSVCCompat ? NormalizedTypoCorrectionPath.c_str()
-                                : TypoCorrectionName,
-            isAngled, LookupFrom, LookupFromFile, CurDir,
-            Callbacks ? &SearchPath : nullptr,
-            Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped,
-            /*IsFrameworkFound=*/nullptr);
-        if (File) {
-          auto Hint =
-              isAngled
-                  ? FixItHint::CreateReplacement(
-                        FilenameRange, "<" + TypoCorrectionName.str() + ">")
-                  : FixItHint::CreateReplacement(
-                        FilenameRange, "\"" + TypoCorrectionName.str() + "\"");
-          Diag(FilenameTok, diag::err_pp_file_not_found_typo_not_fatal)
-              << OriginalFilename << TypoCorrectionName << Hint;
-          // We found the file, so set the Filename to the name after typo
-          // correction.
-          Filename = TypoCorrectionName;
-        }
-      }
-
-      // If the file is still not found, just go with the vanilla diagnostic
-      if (!File) {
-        Diag(FilenameTok, diag::err_pp_file_not_found) << OriginalFilename
-                                                       << FilenameRange;
-        if (IsFrameworkFound) {
-          size_t SlashPos = OriginalFilename.find('/');
-          assert(SlashPos != StringRef::npos &&
-                 "Include with framework name should have '/' in the filename");
-          StringRef FrameworkName = OriginalFilename.substr(0, SlashPos);
-          FrameworkCacheEntry &CacheEntry =
-              HeaderInfo.LookupFrameworkCache(FrameworkName);
-          assert(CacheEntry.Directory && "Found framework should be in cache");
-          Diag(FilenameTok, diag::note_pp_framework_without_header)
-              << OriginalFilename.substr(SlashPos + 1) << FrameworkName
-              << CacheEntry.Directory->getName();
-        }
-      }
-    }
-  }
+  Optional<FileEntryRef> File = LookupHeaderIncludeOrImport(
+      CurDir, Filename, FilenameLoc, FilenameRange, FilenameTok,
+      IsFrameworkFound, IsImportDecl, IsMapped, LookupFrom, LookupFromFile,
+      NormalizedPath, RelativePath, SearchPath, SuggestedModule, isAngled);
 
   if (usingPCHWithThroughHeader() && SkippingUntilPCHThroughHeader) {
-    if (isPCHThroughHeader(File))
+    if (File && isPCHThroughHeader(&File->getFileEntry()))
       SkippingUntilPCHThroughHeader = false;
     return {ImportAction::None};
   }
@@ -1878,7 +1895,8 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
   // some directives (e.g. #endif of a header guard) will never be seen.
   // Since this will lead to confusing errors, avoid the inclusion.
   if (File && PreambleConditionalStack.isRecording() &&
-      SourceMgr.translateFile(File) == SourceMgr.getMainFileID()) {
+      SourceMgr.translateFile(&File->getFileEntry()) ==
+          SourceMgr.getMainFileID()) {
     Diag(FilenameTok.getLocation(),
          diag::err_pp_including_mainfile_in_preamble);
     return {ImportAction::None};
@@ -1897,7 +1915,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
   // include cycle. Don't enter already processed files again as it can lead to
   // reaching the max allowed include depth again.
   if (Action == Enter && HasReachedMaxIncludeDepth && File &&
-      HeaderInfo.getFileInfo(File).NumIncludes)
+      HeaderInfo.getFileInfo(&File->getFileEntry()).NumIncludes)
     Action = IncludeLimitReached;
 
   // Determine whether we should try to import the module for this #include, if
@@ -1973,7 +1991,8 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
   SrcMgr::CharacteristicKind FileCharacter =
       SourceMgr.getFileCharacteristic(FilenameTok.getLocation());
   if (File)
-    FileCharacter = std::max(HeaderInfo.getFileDirFlavor(File), FileCharacter);
+    FileCharacter = std::max(HeaderInfo.getFileDirFlavor(&File->getFileEntry()),
+                             FileCharacter);
 
   // If this is a '#import' or an import-declaration, don't re-enter the file.
   //
@@ -1987,8 +2006,8 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
   // Ask HeaderInfo if we should enter this #include file.  If not, #including
   // this file will have no effect.
   if (Action == Enter && File &&
-      !HeaderInfo.ShouldEnterIncludeFile(*this, File, EnterOnce,
-                                         getLangOpts().Modules,
+      !HeaderInfo.ShouldEnterIncludeFile(*this, &File->getFileEntry(),
+                                         EnterOnce, getLangOpts().Modules,
                                          SuggestedModule.getModule())) {
     // Even if we've already preprocessed this header once and know that we
     // don't need to see its contents again, we still need to import it if it's
@@ -2006,11 +2025,11 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
     Callbacks->InclusionDirective(
         HashLoc, IncludeTok,
         LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled,
-        FilenameRange, File, SearchPath, RelativePath,
-        Action == Import ? SuggestedModule.getModule() : nullptr,
+        FilenameRange, File ? &File->getFileEntry() : nullptr, SearchPath,
+        RelativePath, Action == Import ? SuggestedModule.getModule() : nullptr,
         FileCharacter);
-    if (Action == Skip)
-      Callbacks->FileSkipped(*File, FilenameTok, FileCharacter);
+    if (Action == Skip && File)
+      Callbacks->FileSkipped(File->getFileEntry(), FilenameTok, FileCharacter);
   }
 
   if (!File)
@@ -2027,11 +2046,11 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
   // Issue a diagnostic if the name of the file on disk has a different case
   // than the one we're about to open.
   const bool CheckIncludePathPortability =
-      !IsMapped && File && !File->tryGetRealPathName().empty();
+      !IsMapped && !File->getFileEntry().tryGetRealPathName().empty();
 
   if (CheckIncludePathPortability) {
     StringRef Name = LangOpts.MSVCCompat ? NormalizedPath.str() : Filename;
-    StringRef RealPathName = File->tryGetRealPathName();
+    StringRef RealPathName = File->getFileEntry().tryGetRealPathName();
     SmallVector<StringRef, 16> Components(llvm::sys::path::begin(Name),
                                           llvm::sys::path::end(Name));
 
@@ -2102,7 +2121,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
   // position on the file where it will be included and after the expansions.
   if (IncludePos.isMacroID())
     IncludePos = SourceMgr.getExpansionRange(IncludePos).getEnd();
-  FileID FID = SourceMgr.createFileID(File, IncludePos, FileCharacter);
+  FileID FID = SourceMgr.createFileID(*File, IncludePos, FileCharacter);
   assert(FID.isValid() && "Expected valid file ID");
 
   // If all is good, enter the new file!
index 41fa2b0133c0fc564a499dffa61b25c5c8626c79..3f5ee08b7430fcd93e9ca3c50eddef45cc7af34a 100644 (file)
@@ -1210,19 +1210,21 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
 
   // Search include directories.
   const DirectoryLookup *CurDir;
-  const FileEntry *File =
+  Optional<FileEntryRef> File =
       PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, LookupFromFile,
                     CurDir, nullptr, nullptr, nullptr, nullptr, nullptr);
 
   if (PPCallbacks *Callbacks = PP.getPPCallbacks()) {
     SrcMgr::CharacteristicKind FileType = SrcMgr::C_User;
     if (File)
-      FileType = PP.getHeaderSearchInfo().getFileDirFlavor(File);
-    Callbacks->HasInclude(FilenameLoc, Filename, isAngled, File, FileType);
+      FileType =
+          PP.getHeaderSearchInfo().getFileDirFlavor(&File->getFileEntry());
+    Callbacks->HasInclude(FilenameLoc, Filename, isAngled,
+                          File ? &File->getFileEntry() : nullptr, FileType);
   }
 
   // Get the result value.  A result of true means the file exists.
-  return File != nullptr;
+  return File.hasValue();
 }
 
 /// EvaluateHasInclude - Process a '__has_include("path")' expression.
index 8317e99a4f6d7d881dbbd3a4326abd412b0b5435..64352334fcf7850f96c1b823d32d9c1a940fa139 100644 (file)
@@ -498,7 +498,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
 
   // Search include directories for this file.
   const DirectoryLookup *CurDir;
-  const FileEntry *File =
+  Optional<FileEntryRef> File =
       LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr,
                  nullptr, CurDir, nullptr, nullptr, nullptr, nullptr, nullptr);
   if (!File) {
index 6579319cb3ffc2b22fb7fe98c3e157a959691e63..3abd0c76d0f53d50a44bfcbec0e6a40bc5cd900d 100644 (file)
@@ -563,7 +563,7 @@ void Preprocessor::EnterMainSourceFile() {
     // Lookup and save the FileID for the through header. If it isn't found
     // in the search path, it's a fatal error.
     const DirectoryLookup *CurDir;
-    const FileEntry *File = LookupFile(
+    Optional<FileEntryRef> File = LookupFile(
         SourceLocation(), PPOpts->PCHThroughHeader,
         /*isAngled=*/false, /*FromDir=*/nullptr, /*FromFile=*/nullptr, CurDir,
         /*SearchPath=*/nullptr, /*RelativePath=*/nullptr,
@@ -575,7 +575,7 @@ void Preprocessor::EnterMainSourceFile() {
       return;
     }
     setPCHThroughHeaderFileID(
-        SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User));
+        SourceMgr.createFileID(*File, SourceLocation(), SrcMgr::C_User));
   }
 
   // Skip tokens from the Predefines and if needed the main file.
index d5ef7db5309d2c1fbd4cf67ea4900324899976b7..6a18af8a082236e8244b24f80b97cf44244f25ea 100644 (file)
@@ -1514,6 +1514,7 @@ bool ASTReader::ReadSLocEntry(int ID) {
     }
     SrcMgr::CharacteristicKind
       FileCharacter = (SrcMgr::CharacteristicKind)Record[2];
+    // FIXME: The FileID should be created from the FileEntryRef.
     FileID FID = SourceMgr.createFileID(File, IncludeLoc, FileCharacter,
                                         ID, BaseOffset + Record[0]);
     SrcMgr::FileInfo &FileInfo =
index 019042a1308a7324401e94636960ccb24e1e3158..b7066dc334753caebfcae31f6f373a4b30bcd1d7 100644 (file)
@@ -1842,6 +1842,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
         Entry.IsTransient,
         Entry.IsTopLevelModuleMap};
 
+    // FIXME: The path should be taken from the FileEntryRef.
     EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName());
   }
 
index 598071b78248b37a53ba7f92faf2ce9623a05035..0174048db5591efb9003960042e5ea661415fc42 100644 (file)
@@ -3,6 +3,9 @@
 // REQUIRES: shell
 
 #include "external-names.h"
+#ifdef REINCLUDE
+#include "external-names.h"
+#endif
 
 ////
 // Preprocessor (__FILE__ macro and # directives):
 
 // RUN: %clang_cc1 -I %t -ivfsoverlay %t.yaml -triple %itanium_abi_triple -debug-info-kind=limited -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-DEBUG %s
 // CHECK-DEBUG-NOT: Inputs
+
+////
+// Dependency file
+
+// RUN: %clang_cc1 -D REINCLUDE -I %t -ivfsoverlay %t.external.yaml -Eonly %s -MTfoo -dependency-file %t.external.dep
+// RUN: echo "EOF" >> %t.external.dep
+// RUN: cat %t.external.dep | FileCheck --check-prefix=CHECK-DEP-EXTERNAL %s
+// CHECK-DEP-EXTERNAL: Inputs{{.}}external-names.h
+// CHECK-DEP-EXTERNAL-NEXT: EOF
+
+// RUN: %clang_cc1 -D REINCLUDE -I %t -ivfsoverlay %t.yaml -Eonly %s -MTfoo -dependency-file %t.dep
+// RUN: cat %t.dep | FileCheck --check-prefix=CHECK-DEP %s
+// CHECK-DEP-NOT: Inputs
index c699d41c2846e82cc8f881bc71b169a0f1f5081f..3a4094a8b4051693ca4fc159675741c30c9efca8 100644 (file)
@@ -15,6 +15,7 @@ add_clang_unittest(ToolingTests
   CastExprTest.cpp
   CommentHandlerTest.cpp
   CompilationDatabaseTest.cpp
+  DependencyScannerTest.cpp
   DiagnosticsYamlTest.cpp
   ExecutionTest.cpp
   FixItTest.cpp
diff --git a/unittests/Tooling/DependencyScannerTest.cpp b/unittests/Tooling/DependencyScannerTest.cpp
new file mode 100644 (file)
index 0000000..fa60d0a
--- /dev/null
@@ -0,0 +1,118 @@
+//===- unittest/Tooling/ToolingTest.cpp - Tooling unit tests --------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "gtest/gtest.h"
+#include <algorithm>
+#include <string>
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+/// Prints out all of the gathered dependencies into a string.
+class TestFileCollector : public DependencyFileGenerator {
+public:
+  TestFileCollector(DependencyOutputOptions &Opts,
+                    std::vector<std::string> &Deps)
+      : DependencyFileGenerator(Opts), Deps(Deps) {}
+
+  void finishedMainFile(DiagnosticsEngine &Diags) override {
+    Deps = getDependencies();
+  }
+
+private:
+  std::vector<std::string> &Deps;
+};
+
+class TestDependencyScanningAction : public tooling::ToolAction {
+public:
+  TestDependencyScanningAction(std::vector<std::string> &Deps) : Deps(Deps) {}
+
+  bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
+                     FileManager *FileMgr,
+                     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+                     DiagnosticConsumer *DiagConsumer) override {
+    CompilerInstance Compiler(std::move(PCHContainerOps));
+    Compiler.setInvocation(std::move(Invocation));
+    Compiler.setFileManager(FileMgr);
+
+    Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
+    if (!Compiler.hasDiagnostics())
+      return false;
+
+    Compiler.createSourceManager(*FileMgr);
+    Compiler.addDependencyCollector(std::make_shared<TestFileCollector>(
+        Compiler.getInvocation().getDependencyOutputOpts(), Deps));
+
+    auto Action = std::make_unique<PreprocessOnlyAction>();
+    return Compiler.ExecuteAction(*Action);
+  }
+
+private:
+  std::vector<std::string> &Deps;
+};
+
+} // namespace
+
+TEST(DependencyScanner, ScanDepsReuseFilemanager) {
+  std::vector<std::string> Compilation = {"-c", "-E", "-MT", "test.cpp.o"};
+  StringRef CWD = "/root";
+  FixedCompilationDatabase CDB(CWD, Compilation);
+
+  auto VFS = new llvm::vfs::InMemoryFileSystem();
+  VFS->setCurrentWorkingDirectory(CWD);
+  VFS->addFile("/root/header.h", 0, llvm::MemoryBuffer::getMemBuffer("\n"));
+  VFS->addHardLink("/root/symlink.h", "/root/header.h");
+  VFS->addFile("/root/test.cpp", 0,
+               llvm::MemoryBuffer::getMemBuffer(
+                   "#include \"symlink.h\"\n#include \"header.h\"\n"));
+
+  ClangTool Tool(CDB, {"test.cpp"}, std::make_shared<PCHContainerOperations>(),
+                 VFS);
+  Tool.clearArgumentsAdjusters();
+  std::vector<std::string> Deps;
+  TestDependencyScanningAction Action(Deps);
+  Tool.run(&Action);
+  // The first invocation should return dependencies in order of access.
+  ASSERT_EQ(Deps.size(), 3u);
+  EXPECT_EQ(Deps[0], "/root/test.cpp");
+  EXPECT_EQ(Deps[1], "/root/symlink.h");
+  EXPECT_EQ(Deps[2], "/root/header.h");
+
+  // The file manager should still have two FileEntries, as one file is a
+  // hardlink.
+  FileManager &Files = Tool.getFiles();
+  EXPECT_EQ(Files.getNumUniqueRealFiles(), 2u);
+
+  Deps.clear();
+  Tool.run(&Action);
+  // The second invocation should have the same order of dependencies.
+  ASSERT_EQ(Deps.size(), 3u);
+  EXPECT_EQ(Deps[0], "/root/test.cpp");
+  EXPECT_EQ(Deps[1], "/root/symlink.h");
+  EXPECT_EQ(Deps[2], "/root/header.h");
+
+  EXPECT_EQ(Files.getNumUniqueRealFiles(), 2u);
+}
+
+} // end namespace tooling
+} // end namespace clang