dexonsmith updated this revision to Diff 299506.
dexonsmith added a comment.
Attaching the correct diff :/.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D89834/new/
https://reviews.llvm.org/D89834
Files:
clang/include/clang/Basic/FileEntry.h
clang/unittests/Basic/CMakeLists.txt
clang/unittests/Basic/FileEntryTest.cpp
clang/unittests/Basic/FileManagerTest.cpp
Index: clang/unittests/Basic/FileManagerTest.cpp
===================================================================
--- clang/unittests/Basic/FileManagerTest.cpp
+++ clang/unittests/Basic/FileManagerTest.cpp
@@ -334,6 +334,58 @@
f2 ? *f2 : nullptr);
}
+TEST_F(FileManagerTest, getFileRefEquality) {
+ auto StatCache = std::make_unique<FakeStatCache>();
+ StatCache->InjectDirectory("dir", 40);
+ StatCache->InjectFile("dir/f1.cpp", 41);
+ StatCache->InjectFile("dir/f1-also.cpp", 41);
+ StatCache->InjectFile("dir/f1-redirect.cpp", 41, "dir/f1.cpp");
+ StatCache->InjectFile("dir/f2.cpp", 42);
+ manager.setStatCache(std::move(StatCache));
+
+ auto F1 = manager.getFileRef("dir/f1.cpp");
+ auto F1Again = manager.getFileRef("dir/f1.cpp");
+ auto F1Also = manager.getFileRef("dir/f1-also.cpp");
+ auto F1Redirect = manager.getFileRef("dir/f1-redirect.cpp");
+ auto F2 = manager.getFileRef("dir/f2.cpp");
+
+ // Check Expected<FileEntryRef> for error.
+ ASSERT_FALSE(!F1);
+ ASSERT_FALSE(!F1Also);
+ ASSERT_FALSE(!F1Again);
+ ASSERT_FALSE(!F1Redirect);
+ ASSERT_FALSE(!F2);
+
+ // Check names.
+ EXPECT_EQ("dir/f1.cpp", F1->getName());
+ EXPECT_EQ("dir/f1.cpp", F1Again->getName());
+ EXPECT_EQ("dir/f1-also.cpp", F1Also->getName());
+ EXPECT_EQ("dir/f1.cpp", F1Redirect->getName());
+ EXPECT_EQ("dir/f2.cpp", F2->getName());
+
+ // Compare against FileEntry*.
+ EXPECT_EQ(&F1->getFileEntry(), *F1);
+ EXPECT_EQ(*F1, &F1->getFileEntry());
+ EXPECT_NE(&F2->getFileEntry(), *F1);
+ EXPECT_NE(*F1, &F2->getFileEntry());
+
+ // Compare using ==.
+ EXPECT_EQ(*F1, *F1Also);
+ EXPECT_EQ(*F1, *F1Again);
+ EXPECT_EQ(*F1, *F1Redirect);
+ EXPECT_EQ(*F1Also, *F1Redirect);
+ EXPECT_NE(*F2, *F1);
+ EXPECT_NE(*F2, *F1Also);
+ EXPECT_NE(*F2, *F1Again);
+ EXPECT_NE(*F2, *F1Redirect);
+
+ // Compare using isSameRef.
+ EXPECT_TRUE(F1->isSameRef(*F1Again));
+ EXPECT_TRUE(F1->isSameRef(*F1Redirect));
+ EXPECT_FALSE(F1->isSameRef(*F1Also));
+ EXPECT_FALSE(F1->isSameRef(*F2));
+}
+
// getFile() Should return the same entry as getVirtualFile if the file actually
// is a virtual file, even if the name is not exactly the same (but is after
// normalisation done by the file system, like on Windows). This can be checked
Index: clang/unittests/Basic/FileEntryTest.cpp
===================================================================
--- /dev/null
+++ clang/unittests/Basic/FileEntryTest.cpp
@@ -0,0 +1,131 @@
+//===- unittests/Basic/FileEntryTest.cpp - Test FileEntry/FileEntryRef ----===//
+//
+// 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/Basic/FileEntry.h"
+#include "llvm/ADT/StringMap.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+
+using MapEntry = FileEntryRef::MapEntry;
+using MapValue = FileEntryRef::MapValue;
+using MapType = StringMap<llvm::ErrorOr<MapValue>>;
+
+FileEntryRef addRef(MapType &M, StringRef Name, FileEntry &E) {
+ return FileEntryRef(*M.insert({Name, MapValue(E)}).first);
+}
+
+TEST(FileEntryTest, FileEntryRef) {
+ MapType Refs;
+ FileEntry E1, E2;
+ FileEntryRef R1 = addRef(Refs, "1", E1);
+ FileEntryRef R2 = addRef(Refs, "2", E2);
+ FileEntryRef R1Also = addRef(Refs, "1-also", E1);
+
+ EXPECT_EQ("1", R1.getName());
+ EXPECT_EQ("2", R2.getName());
+ EXPECT_EQ("1-also", R1Also.getName());
+
+ EXPECT_EQ(&E1, &R1.getFileEntry());
+ EXPECT_EQ(&E2, &R2.getFileEntry());
+ EXPECT_EQ(&E1, &R1Also.getFileEntry());
+
+ const FileEntry *CE1 = R1;
+ EXPECT_EQ(CE1, &E1);
+}
+
+TEST(FileEntryTest, MaybeFileEntryRef) {
+ MapType Refs;
+ FileEntry E1, E2;
+ MaybeFileEntryRef M0;
+ MaybeFileEntryRef M1 = addRef(Refs, "1", E1);
+ MaybeFileEntryRef M2 = addRef(Refs, "2", E2);
+ MaybeFileEntryRef M1Also = addRef(Refs, "1-also", E1);
+
+ EXPECT_EQ(None, M0.getName());
+ EXPECT_EQ(StringRef("1"), M1.getName());
+ EXPECT_EQ(StringRef("2"), M2.getName());
+ EXPECT_EQ(StringRef("1-also"), M1Also.getName());
+ EXPECT_NE(None, M1.getName());
+ EXPECT_NE(StringRef("1"), M2.getName());
+
+ EXPECT_EQ(&E1, M1.getFileEntry());
+ EXPECT_EQ(&E2, M2.getFileEntry());
+ EXPECT_EQ(&E1, M1Also.getFileEntry());
+
+ const FileEntry *CE1 = M1;
+ EXPECT_EQ(CE1, &E1);
+}
+
+TEST(FileEntryTest, equals) {
+ MapType Refs;
+ FileEntry E1, E2;
+ FileEntryRef R1 = addRef(Refs, "1", E1);
+ FileEntryRef R2 = addRef(Refs, "2", E2);
+ FileEntryRef R1Also = addRef(Refs, "1-also", E1);
+
+ EXPECT_EQ(R1, &E1);
+ EXPECT_EQ(&E1, R1);
+ EXPECT_EQ(R1, R1Also);
+ EXPECT_NE(R1, &E2);
+ EXPECT_NE(&E2, R1);
+ EXPECT_NE(R1, R2);
+
+ MaybeFileEntryRef M0;
+ MaybeFileEntryRef M1 = R1;
+ MaybeFileEntryRef M2 = R2;
+ MaybeFileEntryRef M1Also = R1Also;
+
+ EXPECT_EQ(M0, nullptr);
+ EXPECT_EQ(M0, None);
+ EXPECT_EQ(nullptr, M0);
+ EXPECT_EQ(None, M0);
+ EXPECT_EQ(M1, &E1);
+ EXPECT_EQ(&E1, M1);
+ EXPECT_EQ(R1, M1);
+ EXPECT_EQ(M1, R1);
+ EXPECT_EQ(M1, M1Also);
+ EXPECT_NE(M1, nullptr);
+ EXPECT_NE(M1, None);
+ EXPECT_NE(nullptr, M1);
+ EXPECT_NE(None, M1);
+ EXPECT_NE(M1, &E2);
+ EXPECT_NE(&E2, M1);
+ EXPECT_NE(M1, R2);
+ EXPECT_NE(R2, M1);
+ EXPECT_NE(M1, M2);
+}
+
+TEST(FileEntryTest, isSameRef) {
+ MapType Refs;
+ FileEntry E1, E2;
+ FileEntryRef R1 = addRef(Refs, "1", E1);
+ FileEntryRef R2 = addRef(Refs, "2", E2);
+ FileEntryRef R1Also = addRef(Refs, "1-also", E1);
+
+ EXPECT_TRUE(R1.isSameRef(FileEntryRef(R1)));
+ EXPECT_FALSE(R1.isSameRef(R2));
+ EXPECT_FALSE(R1.isSameRef(R1Also));
+
+ MaybeFileEntryRef M0;
+ MaybeFileEntryRef M1 = R1;
+ MaybeFileEntryRef M2 = R2;
+ MaybeFileEntryRef M1Also = R1Also;
+
+ EXPECT_FALSE(M0.isSameRef(M1));
+ EXPECT_FALSE(M1.isSameRef(M0));
+ EXPECT_TRUE(M1.isSameRef(MaybeFileEntryRef(M1)));
+ EXPECT_FALSE(M1.isSameRef(M1Also));
+ EXPECT_FALSE(M1.isSameRef(M2));
+ EXPECT_TRUE(M1.isSameRef(R1));
+}
+
+} // end namespace
Index: clang/unittests/Basic/CMakeLists.txt
===================================================================
--- clang/unittests/Basic/CMakeLists.txt
+++ clang/unittests/Basic/CMakeLists.txt
@@ -5,6 +5,7 @@
add_clang_unittest(BasicTests
CharInfoTest.cpp
DiagnosticTest.cpp
+ FileEntryTest.cpp
FileManagerTest.cpp
SourceManagerTest.cpp
)
Index: clang/include/clang/Basic/FileEntry.h
===================================================================
--- clang/include/clang/Basic/FileEntry.h
+++ clang/include/clang/Basic/FileEntry.h
@@ -34,28 +34,8 @@
class DirectoryEntry;
class FileEntry;
-/// A reference to a \c FileEntry that includes the name of the file as it was
-/// accessed by the FileManager's client.
-class FileEntryRef {
+class FileEntryRefBase {
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);
- }
-
struct MapValue;
/// Type used in the StringMap.
@@ -75,18 +55,119 @@
MapValue(MapEntry &ME) : V(&ME) {}
};
-private:
- friend class FileManager;
+ /// Check if RHS referenced the file in exactly the same way.
+ bool isSameRef(const FileEntryRefBase &RHS) const { return ME == RHS.ME; }
- FileEntryRef() = delete;
- explicit FileEntryRef(const MapEntry &Entry)
- : Entry(&Entry) {
- assert(Entry.second && "Expected payload");
- assert(Entry.second->V && "Expected non-null");
- assert(Entry.second->V.is<FileEntry *>() && "Expected FileEntry");
+ /// Check if the underlying FileEntry is the same, intentially ignoring
+ /// whether the file was referenced with the same spelling of the filename.
+ friend bool operator==(const FileEntryRefBase &LHS,
+ const FileEntryRefBase &RHS) {
+ return LHS.getFileEntry() == RHS.getFileEntry();
+ }
+ friend bool operator==(const FileEntry *LHS, const FileEntryRefBase &RHS) {
+ return LHS == RHS.getFileEntry();
+ }
+ friend bool operator==(const FileEntryRefBase &LHS, const FileEntry *RHS) {
+ return LHS.getFileEntry() == RHS;
+ }
+ friend bool operator!=(const FileEntryRefBase &LHS,
+ const FileEntryRefBase &RHS) {
+ return !(LHS == RHS);
+ }
+ friend bool operator!=(const FileEntry *LHS, const FileEntryRefBase &RHS) {
+ return !(LHS == RHS);
+ }
+ friend bool operator!=(const FileEntryRefBase &LHS, const FileEntry *RHS) {
+ return !(LHS == RHS);
+ }
+
+protected:
+ FileEntryRefBase() = delete;
+ explicit FileEntryRefBase(const MapEntry *ME) : ME(ME) {
+ if (!ME)
+ return;
+ assert(ME->second && "Expected payload");
+ assert(ME->second->V && "Expected non-null");
+ assert(ME->second->V.is<FileEntry *>() && "Expected FileEntry");
+ }
+
+ Optional<StringRef> getName() const {
+ return ME ? ME->first() : Optional<StringRef>();
+ }
+
+ const FileEntry *getFileEntry() const {
+ return ME ? ME->second->V.get<FileEntry *>() : nullptr;
}
- const MapEntry *Entry;
+ const MapEntry *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 FileEntryRefBase {
+ friend class MaybeFileEntryRef;
+
+public:
+ StringRef getName() const { return *FileEntryRefBase::getName(); }
+ const FileEntry &getFileEntry() const {
+ return *FileEntryRefBase::getFileEntry();
+ }
+
+ /// Allow FileEntryRef to degrade into FileEntry* to facilitate incremental
+ /// adoption.
+ operator const FileEntry *() const { return &getFileEntry(); }
+
+ 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;
+
+ explicit FileEntryRef(const MapEntry &ME) : FileEntryRefBase(&ME) {}
+};
+
+class MaybeFileEntryRef : public FileEntryRefBase {
+public:
+ using FileEntryRefBase::getFileEntry;
+ using FileEntryRefBase::getName;
+
+ /// Allow MaybeFileEntryRef to degrade into FileEntry* to facilitate
+ /// incremental adoption.
+ operator const FileEntry *() const { return getFileEntry(); }
+
+ explicit operator bool() const { return ME; }
+
+ FileEntryRef operator*() const {
+ assert(ME && "Dereferencing null?");
+ return FileEntryRef(*ME);
+ }
+
+ /// Use Optional<FileEntryRef> to provide storage for arrow.
+ Optional<FileEntryRef> operator->() const { return *this; }
+
+ friend bool operator==(llvm::NoneType, const MaybeFileEntryRef &RHS) {
+ return !RHS;
+ }
+ friend bool operator==(const MaybeFileEntryRef &LHS, llvm::NoneType) {
+ return !LHS;
+ }
+ friend bool operator!=(llvm::NoneType LHS, const MaybeFileEntryRef &RHS) {
+ return !(LHS == RHS);
+ }
+ friend bool operator!=(const MaybeFileEntryRef &LHS, llvm::NoneType RHS) {
+ return !(LHS == RHS);
+ }
+
+ /// Implicitly convert to/from Optional<FileEntryRef>.
+ operator Optional<FileEntryRef>() const {
+ return ME ? FileEntryRef(*ME) : Optional<FileEntryRef>();
+ }
+ MaybeFileEntryRef(Optional<FileEntryRef> F)
+ : FileEntryRefBase(F ? F->ME : nullptr) {}
+
+ explicit MaybeFileEntryRef(const MapEntry *ME) : FileEntryRefBase(ME) {}
+ MaybeFileEntryRef(llvm::NoneType = None) : FileEntryRefBase(nullptr) {}
+ MaybeFileEntryRef(FileEntryRef F) : FileEntryRefBase(F) {}
};
/// Cached information about one file (either on disk
@@ -115,7 +196,7 @@
// default constructor). It should always have a value in practice.
//
// TODO: remote this once everyone that needs a name uses FileEntryRef.
- Optional<FileEntryRef> LastRef;
+ MaybeFileEntryRef LastRef;
public:
FileEntry();
@@ -144,10 +225,6 @@
bool isNamedPipe() const { return IsNamedPipe; }
void closeFile() const;
-
- // Only for use in tests to see if deferred opens are happening, rather than
- // relying on RealPathName being empty.
- bool isOpenForTests() const { return File != nullptr; }
};
bool FileEntryRef::isValid() const { return getFileEntry().isValid(); }
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits