dexonsmith created this revision.
dexonsmith added a reviewer: arphaman.
Herald added subscribers: usaxena95, ributzka, kadircet.
dexonsmith requested review of this revision.

This is a WIP patch to shrink FileEntryRef to the size of a pointer,
posting for early feedback in case someone has some. This pulled in more
changes than I expected, and I'll try to find some things to split off
and commit incrementally, but I think this concept is sound
(`BasicTests` passes, still have to build and test the rest of clang).


https://reviews.llvm.org/D89488

Files:
  clang-tools-extra/clangd/ParsedAST.cpp
  clang/include/clang/Basic/FileManager.h
  clang/include/clang/Basic/SourceManager.h
  clang/lib/Basic/FileManager.cpp
  clang/lib/Basic/SourceManager.cpp
  clang/lib/Frontend/DependencyFile.cpp
  clang/lib/Lex/HeaderSearch.cpp
  clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
  clang/unittests/Basic/FileManagerTest.cpp
  clang/unittests/Basic/SourceManagerTest.cpp

Index: clang/unittests/Basic/SourceManagerTest.cpp
===================================================================
--- clang/unittests/Basic/SourceManagerTest.cpp
+++ clang/unittests/Basic/SourceManagerTest.cpp
@@ -496,23 +496,26 @@
 
   std::unique_ptr<llvm::MemoryBuffer> Buf =
       llvm::MemoryBuffer::getMemBuffer(Source);
-  const FileEntry *SourceFile =
-      FileMgr.getVirtualFile("mainFile.cpp", Buf->getBufferSize(), 0);
-  SourceMgr.overrideFileContents(SourceFile, std::move(Buf));
+  auto SourceFile =
+      FileMgr.getVirtualFileRef("mainFile.cpp", Buf->getBufferSize(), 0);
+  SourceMgr.overrideFileContents(&SourceFile.getFileEntry(), std::move(Buf));
 
   std::unique_ptr<llvm::MemoryBuffer> Buf2 =
       llvm::MemoryBuffer::getMemBuffer(Source);
-  const FileEntry *SecondFile =
-      FileMgr.getVirtualFile("file2.cpp", Buf2->getBufferSize(), 0);
-  SourceMgr.overrideFileContents(SecondFile, std::move(Buf2));
+  auto SecondFile =
+      FileMgr.getVirtualFileRef("file2.cpp", Buf2->getBufferSize(), 0);
+  SourceMgr.overrideFileContents(&SecondFile.getFileEntry(), std::move(Buf2));
 
-  FileID MainFileID = SourceMgr.getOrCreateFileID(SourceFile, SrcMgr::C_User);
+  FileID MainFileID =
+      SourceMgr.getOrCreateFileID(&SourceFile.getFileEntry(), SrcMgr::C_User);
   SourceMgr.setMainFileID(MainFileID);
 
-  EXPECT_TRUE(SourceMgr.isMainFile(FileEntryRef("mainFile.cpp", *SourceFile)));
-  EXPECT_TRUE(
-      SourceMgr.isMainFile(FileEntryRef("anotherName.cpp", *SourceFile)));
-  EXPECT_FALSE(SourceMgr.isMainFile(FileEntryRef("mainFile.cpp", *SecondFile)));
+  auto MainAlias =
+      FileMgr.addAliasForFile("anotherName.cpp", SourceFile.getFileEntry());
+
+  EXPECT_TRUE(SourceMgr.isMainFile(SourceFile));
+  EXPECT_TRUE(SourceMgr.isMainFile(*MainAlias));
+  EXPECT_FALSE(SourceMgr.isMainFile(SecondFile));
 }
 
 #endif
Index: clang/unittests/Basic/FileManagerTest.cpp
===================================================================
--- clang/unittests/Basic/FileManagerTest.cpp
+++ clang/unittests/Basic/FileManagerTest.cpp
@@ -485,29 +485,34 @@
   // Set up a virtual file with a different size than FakeStatCache uses.
   const FileEntry *File = Manager.getVirtualFile("/tmp/test", /*Size=*/10, 0);
   ASSERT_TRUE(File);
