dexonsmith created this revision. dexonsmith added reviewers: JDevlieghere, arphaman, teemperor. Herald added subscribers: llvm-commits, ributzka, mgorny. Herald added a project: LLVM. dexonsmith requested review of this revision.
Make a few changes to the `FileEntryRef` API in preparation for propagating it enough to remove `FileEntry::getName()`. - Change `operator==` to compare the underlying `FileEntry*`, ignoring any difference to the spelling of the name. There were 0 users of the existing function because it's not useful. This avoids adding noisy code where `getFileEntry()` is used pervasively to compare equality. In case comparing the named reference becomes important, add (and test) the API now called `isSameRef`. - Add `MaybeFileEntryRef`, which is a pointer-sized version of `Optional<FileEntryRef>` that is designed to replace fields that are currently `FileEntry*`. To avoid code duplication, the guts of `FileEntryRef` were moved to a common base class, `FileEntryRefBase`. Besides interoperation with `Optional`, this calls exposes `getName()` (`Optional` version) and `getFileEntry()` (pointer version). - Add implicit conversions to `FileEntry*` to allow functions currently returning `const FileEntry*` to be updated to `FileEntryRef` or `MaybeFileEntryRef` without requiring all callers to be updated in the same step. This helps avoid both (a) massive patches where many fields and locals are updated simultaneously and (b) noisy incremental patches where the first patch adds `getFileEntry()` at call sites and the second patch removes it. - Add various `operator==` for easy interoperation. - Remove the `const` from the return of `FileEntryRef::getName`. - As a drive-by cleanup, delete the unused `FileEntry::isOpenForTests`. Note that there are still `FileEntry` APIs that aren't wrapped and I plan to deal with these separately / incrementally, as they are needed. https://reviews.llvm.org/D89834 Files: clang/include/clang/Basic/FileEntry.h clang/include/clang/Basic/FileManager.h clang/lib/Basic/CMakeLists.txt clang/lib/Basic/FileEntry.cpp llvm/include/llvm/Support/FileSystem.h llvm/include/llvm/Support/FileSystem/UniqueID.h
Index: llvm/include/llvm/Support/FileSystem/UniqueID.h =================================================================== --- /dev/null +++ llvm/include/llvm/Support/FileSystem/UniqueID.h @@ -0,0 +1,47 @@ +//===- llvm/Support/FileSystem/UniqueID.h - UniqueID for files --*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file is cut out of llvm/Support/FileSystem.h to allow UniqueID to be +// reused without bloating the includes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_FILESYSTEM_UNIQUEID_H +#define LLVM_SUPPORT_FILESYSTEM_UNIQUEID_H + +#include <cstddef> + +namespace llvm { +namespace sys { +namespace fs { + +class UniqueID { + uint64_t Device; + uint64_t File; + +public: + UniqueID() = default; + UniqueID(uint64_t Device, uint64_t File) : Device(Device), File(File) {} + + bool operator==(const UniqueID &Other) const { + return Device == Other.Device && File == Other.File; + } + bool operator!=(const UniqueID &Other) const { return !(*this == Other); } + bool operator<(const UniqueID &Other) const { + return std::tie(Device, File) < std::tie(Other.Device, Other.File); + } + + uint64_t getDevice() const { return Device; } + uint64_t getFile() const { return File; } +}; + +} // end namespace fs +} // end namespace sys +} // end namespace llvm + +#endif // LLVM_SUPPORT_FILESYSTEM_UNIQUEID_H Index: llvm/include/llvm/Support/FileSystem.h =================================================================== --- llvm/include/llvm/Support/FileSystem.h +++ llvm/include/llvm/Support/FileSystem.h @@ -34,6 +34,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem/UniqueID.h" #include "llvm/Support/MD5.h" #include <cassert> #include <cstdint> @@ -131,26 +132,6 @@ static_cast<unsigned short>(~static_cast<unsigned short>(x))); } -class UniqueID { - uint64_t Device; - uint64_t File; - -public: - UniqueID() = default; - UniqueID(uint64_t Device, uint64_t File) : Device(Device), File(File) {} - - bool operator==(const UniqueID &Other) const { - return Device == Other.Device && File == Other.File; - } - bool operator!=(const UniqueID &Other) const { return !(*this == Other); } - bool operator<(const UniqueID &Other) const { - return std::tie(Device, File) < std::tie(Other.Device, Other.File); - } - - uint64_t getDevice() const { return Device; } - uint64_t getFile() const { return File; } -}; - /// Represents the result of a call to directory_iterator::status(). This is a /// subset of the information returned by a regular sys::fs::status() call, and /// represents the information provided by Windows FileFirstFile/FindNextFile. Index: clang/lib/Basic/FileEntry.cpp =================================================================== --- /dev/null +++ clang/lib/Basic/FileEntry.cpp @@ -0,0 +1,23 @@ +//===- FileEntry.cpp - File references --------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines implementation for clang::FileEntry and clang::FileEntryRef. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/FileEntry.h" +#include "llvm/Support/VirtualFileSystem.h" + +using namespace clang; + +FileEntry::FileEntry() : UniqueID(0, 0), IsNamedPipe(false), IsValid(false) {} + +FileEntry::~FileEntry() = default; + +void FileEntry::closeFile() const { File.reset(); } Index: clang/lib/Basic/CMakeLists.txt =================================================================== --- clang/lib/Basic/CMakeLists.txt +++ clang/lib/Basic/CMakeLists.txt @@ -46,6 +46,7 @@ DiagnosticIDs.cpp DiagnosticOptions.cpp ExpressionTraits.cpp + FileEntry.cpp FileManager.cpp FileSystemStatCache.cpp IdentifierTable.cpp Index: clang/include/clang/Basic/FileManager.h =================================================================== --- clang/include/clang/Basic/FileManager.h +++ clang/include/clang/Basic/FileManager.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_BASIC_FILEMANAGER_H #define LLVM_CLANG_BASIC_FILEMANAGER_H +#include "clang/Basic/FileEntry.h" #include "clang/Basic/FileSystemOptions.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/DenseMap.h" @@ -71,141 +72,6 @@ const llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>> *Entry; }; -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 { -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. - using MapEntry = llvm::StringMapEntry<llvm::ErrorOr<MapValue>>; - - /// Type stored in the StringMap. - struct MapValue { - /// The pointer at another MapEntry is used when the FileManager should - /// silently forward from one name to another, which occurs in 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. - llvm::PointerUnion<FileEntry *, const MapEntry *> V; - - MapValue() = delete; - MapValue(FileEntry &FE) : V(&FE) {} - MapValue(MapEntry &ME) : V(&ME) {} - }; - -private: - friend class FileManager; - - 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"); - } - - const MapEntry *Entry; -}; - -/// Cached information about one file (either on disk -/// or in the virtual file system). -/// -/// If the 'File' member is valid, then this FileEntry has an open file -/// descriptor for the file. -class FileEntry { - friend class FileManager; - - 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. - const DirectoryEntry *Dir; // Directory file lives in. - llvm::sys::fs::UniqueID UniqueID; - unsigned UID; // A unique (small) ID for the file. - bool IsNamedPipe; - bool IsValid; // Is this \c FileEntry initialized and valid? - - /// 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) - {} - - FileEntry(const FileEntry &) = delete; - FileEntry &operator=(const FileEntry &) = delete; - - 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; } - unsigned getUID() const { return UID; } - const llvm::sys::fs::UniqueID &getUniqueID() const { return UniqueID; } - time_t getModificationTime() const { return ModTime; } - - /// Return the directory the file lives in. - const DirectoryEntry *getDir() const { return Dir; } - - bool operator<(const FileEntry &RHS) const { return UniqueID < RHS.UniqueID; } - - /// Check whether the file is a named pipe (and thus can't be opened by - /// the native FileManager methods). - bool isNamedPipe() const { return IsNamedPipe; } - - void closeFile() const { - File.reset(); // rely on destructor to close File - } - - // 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(); } - -off_t FileEntryRef::getSize() const { return getFileEntry().getSize(); } - -unsigned FileEntryRef::getUID() const { return getFileEntry().getUID(); } - -const llvm::sys::fs::UniqueID &FileEntryRef::getUniqueID() const { - return getFileEntry().getUniqueID(); -} - -time_t FileEntryRef::getModificationTime() const { - return getFileEntry().getModificationTime(); -} - /// Implements support for file system lookup, file system caching, /// and directory search management. /// Index: clang/include/clang/Basic/FileEntry.h =================================================================== --- /dev/null +++ clang/include/clang/Basic/FileEntry.h @@ -0,0 +1,169 @@ +//===- clang/Basic/FileEntry.h - File references ----------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Defines interfaces for clang::FileEntry and clang::FileEntryRef. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_FILEENTRY_H +#define LLVM_CLANG_BASIC_FILEENTRY_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem/UniqueID.h" + +namespace llvm { +namespace vfs { + +class File; + +} // namespace vfs +} // namespace llvm + +namespace clang { + +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 { +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. + using MapEntry = llvm::StringMapEntry<llvm::ErrorOr<MapValue>>; + + /// Type stored in the StringMap. + struct MapValue { + /// The pointer at another MapEntry is used when the FileManager should + /// silently forward from one name to another, which occurs in 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. + llvm::PointerUnion<FileEntry *, const MapEntry *> V; + + MapValue() = delete; + MapValue(FileEntry &FE) : V(&FE) {} + MapValue(MapEntry &ME) : V(&ME) {} + }; + +private: + friend class FileManager; + + 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"); + } + + const MapEntry *Entry; +}; + +/// Cached information about one file (either on disk +/// or in the virtual file system). +/// +/// If the 'File' member is valid, then this FileEntry has an open file +/// descriptor for the file. +class FileEntry { + friend class FileManager; + + 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. + const DirectoryEntry *Dir; // Directory file lives in. + llvm::sys::fs::UniqueID UniqueID; + unsigned UID; // A unique (small) ID for the file. + bool IsNamedPipe; + bool IsValid; // Is this \c FileEntry initialized and valid? + + /// 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(); + ~FileEntry(); + + FileEntry(const FileEntry &) = delete; + FileEntry &operator=(const FileEntry &) = delete; + + 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; } + unsigned getUID() const { return UID; } + const llvm::sys::fs::UniqueID &getUniqueID() const { return UniqueID; } + time_t getModificationTime() const { return ModTime; } + + /// Return the directory the file lives in. + const DirectoryEntry *getDir() const { return Dir; } + + bool operator<(const FileEntry &RHS) const { return UniqueID < RHS.UniqueID; } + + /// Check whether the file is a named pipe (and thus can't be opened by + /// the native FileManager methods). + 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(); } + +off_t FileEntryRef::getSize() const { return getFileEntry().getSize(); } + +unsigned FileEntryRef::getUID() const { return getFileEntry().getUID(); } + +const llvm::sys::fs::UniqueID &FileEntryRef::getUniqueID() const { + return getFileEntry().getUniqueID(); +} + +time_t FileEntryRef::getModificationTime() const { + return getFileEntry().getModificationTime(); +} + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_FILEENTRY_H
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits