Home | History | Annotate | Line # | Download | only in Basic
      1 //===- clang/Basic/DirectoryEntry.h - Directory references ------*- C++ -*-===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 ///
      9 /// \file
     10 /// Defines interfaces for clang::DirectoryEntry and clang::DirectoryEntryRef.
     11 ///
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifndef LLVM_CLANG_BASIC_DIRECTORYENTRY_H
     15 #define LLVM_CLANG_BASIC_DIRECTORYENTRY_H
     16 
     17 #include "clang/Basic/LLVM.h"
     18 #include "llvm/ADT/DenseMapInfo.h"
     19 #include "llvm/ADT/Hashing.h"
     20 #include "llvm/ADT/StringMap.h"
     21 #include "llvm/ADT/StringRef.h"
     22 #include "llvm/Support/ErrorOr.h"
     23 
     24 namespace clang {
     25 namespace FileMgr {
     26 
     27 template <class RefTy> class MapEntryOptionalStorage;
     28 
     29 } // end namespace FileMgr
     30 
     31 /// Cached information about one directory (either on disk or in
     32 /// the virtual file system).
     33 class DirectoryEntry {
     34   friend class FileManager;
     35 
     36   // FIXME: We should not be storing a directory entry name here.
     37   StringRef Name; // Name of the directory.
     38 
     39 public:
     40   StringRef getName() const { return Name; }
     41 };
     42 
     43 /// A reference to a \c DirectoryEntry  that includes the name of the directory
     44 /// as it was accessed by the FileManager's client.
     45 class DirectoryEntryRef {
     46 public:
     47   const DirectoryEntry &getDirEntry() const { return *ME->getValue(); }
     48 
     49   StringRef getName() const { return ME->getKey(); }
     50 
     51   /// Hash code is based on the DirectoryEntry, not the specific named
     52   /// reference.
     53   friend llvm::hash_code hash_value(DirectoryEntryRef Ref) {
     54     return llvm::hash_value(&Ref.getDirEntry());
     55   }
     56 
     57   using MapEntry = llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>>;
     58 
     59   const MapEntry &getMapEntry() const { return *ME; }
     60 
     61   /// Check if RHS referenced the file in exactly the same way.
     62   bool isSameRef(DirectoryEntryRef RHS) const { return ME == RHS.ME; }
     63 
     64   DirectoryEntryRef() = delete;
     65   DirectoryEntryRef(const MapEntry &ME) : ME(&ME) {}
     66 
     67   /// Allow DirectoryEntryRef to degrade into 'const DirectoryEntry*' to
     68   /// facilitate incremental adoption.
     69   ///
     70   /// The goal is to avoid code churn due to dances like the following:
     71   /// \code
     72   /// // Old code.
     73   /// lvalue = rvalue;
     74   ///
     75   /// // Temporary code from an incremental patch.
     76   /// lvalue = &rvalue.getDirectoryEntry();
     77   ///
     78   /// // Final code.
     79   /// lvalue = rvalue;
     80   /// \endcode
     81   ///
     82   /// FIXME: Once DirectoryEntryRef is "everywhere" and DirectoryEntry::getName
     83   /// has been deleted, delete this implicit conversion.
     84   operator const DirectoryEntry *() const { return &getDirEntry(); }
     85 
     86 private:
     87   friend class FileMgr::MapEntryOptionalStorage<DirectoryEntryRef>;
     88   struct optional_none_tag {};
     89 
     90   // Private constructor for use by OptionalStorage.
     91   DirectoryEntryRef(optional_none_tag) : ME(nullptr) {}
     92   bool hasOptionalValue() const { return ME; }
     93 
     94   friend struct llvm::DenseMapInfo<DirectoryEntryRef>;
     95   struct dense_map_empty_tag {};
     96   struct dense_map_tombstone_tag {};
     97 
     98   // Private constructors for use by DenseMapInfo.
     99   DirectoryEntryRef(dense_map_empty_tag)
    100       : ME(llvm::DenseMapInfo<const MapEntry *>::getEmptyKey()) {}
    101   DirectoryEntryRef(dense_map_tombstone_tag)
    102       : ME(llvm::DenseMapInfo<const MapEntry *>::getTombstoneKey()) {}
    103   bool isSpecialDenseMapKey() const {
    104     return isSameRef(DirectoryEntryRef(dense_map_empty_tag())) ||
    105            isSameRef(DirectoryEntryRef(dense_map_tombstone_tag()));
    106   }
    107 
    108   const MapEntry *ME;
    109 };
    110 
    111 namespace FileMgr {
    112 
    113 /// Customized storage for refs derived from map entires in FileManager, using
    114 /// the private optional_none_tag to keep it to the size of a single pointer.
    115 template <class RefTy> class MapEntryOptionalStorage {
    116   using optional_none_tag = typename RefTy::optional_none_tag;
    117   RefTy MaybeRef;
    118 
    119 public:
    120   MapEntryOptionalStorage() : MaybeRef(optional_none_tag()) {}
    121 
    122   template <class... ArgTypes>
    123   explicit MapEntryOptionalStorage(llvm::in_place_t, ArgTypes &&...Args)
    124       : MaybeRef(std::forward<ArgTypes>(Args)...) {}
    125 
    126   void reset() { MaybeRef = optional_none_tag(); }
    127 
    128   bool hasValue() const { return MaybeRef.hasOptionalValue(); }
    129 
    130   RefTy &getValue() LLVM_LVALUE_FUNCTION {
    131     assert(hasValue());
    132     return MaybeRef;
    133   }
    134   RefTy const &getValue() const LLVM_LVALUE_FUNCTION {
    135     assert(hasValue());
    136     return MaybeRef;
    137   }
    138 #if LLVM_HAS_RVALUE_REFERENCE_THIS
    139   RefTy &&getValue() && {
    140     assert(hasValue());
    141     return std::move(MaybeRef);
    142   }
    143 #endif
    144 
    145   template <class... Args> void emplace(Args &&...args) {
    146     MaybeRef = RefTy(std::forward<Args>(args)...);
    147   }
    148 
    149   MapEntryOptionalStorage &operator=(RefTy Ref) {
    150     MaybeRef = Ref;
    151     return *this;
    152   }
    153 };
    154 
    155 } // end namespace FileMgr
    156 } // end namespace clang
    157 
    158 namespace llvm {
    159 namespace optional_detail {
    160 
    161 /// Customize OptionalStorage<DirectoryEntryRef> to use DirectoryEntryRef and
    162 /// its optional_none_tag to keep it the size of a single pointer.
    163 template <>
    164 class OptionalStorage<clang::DirectoryEntryRef>
    165     : public clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef> {
    166   using StorageImpl =
    167       clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef>;
    168 
    169 public:
    170   OptionalStorage() = default;
    171 
    172   template <class... ArgTypes>
    173   explicit OptionalStorage(in_place_t, ArgTypes &&...Args)
    174       : StorageImpl(in_place_t{}, std::forward<ArgTypes>(Args)...) {}
    175 
    176   OptionalStorage &operator=(clang::DirectoryEntryRef Ref) {
    177     StorageImpl::operator=(Ref);
    178     return *this;
    179   }
    180 };
    181 
    182 static_assert(sizeof(Optional<clang::DirectoryEntryRef>) ==
    183                   sizeof(clang::DirectoryEntryRef),
    184               "Optional<DirectoryEntryRef> must avoid size overhead");
    185 
    186 static_assert(
    187     std::is_trivially_copyable<Optional<clang::DirectoryEntryRef>>::value,
    188     "Optional<DirectoryEntryRef> should be trivially copyable");
    189 
    190 } // end namespace optional_detail
    191 
    192 /// Specialisation of DenseMapInfo for DirectoryEntryRef.
    193 template <> struct DenseMapInfo<clang::DirectoryEntryRef> {
    194   static inline clang::DirectoryEntryRef getEmptyKey() {
    195     return clang::DirectoryEntryRef(
    196         clang::DirectoryEntryRef::dense_map_empty_tag());
    197   }
    198 
    199   static inline clang::DirectoryEntryRef getTombstoneKey() {
    200     return clang::DirectoryEntryRef(
    201         clang::DirectoryEntryRef::dense_map_tombstone_tag());
    202   }
    203 
    204   static unsigned getHashValue(clang::DirectoryEntryRef Val) {
    205     return hash_value(Val);
    206   }
    207 
    208   static bool isEqual(clang::DirectoryEntryRef LHS,
    209                       clang::DirectoryEntryRef RHS) {
    210     // Catch the easy cases: both empty, both tombstone, or the same ref.
    211     if (LHS.isSameRef(RHS))
    212       return true;
    213 
    214     // Confirm LHS and RHS are valid.
    215     if (LHS.isSpecialDenseMapKey() || RHS.isSpecialDenseMapKey())
    216       return false;
    217 
    218     // It's safe to use operator==.
    219     return LHS == RHS;
    220   }
    221 };
    222 
    223 } // end namespace llvm
    224 
    225 namespace clang {
    226 
    227 /// Wrapper around Optional<DirectoryEntryRef> that degrades to 'const
    228 /// DirectoryEntry*', facilitating incremental patches to propagate
    229 /// DirectoryEntryRef.
    230 ///
    231 /// This class can be used as return value or field where it's convenient for
    232 /// an Optional<DirectoryEntryRef> to degrade to a 'const DirectoryEntry*'. The
    233 /// purpose is to avoid code churn due to dances like the following:
    234 /// \code
    235 /// // Old code.
    236 /// lvalue = rvalue;
    237 ///
    238 /// // Temporary code from an incremental patch.
    239 /// Optional<DirectoryEntryRef> MaybeF = rvalue;
    240 /// lvalue = MaybeF ? &MaybeF.getDirectoryEntry() : nullptr;
    241 ///
    242 /// // Final code.
    243 /// lvalue = rvalue;
    244 /// \endcode
    245 ///
    246 /// FIXME: Once DirectoryEntryRef is "everywhere" and DirectoryEntry::LastRef
    247 /// and DirectoryEntry::getName have been deleted, delete this class and
    248 /// replace instances with Optional<DirectoryEntryRef>.
    249 class OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr
    250     : public Optional<DirectoryEntryRef> {
    251 public:
    252   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr() = default;
    253   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(
    254       OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &&) = default;
    255   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(
    256       const OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &) = default;
    257   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
    258   operator=(OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &&) = default;
    259   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
    260   operator=(const OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &) = default;
    261 
    262   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(llvm::NoneType) {}
    263   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(DirectoryEntryRef Ref)
    264       : Optional<DirectoryEntryRef>(Ref) {}
    265   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(Optional<DirectoryEntryRef> MaybeRef)
    266       : Optional<DirectoryEntryRef>(MaybeRef) {}
    267 
    268   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &operator=(llvm::NoneType) {
    269     Optional<DirectoryEntryRef>::operator=(None);
    270     return *this;
    271   }
    272   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &operator=(DirectoryEntryRef Ref) {
    273     Optional<DirectoryEntryRef>::operator=(Ref);
    274     return *this;
    275   }
    276   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
    277   operator=(Optional<DirectoryEntryRef> MaybeRef) {
    278     Optional<DirectoryEntryRef>::operator=(MaybeRef);
    279     return *this;
    280   }
    281 
    282   /// Degrade to 'const DirectoryEntry *' to allow  DirectoryEntry::LastRef and
    283   /// DirectoryEntry::getName have been deleted, delete this class and replace
    284   /// instances with Optional<DirectoryEntryRef>
    285   operator const DirectoryEntry *() const {
    286     return hasValue() ? &getValue().getDirEntry() : nullptr;
    287   }
    288 };
    289 
    290 static_assert(std::is_trivially_copyable<
    291                   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr>::value,
    292               "OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr should be "
    293               "trivially copyable");
    294 
    295 } // end namespace clang
    296 
    297 #endif // LLVM_CLANG_BASIC_DIRECTORYENTRY_H
    298