-  FileEntryRef Ref("/tmp/test", *File);
-  EXPECT_TRUE(Ref.isValid());
-  EXPECT_EQ(Ref.getSize(), 10);
+  const FileEntry &FE = *File;
+  EXPECT_TRUE(FE.isValid());
+  EXPECT_EQ(FE.getSize(), 10);
 
   // Calling a second time should not affect the UID or size.
-  unsigned VirtualUID = Ref.getUID();
-  EXPECT_EQ(*expectedToOptional(Manager.getFileRef("/tmp/test")), Ref);
-  EXPECT_EQ(Ref.getUID(), VirtualUID);
-  EXPECT_EQ(Ref.getSize(), 10);
+  unsigned VirtualUID = FE.getUID();
+  EXPECT_EQ(
+      &FE,
+      &expectedToOptional(Manager.getFileRef("/tmp/test"))->getFileEntry());
+  EXPECT_EQ(FE.getUID(), VirtualUID);
+  EXPECT_EQ(FE.getSize(), 10);
 
   // Bypass the file.
-  llvm::Optional<FileEntryRef> BypassRef = Manager.getBypassFile(Ref);
+  llvm::Optional<FileEntryRef> BypassRef =
+      Manager.getBypassFile(File->getLastRef());
   ASSERT_TRUE(BypassRef);
   EXPECT_TRUE(BypassRef->isValid());
-  EXPECT_EQ(BypassRef->getName(), Ref.getName());
+  EXPECT_EQ("/tmp/test", BypassRef->getName());
 
   // Check that it's different in the right ways.
   EXPECT_NE(&BypassRef->getFileEntry(), File);
   EXPECT_NE(BypassRef->getUID(), VirtualUID);
-  EXPECT_NE(BypassRef->getSize(), Ref.getSize());
+  EXPECT_NE(BypassRef->getSize(), FE.getSize());
 
   // The virtual file should still be returned when searching.
-  EXPECT_EQ(*expectedToOptional(Manager.getFileRef("/tmp/test")), Ref);
+  EXPECT_EQ(
+      &FE,
+      &expectedToOptional(Manager.getFileRef("/tmp/test"))->getFileEntry());
 }
 
 } // anonymous namespace
Index: clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
===================================================================
--- clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -77,8 +77,7 @@
   // 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!
-  Optional<FileEntryRef> File =
-      SM.getFileEntryRefForID(SM.getFileID(SM.getExpansionLoc(Loc)));
+  auto File = SM.getFileInfoForID(SM.getFileID(SM.getExpansionLoc(Loc)));
   if (!File)
     return;
 
Index: clang/lib/Lex/HeaderSearch.cpp
===================================================================
--- clang/lib/Lex/HeaderSearch.cpp
+++ clang/lib/Lex/HeaderSearch.cpp
@@ -765,8 +765,7 @@
 
   // This is the header that MSVC's header search would have found.
   ModuleMap::KnownHeader MSSuggestedModule;
-  const FileEntry *MSFE_FE = nullptr;
-  StringRef MSFE_Name;
+  Optional<FileEntryRef> MSFE;
 
   // 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
@@ -841,8 +840,7 @@
         if (Diags.isIgnored(diag::ext_pp_include_search_ms, IncludeLoc)) {
           return FE;
         } else {
-          MSFE_FE = &FE->getFileEntry();
-          MSFE_Name = FE->getName();
+          MSFE = FE;
           if (SuggestedModule) {
             MSSuggestedModule = *SuggestedModule;
             *SuggestedModule = ModuleMap::KnownHeader();
@@ -854,9 +852,6 @@
     }
   }
 
-  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.
Index: clang/lib/Frontend/DependencyFile.cpp
===================================================================
--- clang/lib/Frontend/DependencyFile.cpp
+++ clang/lib/Frontend/DependencyFile.cpp
@@ -46,8 +46,7 @@
     // 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!
-    Optional<FileEntryRef> File =
-        SM.getFileEntryRefForID(SM.getFileID(SM.getExpansionLoc(Loc)));
+    auto File = SM.getFileInfoForID(SM.getFileID(SM.getExpansionLoc(Loc)));
     if (!File)
       return;
 
Index: clang/lib/Basic/SourceManager.cpp
===================================================================
--- clang/lib/Basic/SourceManager.cpp
+++ clang/lib/Basic/SourceManager.cpp
@@ -345,7 +345,7 @@
 
 bool SourceManager::isMainFile(FileEntryRef SourceFile) {
   assert(MainFileID.isValid() && "expected initialized SourceManager");
-  auto FE = getFileEntryRefForID(MainFileID);
+  auto FE = getFileEntryForID(MainFileID);
   if (!FE)
     return false;
   return FE->getUID() == SourceFile.getUID();
@@ -708,7 +708,7 @@
 SourceManager::bypassFileContentsOverride(const FileEntry &File) {
   assert(isFileOverridden(&File));
   llvm::Optional<FileEntryRef> BypassFile =
-      FileMgr.getBypassFile(FileEntryRef(File.getName(), File));
+      FileMgr.getBypassFile(File.getLastRef());
 
   // If the file can't be found in the FS, give up.
   if (!BypassFile)
@@ -724,18 +724,6 @@
   const_cast<SrcMgr::ContentCache *>(CC)->IsTransient = true;
 }
 
-Optional<FileEntryRef> SourceManager::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);
-}
-
 StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
   auto B = getBufferDataOrNone(FID);
   if (Invalid)
Index: clang/lib/Basic/FileManager.cpp
===================================================================
--- clang/lib/Basic/FileManager.cpp
+++ clang/lib/Basic/FileManager.cpp
@@ -212,11 +212,11 @@
           SeenFileInsertResult.first->second.getError());
     // Construct and return and FileEntryRef, unless it's a redirect to another
     // filename.
-    SeenFileEntryOrRedirect Value = *SeenFileInsertResult.first->second;
+    SeenFileTableValue 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);
+    if (LLVM_LIKELY(FE = Value.V.dyn_cast<FileEntry *>()))
+      return FileEntryRef(*SeenFileInsertResult.first);
+    return FileEntryRef(*Value.V.get<const SeenFileTableValue::MapEntryTy *>());
   }
 
   // We've not seen this before. Fill it in.
@@ -268,24 +268,24 @@
   // This occurs when one dir is symlinked to another, for example.
   FileEntry &UFE = UniqueRealFiles[Status.getUniqueID()];
 
-  NamedFileEnt->second = &UFE;
-
-  // If the name returned by getStatValue is different than Filename, re-intern
-  // the name.
-  if (Status.getName() != Filename) {
-    auto &NewNamedFileEnt =
-        *SeenFileEntries.insert({Status.getName(), &UFE}).first;
-    assert((*NewNamedFileEnt.second).get<FileEntry *>() == &UFE &&
+  if (Status.getName() == Filename) {
+    // The name matches. Set the FileEntry.
+    NamedFileEnt->second = SeenFileTableValue(UFE);
+  } else {
+    // Name mismatch. We need a redirect. First grab the actual entry we want
+    // to return.
+    auto &Redirection =
+        *SeenFileEntries.insert({Status.getName(), SeenFileTableValue(UFE)})
+             .first;
+    assert(Redirection.second->V.get<FileEntry *>() == &UFE &&
            "filename from getStatValue() refers to wrong file");
-    InterndFileName = NewNamedFileEnt.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);
-    auto SeenFileInsertResultIt = SeenFileEntries.find(Filename);
-    assert(SeenFileInsertResultIt != SeenFileEntries.end() &&
-           "unexpected SeenFileEntries cache miss");
-    SeenFileInsertResultIt->second = Redirect;
-    NamedFileEnt = &*SeenFileInsertResultIt;
+
+    // Cache the redirection in the previously-inserted entry, still available
+    // in the tentative return value.
+    NamedFileEnt->second = SeenFileTableValue(Redirection);
+
+    // Fix the tentative return value.
+    NamedFileEnt = &Redirection;
   }
 
   if (UFE.isValid()) { // Already have an entry with this inode, return it.
@@ -306,13 +306,10 @@
     // corresponding FileEntry.
     // FIXME: The Name should be removed from FileEntry once all clients
     // adopt FileEntryRef.
-    UFE.Name = InterndFileName;
-
-    return FileEntryRef(InterndFileName, UFE);
+    return *(UFE.LastRef = FileEntryRef(*NamedFileEnt));
   }
 
   // Otherwise, we don't have this file yet, add it.
-  UFE.Name    = InterndFileName;
   UFE.Size    = Status.getSize();
   UFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime());
   UFE.Dir     = DirInfo;
