diff --git a/clang/include/clang/Basic/FileEntry.h b/clang/include/clang/Basic/FileEntry.h --- a/clang/include/clang/Basic/FileEntry.h +++ b/clang/include/clang/Basic/FileEntry.h @@ -59,11 +59,21 @@ /// accessed by the FileManager's client. class FileEntryRef { public: - StringRef getName() const { return ME->first(); } + /// The name of this FileEntry. If a VFS uses 'use-external-name', this is + /// the redirected name. See getRequestedName(). + StringRef getName() const { return getBaseMapEntry().first(); } + + /// The name of this FileEntry, as originally requested without applying any + /// remappings for VFS 'use-external-name'. + /// + /// FIXME: this should be the semantics of getName(). See comment in + /// FileManager::getFileRef(). + StringRef getNameAsRequested() const { return ME->first(); } + const FileEntry &getFileEntry() const { - return *ME->second->V.get(); + return *getBaseMapEntry().second->V.get(); } - DirectoryEntryRef getDir() const { return *ME->second->Dir; } + DirectoryEntryRef getDir() const { return *getBaseMapEntry().second->Dir; } inline off_t getSize() const; inline unsigned getUID() const; @@ -150,13 +160,20 @@ explicit FileEntryRef(const MapEntry &ME) : ME(&ME) { assert(ME.second && "Expected payload"); assert(ME.second->V && "Expected non-null"); - assert(ME.second->V.is() && "Expected FileEntry"); } /// Expose the underlying MapEntry to simplify packing in a PointerIntPair or /// PointerUnion and allow construction in Optional. const clang::FileEntryRef::MapEntry &getMapEntry() const { return *ME; } + /// Retrieve the base MapEntry after redirects. + const MapEntry &getBaseMapEntry() const { + const MapEntry *ME = this->ME; + while (const void *Next = ME->second->V.dyn_cast()) + ME = static_cast(Next); + return *ME; + } + private: friend class FileMgr::MapEntryOptionalStorage; struct optional_none_tag {}; diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp --- a/clang/lib/Basic/FileManager.cpp +++ b/clang/lib/Basic/FileManager.cpp @@ -293,12 +293,8 @@ // name-as-accessed on the \a FileEntryRef. // // A potential plan to remove this is as follows - - // - Expose the requested filename. One possibility would be to allow - // redirection-FileEntryRefs to be returned, rather than returning - // the pointed-at-FileEntryRef, and customizing `getName()` to look - // through the indirection. // - Update callers such as `HeaderSearch::findUsableModuleForHeader()` - // to explicitly use the requested filename rather than just using + // to explicitly use the `getNameAsRequested()` rather than just using // `getName()`. // - Add a `FileManager::getExternalPath` API for explicitly getting the // remapped external filename when there is one available. Adopt it in @@ -329,9 +325,6 @@ // Cache the redirection in the previously-inserted entry, still available // in the tentative return value. NamedFileEnt->second = FileEntryRef::MapValue(Redirection); - - // Fix the tentative return value. - NamedFileEnt = &Redirection; } FileEntryRef ReturnedRef(*NamedFileEnt); diff --git a/clang/unittests/Basic/FileEntryTest.cpp b/clang/unittests/Basic/FileEntryTest.cpp --- a/clang/unittests/Basic/FileEntryTest.cpp +++ b/clang/unittests/Basic/FileEntryTest.cpp @@ -50,6 +50,14 @@ const_cast(Base.getFileEntry()), DR)}) .first); } + FileEntryRef addFileRedirect(StringRef Name, FileEntryRef Base) { + return FileEntryRef( + *Files + .insert({Name, FileEntryRef::MapValue( + const_cast( + Base.getMapEntry()))}) + .first); + } }; namespace { @@ -58,13 +66,23 @@ FileEntryRef R1 = Refs.addFile("1"); FileEntryRef R2 = Refs.addFile("2"); FileEntryRef R1Also = Refs.addFileAlias("1-also", R1); + FileEntryRef R1Redirect = Refs.addFileRedirect("1-redirect", R1); + FileEntryRef R1Redirect2 = Refs.addFileRedirect("1-redirect2", R1Redirect); EXPECT_EQ("1", R1.getName()); EXPECT_EQ("2", R2.getName()); EXPECT_EQ("1-also", R1Also.getName()); + EXPECT_EQ("1", R1Redirect.getName()); + EXPECT_EQ("1", R1Redirect2.getName()); + + EXPECT_EQ("1", R1.getNameAsRequested()); + EXPECT_EQ("1-redirect", R1Redirect.getNameAsRequested()); + EXPECT_EQ("1-redirect2", R1Redirect2.getNameAsRequested()); EXPECT_NE(&R1.getFileEntry(), &R2.getFileEntry()); EXPECT_EQ(&R1.getFileEntry(), &R1Also.getFileEntry()); + EXPECT_EQ(&R1.getFileEntry(), &R1Redirect.getFileEntry()); + EXPECT_EQ(&R1Redirect.getFileEntry(), &R1Redirect2.getFileEntry()); const FileEntry *CE1 = R1; EXPECT_EQ(CE1, &R1.getFileEntry()); @@ -93,6 +111,8 @@ FileEntryRef R1 = Refs.addFile("1"); FileEntryRef R2 = Refs.addFile("2"); FileEntryRef R1Also = Refs.addFileAlias("1-also", R1); + FileEntryRef R1Redirect = Refs.addFileRedirect("1-redirect", R1); + FileEntryRef R1Redirect2 = Refs.addFileRedirect("1-redirect2", R1Redirect); EXPECT_EQ(R1, &R1.getFileEntry()); EXPECT_EQ(&R1.getFileEntry(), R1); @@ -100,6 +120,8 @@ EXPECT_NE(R1, &R2.getFileEntry()); EXPECT_NE(&R2.getFileEntry(), R1); EXPECT_NE(R1, R2); + EXPECT_EQ(R1, R1Redirect); + EXPECT_EQ(R1, R1Redirect2); OptionalFileEntryRefDegradesToFileEntryPtr M1 = R1; @@ -114,11 +136,16 @@ FileEntryRef R1 = Refs.addFile("1"); FileEntryRef R2 = Refs.addFile("2"); FileEntryRef R1Also = Refs.addFileAlias("1-also", R1); + FileEntryRef R1Redirect = Refs.addFileRedirect("1-redirect", R1); + FileEntryRef R1Redirect2 = Refs.addFileRedirect("1-redirect2", R1Redirect); EXPECT_TRUE(R1.isSameRef(FileEntryRef(R1))); EXPECT_TRUE(R1.isSameRef(FileEntryRef(R1.getMapEntry()))); EXPECT_FALSE(R1.isSameRef(R2)); EXPECT_FALSE(R1.isSameRef(R1Also)); + EXPECT_FALSE(R1.isSameRef(R1Redirect)); + EXPECT_FALSE(R1.isSameRef(R1Redirect2)); + EXPECT_FALSE(R1Redirect.isSameRef(R1Redirect2)); } TEST(FileEntryTest, DenseMapInfo) { diff --git a/clang/unittests/Basic/FileManagerTest.cpp b/clang/unittests/Basic/FileManagerTest.cpp --- a/clang/unittests/Basic/FileManagerTest.cpp +++ b/clang/unittests/Basic/FileManagerTest.cpp @@ -356,9 +356,13 @@ EXPECT_EQ("dir/f1.cpp", F1Redirect->getName()); EXPECT_EQ("dir/f2.cpp", F2->getName()); + EXPECT_EQ("dir/f1.cpp", F1->getNameAsRequested()); + EXPECT_EQ("dir/f1-redirect.cpp", F1Redirect->getNameAsRequested()); + // Compare against FileEntry*. EXPECT_EQ(&F1->getFileEntry(), *F1); EXPECT_EQ(*F1, &F1->getFileEntry()); + EXPECT_EQ(&F1->getFileEntry(), &F1Redirect->getFileEntry()); EXPECT_NE(&F2->getFileEntry(), *F1); EXPECT_NE(*F1, &F2->getFileEntry()); @@ -374,7 +378,7 @@ // Compare using isSameRef. EXPECT_TRUE(F1->isSameRef(*F1Again)); - EXPECT_TRUE(F1->isSameRef(*F1Redirect)); + EXPECT_FALSE(F1->isSameRef(*F1Redirect)); EXPECT_FALSE(F1->isSameRef(*F1Also)); EXPECT_FALSE(F1->isSameRef(*F2)); }