@@ -329,24 +326,28 @@
     // We should still fill the path even if we aren't opening the file.
     fillRealPathName(&UFE, InterndFileName);
   }
-  return FileEntryRef(InterndFileName, UFE);
+  return *(UFE.LastRef = FileEntryRef(*NamedFileEnt));
 }
 
 const FileEntry *
 FileManager::getVirtualFile(StringRef Filename, off_t Size,
                             time_t ModificationTime) {
+  return &getVirtualFileRef(Filename, Size, ModificationTime).getFileEntry();
+}
+
+FileEntryRef FileManager::getVirtualFileRef(StringRef Filename, off_t Size,
+                                            time_t ModificationTime) {
   ++NumFileLookups;
 
   // 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) {
-    SeenFileEntryOrRedirect Value = *NamedFileEnt.second;
+    SeenFileTableValue Value = *NamedFileEnt.second;
     FileEntry *FE;
-    if (LLVM_LIKELY(FE = Value.dyn_cast<FileEntry *>()))
-      return FE;
-    return getVirtualFile(*Value.get<const StringRef *>(), Size,
-                          ModificationTime);
+    if (LLVM_LIKELY(FE = Value.V.dyn_cast<FileEntry *>()))
+      return FileEntryRef(NamedFileEnt);
+    return FileEntryRef(*Value.V.get<const SeenFileTableValue::MapEntryTy *>());
   }
 
   // We've not seen this before, or the file is cached as non-existent.
@@ -372,7 +373,7 @@
       Status.getUser(), Status.getGroup(), Size,
       Status.getType(), Status.getPermissions());
 
-    NamedFileEnt.second = UFE;
+    NamedFileEnt.second = SeenFileTableValue(*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
@@ -381,8 +382,11 @@
       UFE->closeFile();
 
     // If we already have an entry with this inode, return it.
+    //
+    // FIXME: Surely this should add a reference by the new name, and return
+    // it instead...
     if (UFE->isValid())
-      return UFE;
+      return UFE->getLastRef();
 
     UFE->UniqueID = Status.getUniqueID();
     UFE->IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file;
@@ -390,17 +394,28 @@
   } else {
     VirtualFileEntries.push_back(std::make_unique<FileEntry>());
     UFE = VirtualFileEntries.back().get();
-    NamedFileEnt.second = UFE;
+    NamedFileEnt.second = SeenFileTableValue(*UFE);
   }
 
-  UFE->Name    = InterndFileName;
   UFE->Size    = Size;
   UFE->ModTime = ModificationTime;
   UFE->Dir     = *DirInfo;
   UFE->UID     = NextFileUID++;
   UFE->IsValid = true;
   UFE->File.reset();
-  return UFE;
+  return *(UFE->LastRef = FileEntryRef(NamedFileEnt));
+}
+
+Optional<FileEntryRef> FileManager::addAliasForFile(StringRef Filename,
+                                                    const FileEntry &FE) {
+  // See if there is already an entry in the map for an existing file.
+  auto Insertion = SeenFileEntries.insert(
+      {Filename, std::errc::no_such_file_or_directory});
+  if (!Insertion.second)
+    return None; // Failed to insert...
+
+  Insertion.first->second = SeenFileTableValue(const_cast<FileEntry &>(FE));
+  return FileEntryRef(*Insertion.first);
 }
 
 llvm::Optional<FileEntryRef> FileManager::getBypassFile(FileEntryRef VF) {
@@ -409,17 +424,30 @@
   if (getStatValue(VF.getName(), Status, /*isFile=*/true, /*F=*/nullptr))
     return None;
 
-  // Fill it in from the stat.
+  if (!SeenBypassFileEntries)
+    SeenBypassFileEntries =
+        std::make_unique<llvm::StringMap<llvm::ErrorOr<SeenFileTableValue>>>();
+
+  // If we've already bypassed just use the existing one.
+  auto Insertion = SeenBypassFileEntries->insert(
+      {VF.getName(), std::errc::no_such_file_or_directory});
+  if (!Insertion.second)
+    return FileEntryRef(*Insertion.first);
+
+  // Fill in the new entry from the stat.
   BypassFileEntries.push_back(std::make_unique<FileEntry>());
   const FileEntry &VFE = VF.getFileEntry();
   FileEntry &BFE = *BypassFileEntries.back();
-  BFE.Name = VFE.getName();
+  Insertion.first->second = SeenFileTableValue(BFE);
+  BFE.LastRef = FileEntryRef(*Insertion.first);
   BFE.Size = Status.getSize();
   BFE.Dir = VFE.Dir;
   BFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime());
   BFE.UID = NextFileUID++;
   BFE.IsValid = true;
-  return FileEntryRef(VF.getName(), BFE);
+
+  // Save the entry in the bypass table and return.
+  return FileEntryRef(*Insertion.first);
 }
 
 bool FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const {
@@ -534,13 +562,13 @@
   UIDToFiles.resize(NextFileUID);
 
   // Map file entries
-  for (llvm::StringMap<llvm::ErrorOr<SeenFileEntryOrRedirect>,
+  for (llvm::StringMap<llvm::ErrorOr<SeenFileTableValue>,
                        llvm::BumpPtrAllocator>::const_iterator
            FE = SeenFileEntries.begin(),
            FEEnd = SeenFileEntries.end();
        FE != FEEnd; ++FE)
-    if (llvm::ErrorOr<SeenFileEntryOrRedirect> Entry = FE->getValue()) {
-      if (const auto *FE = (*Entry).dyn_cast<FileEntry *>())
+    if (llvm::ErrorOr<SeenFileTableValue> Entry = FE->getValue()) {
+      if (const auto *FE = Entry->V.dyn_cast<FileEntry *>())
         UIDToFiles[FE->getUID()] = FE;
     }
 
Index: clang/include/clang/Basic/SourceManager.h
===================================================================
--- clang/include/clang/Basic/SourceManager.h
+++ clang/include/clang/Basic/SourceManager.h
@@ -992,14 +992,21 @@
     return getFakeBufferForRecovery()->getMemBufferRef();
   }
 
-  /// Returns the FileEntry record for the provided FileID.
-  const FileEntry *getFileEntryForID(FileID FID) const {
+  /// Returns the FileInfo record for the provided FileID.
+  const SrcMgr::FileInfo *getFileInfoForID(FileID FID) const {
     bool MyInvalid = false;
     const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
     if (MyInvalid || !Entry.isFile())
       return nullptr;
+    return &Entry.getFile();
+  }
+
+  const FileEntry *getFileEntryForID(FileID FID) const {
+    auto FI = getFileInfoForID(FID);
+    if (!FI)
+      return nullptr;
 
-    const SrcMgr::ContentCache *Content = Entry.getFile().getContentCache();
+    const SrcMgr::ContentCache *Content = FI->getContentCache();
     if (!Content)
       return nullptr;
     return Content->OrigEntry;
Index: clang/include/clang/Basic/FileManager.h
===================================================================
--- clang/include/clang/Basic/FileManager.h
+++ clang/include/clang/Basic/FileManager.h
@@ -71,6 +71,62 @@
   const llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>> *Entry;
 };
 
+class FileEntry;
+
+/// A reference to the file entry that is associated with a particular
+/// filename, or a reference to another FileEntryRef that should be used
+/// instead.
+///
+/// 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.
+struct SeenFileTableValue {
+  using MapEntryTy = llvm::StringMapEntry<llvm::ErrorOr<SeenFileTableValue>>;
+  llvm::PointerUnion<FileEntry *, const MapEntryTy *> V;
+
+  SeenFileTableValue() = delete;
+  SeenFileTableValue(FileEntry &FE) : V(&FE) {}
+  SeenFileTableValue(MapEntryTy &ME) : V(&ME) {}
+};
+
+/// 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:
+  const StringRef getName() const { return Entry->first(); }
+
+  const FileEntry &getFileEntry() const {
+    return *Entry->second->V.get<FileEntry *>();
+  }
+
+  inline bool isValid() const;
+  inline off_t getSize() const;
+  inline unsigned getUID() const;
+  inline const llvm::sys::fs::UniqueID &getUniqueID() const;
+  inline time_t getModificationTime() const;
+
+  friend bool operator==(const FileEntryRef &LHS, const FileEntryRef &RHS) {
+    return LHS.Entry == RHS.Entry;
+  }
+  friend bool operator!=(const FileEntryRef &LHS, const FileEntryRef &RHS) {
+    return !(LHS == RHS);
+  }
+
+private:
+  friend class FileManager;
+
+  FileEntryRef() = delete;
+  explicit FileEntryRef(const SeenFileTableValue::MapEntryTy &Entry)
+      : Entry(&Entry) {
+    assert(Entry.second && "Expected payload");
+    assert(Entry.second->V && "Expected non-null");
+    assert(Entry.second->V.is<FileEntry *>() && "Expected FileEntry");
+  }
+
+  const SeenFileTableValue::MapEntryTy *Entry;
+};
+
 /// Cached information about one file (either on disk
 /// or in the virtual file system).
 ///
@@ -79,7 +135,6 @@
 class FileEntry {
   friend class FileManager;
 
-  StringRef Name;             // Name of the file.
   std::string RealPathName;   // Real path to the file; could be empty.
   off_t Size;                 // File size in bytes.
   time_t ModTime;             // Modification time of file.
@@ -92,6 +147,14 @@
   /// The open file, if it is owned by the \p FileEntry.
   mutable std::unique_ptr<llvm::vfs::File> File;
 
+  // First access name for this FileEntry.
+  //
+  // This is Optional only to allow delayed construction (FileEntryRef has no
+  // default constructor). It should always have a value in practice.
+  //
+  // TODO: remote this once everyone that needs a name uses FileEntryRef.
+  Optional<FileEntryRef> LastRef;
+
 public:
   FileEntry()
       : UniqueID(0, 0), IsNamedPipe(false), IsValid(false)
@@ -100,7 +163,9 @@
   FileEntry(const FileEntry &) = delete;
   FileEntry &operator=(const FileEntry &) = delete;
 
-  StringRef getName() const { return Name; }
+  StringRef getName() const { return LastRef->getName(); }
+  FileEntryRef getLastRef() const { return *LastRef; }
+
   StringRef tryGetRealPathName() const { return RealPathName; }
   bool isValid() const { return IsValid; }
   off_t getSize() const { return Size; }
@@ -126,41 +191,19 @@
   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() = delete;
-  FileEntryRef(StringRef Name, const FileEntry &Entry)
-      : Name(Name), Entry(&Entry) {}
-
-  const StringRef getName() const { return Name; }
-
-  bool isValid() const { return Entry->isValid(); }
+bool FileEntryRef::isValid() const { return getFileEntry().isValid(); }
 
-  const FileEntry &getFileEntry() const { return *Entry; }
+off_t FileEntryRef::getSize() const { return getFileEntry().getSize(); }
 
-  off_t getSize() const { return Entry->getSize(); }
+unsigned FileEntryRef::getUID() const { return getFileEntry().getUID(); }
 
-  unsigned getUID() const { return Entry->getUID(); }
+const llvm::sys::fs::UniqueID &FileEntryRef::getUniqueID() const {
+  return getFileEntry().getUniqueID();
+}
 
-  const llvm::sys::fs::UniqueID &getUniqueID() const {
-    return Entry->getUniqueID();
-  }
-
-  time_t getModificationTime() const { return Entry->getModificationTime(); }
-
-  friend bool operator==(const FileEntryRef &LHS, const FileEntryRef &RHS) {
-    return LHS.Entry == RHS.Entry && LHS.Name == RHS.Name;
-  }
-  friend bool operator!=(const FileEntryRef &LHS, const FileEntryRef &RHS) {
-    return !(LHS == RHS);
-  }
-
-private:
-  StringRef Name;
-  const FileEntry *Entry;
-};
+time_t FileEntryRef::getModificationTime() const {
+  return getFileEntry().getModificationTime();
+}
 
 /// Implements support for file system lookup, file system caching,
 /// and directory search management.
@@ -219,10 +262,16 @@
   /// the file.
   ///
   /// \see SeenDirEntries
-  llvm::StringMap<llvm::ErrorOr<SeenFileEntryOrRedirect>,
-                  llvm::BumpPtrAllocator>
+  llvm::StringMap<llvm::ErrorOr<SeenFileTableValue>, llvm::BumpPtrAllocator>
       SeenFileEntries;
 
+  /// A mirror of SeenFileEntries to give fake answers for getBypassFile().
+  ///
+  /// Don't bother hooking up a BumpPtrAllocator. This should be rarely used,
+  /// and only on error paths.
+  std::unique_ptr<llvm::StringMap<llvm::ErrorOr<SeenFileTableValue>>>
+      SeenBypassFileEntries;
+
   /// The canonical names of files and directories .
   llvm::DenseMap<const void *, llvm::StringRef> CanonicalNames;
 
@@ -365,6 +414,14 @@
   /// The file itself is not accessed.
   const FileEntry *getVirtualFile(StringRef Filename, off_t Size,
                                   time_t ModificationTime);
+  FileEntryRef getVirtualFileRef(StringRef Filename, off_t Size,
+                                 time_t ModificationTime);
+
+  /// Blindly add another reference to the given FileEntry.
+  ///
+  /// Returns None if the filename is already mapped.
+  Optional<FileEntryRef> addAliasForFile(StringRef Filename,
+                                         const FileEntry &FE);
 
   /// Retrieve a FileEntry that bypasses VFE, which is expected to be a virtual
   /// file entry, to access the real file.  The returned FileEntry will have
Index: clang-tools-extra/clangd/ParsedAST.cpp
===================================================================
--- clang-tools-extra/clangd/ParsedAST.cpp
+++ clang-tools-extra/clangd/ParsedAST.cpp
@@ -170,10 +170,9 @@
 
   void replay() {
     for (const auto &Inc : Includes) {
-      const FileEntry *File = nullptr;
+      llvm::Optional<FileEntryRef> File;
       if (Inc.Resolved != "")
-        if (auto FE = SM.getFileManager().getFile(Inc.Resolved))
-          File = *FE;
+        File = SM.getFileManager().getFileRef(Inc.Resolved);
 
       // Re-lex the #include directive to find its interesting parts.
       auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
@@ -211,17 +210,17 @@
       SynthesizedFilenameTok.setKind(tok::header_name);
       SynthesizedFilenameTok.setLiteralData(Inc.Written.data());
 
+      const FileEntry *FE = File ? &File.getEntry() : nullptr;
       llvm::StringRef WrittenFilename =
           llvm::StringRef(Inc.Written).drop_front().drop_back();
       Delegate->InclusionDirective(HashTok->location(), SynthesizedIncludeTok,
                                    WrittenFilename, Inc.Written.front() == '<',
-                                   FileTok->range(SM).toCharRange(SM), File,
+                                   FileTok->range(SM).toCharRange(SM), FE,
                                    "SearchPath", "RelPath",
                                    /*Imported=*/nullptr, Inc.FileKind);
       if (File)
         // FIXME: Use correctly named FileEntryRef.
-        Delegate->FileSkipped(FileEntryRef(File->getName(), *File),
-                              SynthesizedFilenameTok, Inc.FileKind);
+        Delegate->FileSkipped(File, SynthesizedFilenameTok, Inc.FileKind);
       else {
         llvm::SmallString<1> UnusedRecovery;
         Delegate->FileNotFound(WrittenFilename, UnusedRecovery);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D89488: WI... Duncan P. N. Exon Smith via Phabricator via cfe-commits

Reply via email to