//===- clang/Basic/DirectoryEntry.h - Directory 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::DirectoryEntry and clang::DirectoryEntryRef.
 
///
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CLANG_BASIC_DIRECTORYENTRY_H
 
#define LLVM_CLANG_BASIC_DIRECTORYENTRY_H
 
 
 
#include "clang/Basic/CustomizableOptional.h"
 
#include "clang/Basic/LLVM.h"
 
#include "llvm/ADT/DenseMapInfo.h"
 
#include "llvm/ADT/Hashing.h"
 
#include "llvm/ADT/STLExtras.h"
 
#include "llvm/ADT/StringMap.h"
 
#include "llvm/ADT/StringRef.h"
 
#include "llvm/Support/ErrorOr.h"
 
 
 
#include <optional>
 
#include <utility>
 
 
 
namespace clang {
 
namespace FileMgr {
 
 
 
template <class RefTy> class MapEntryOptionalStorage;
 
 
 
} // end namespace FileMgr
 
 
 
/// Cached information about one directory (either on disk or in
 
/// the virtual file system).
 
class DirectoryEntry {
 
  DirectoryEntry() = default;
 
  DirectoryEntry(const DirectoryEntry &) = delete;
 
  DirectoryEntry &operator=(const DirectoryEntry &) = delete;
 
  friend class FileManager;
 
  friend class FileEntryTestHelper;
 
 
 
  // FIXME: We should not be storing a directory entry name here.
 
  StringRef Name; // Name of the directory.
 
 
 
public:
 
  StringRef getName() const { return Name; }
 
};
 
 
 
/// A reference to a \c DirectoryEntry  that includes the name of the directory
 
/// as it was accessed by the FileManager's client.
 
class DirectoryEntryRef {
 
public:
 
  const DirectoryEntry &getDirEntry() const { return *ME->getValue(); }
 
 
 
  StringRef getName() const { return ME->getKey(); }
 
 
 
  /// Hash code is based on the DirectoryEntry, not the specific named
 
  /// reference.
 
  friend llvm::hash_code hash_value(DirectoryEntryRef Ref) {
 
    return llvm::hash_value(&Ref.getDirEntry());
 
  }
 
 
 
  using MapEntry = llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>>;
 
 
 
  const MapEntry &getMapEntry() const { return *ME; }
 
 
 
  /// Check if RHS referenced the file in exactly the same way.
 
  bool isSameRef(DirectoryEntryRef RHS) const { return ME == RHS.ME; }
 
 
 
  DirectoryEntryRef() = delete;
 
  DirectoryEntryRef(const MapEntry &ME) : ME(&ME) {}
 
 
 
  /// Allow DirectoryEntryRef to degrade into 'const DirectoryEntry*' to
 
  /// facilitate incremental adoption.
 
  ///
 
  /// The goal is to avoid code churn due to dances like the following:
 
  /// \code
 
  /// // Old code.
 
  /// lvalue = rvalue;
 
  ///
 
  /// // Temporary code from an incremental patch.
 
  /// lvalue = &rvalue.getDirectoryEntry();
 
  ///
 
  /// // Final code.
 
  /// lvalue = rvalue;
 
  /// \endcode
 
  ///
 
  /// FIXME: Once DirectoryEntryRef is "everywhere" and DirectoryEntry::getName
 
  /// has been deleted, delete this implicit conversion.
 
  operator const DirectoryEntry *() const { return &getDirEntry(); }
 
 
 
private:
 
  friend class FileMgr::MapEntryOptionalStorage<DirectoryEntryRef>;
 
  struct optional_none_tag {};
 
 
 
  // Private constructor for use by OptionalStorage.
 
  DirectoryEntryRef(optional_none_tag) : ME(nullptr) {}
 
  bool hasOptionalValue() const { return ME; }
 
 
 
  friend struct llvm::DenseMapInfo<DirectoryEntryRef>;
 
  struct dense_map_empty_tag {};
 
  struct dense_map_tombstone_tag {};
 
 
 
  // Private constructors for use by DenseMapInfo.
 
  DirectoryEntryRef(dense_map_empty_tag)
 
      : ME(llvm::DenseMapInfo<const MapEntry *>::getEmptyKey()) {}
 
  DirectoryEntryRef(dense_map_tombstone_tag)
 
      : ME(llvm::DenseMapInfo<const MapEntry *>::getTombstoneKey()) {}
 
  bool isSpecialDenseMapKey() const {
 
    return isSameRef(DirectoryEntryRef(dense_map_empty_tag())) ||
 
           isSameRef(DirectoryEntryRef(dense_map_tombstone_tag()));
 
  }
 
 
 
  const MapEntry *ME;
 
};
 
 
 
using OptionalDirectoryEntryRef = CustomizableOptional<DirectoryEntryRef>;
 
 
 
namespace FileMgr {
 
 
 
/// Customized storage for refs derived from map entires in FileManager, using
 
/// the private optional_none_tag to keep it to the size of a single pointer.
 
template <class RefTy> class MapEntryOptionalStorage {
 
  using optional_none_tag = typename RefTy::optional_none_tag;
 
  RefTy MaybeRef;
 
 
 
public:
 
  MapEntryOptionalStorage() : MaybeRef(optional_none_tag()) {}
 
 
 
  template <class... ArgTypes>
 
  explicit MapEntryOptionalStorage(std::in_place_t, ArgTypes &&...Args)
 
      : MaybeRef(std::forward<ArgTypes>(Args)...) {}
 
 
 
  void reset() { MaybeRef = optional_none_tag(); }
 
 
 
  bool has_value() const { return MaybeRef.hasOptionalValue(); }
 
 
 
  RefTy &value() & {
 
    assert(has_value());
 
    return MaybeRef;
 
  }
 
  RefTy const &value() const & {
 
    assert(has_value());
 
    return MaybeRef;
 
  }
 
  RefTy &&value() && {
 
    assert(has_value());
 
    return std::move(MaybeRef);
 
  }
 
 
 
  template <class... Args> void emplace(Args &&...args) {
 
    MaybeRef = RefTy(std::forward<Args>(args)...);
 
  }
 
 
 
  MapEntryOptionalStorage &operator=(RefTy Ref) {
 
    MaybeRef = Ref;
 
    return *this;
 
  }
 
};
 
 
 
} // end namespace FileMgr
 
 
 
namespace optional_detail {
 
 
 
/// Customize OptionalStorage<DirectoryEntryRef> to use DirectoryEntryRef and
 
/// its optional_none_tag to keep it the size of a single pointer.
 
template <>
 
class OptionalStorage<clang::DirectoryEntryRef>
 
    : public clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef> {
 
  using StorageImpl =
 
      clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef>;
 
 
 
public:
 
  OptionalStorage() = default;
 
 
 
  template <class... ArgTypes>
 
  explicit OptionalStorage(std::in_place_t, ArgTypes &&...Args)
 
      : StorageImpl(std::in_place_t{}, std::forward<ArgTypes>(Args)...) {}
 
 
 
  OptionalStorage &operator=(clang::DirectoryEntryRef Ref) {
 
    StorageImpl::operator=(Ref);
 
    return *this;
 
  }
 
};
 
 
 
static_assert(sizeof(OptionalDirectoryEntryRef) == sizeof(DirectoryEntryRef),
 
              "OptionalDirectoryEntryRef must avoid size overhead");
 
 
 
static_assert(std::is_trivially_copyable<OptionalDirectoryEntryRef>::value,
 
              "OptionalDirectoryEntryRef should be trivially copyable");
 
 
 
} // end namespace optional_detail
 
} // namespace clang
 
 
 
namespace llvm {
 
/// Specialisation of DenseMapInfo for DirectoryEntryRef.
 
template <> struct DenseMapInfo<clang::DirectoryEntryRef> {
 
  static inline clang::DirectoryEntryRef getEmptyKey() {
 
    return clang::DirectoryEntryRef(
 
        clang::DirectoryEntryRef::dense_map_empty_tag());
 
  }
 
 
 
  static inline clang::DirectoryEntryRef getTombstoneKey() {
 
    return clang::DirectoryEntryRef(
 
        clang::DirectoryEntryRef::dense_map_tombstone_tag());
 
  }
 
 
 
  static unsigned getHashValue(clang::DirectoryEntryRef Val) {
 
    return hash_value(Val);
 
  }
 
 
 
  static bool isEqual(clang::DirectoryEntryRef LHS,
 
                      clang::DirectoryEntryRef RHS) {
 
    // Catch the easy cases: both empty, both tombstone, or the same ref.
 
    if (LHS.isSameRef(RHS))
 
      return true;
 
 
 
    // Confirm LHS and RHS are valid.
 
    if (LHS.isSpecialDenseMapKey() || RHS.isSpecialDenseMapKey())
 
      return false;
 
 
 
    // It's safe to use operator==.
 
    return LHS == RHS;
 
  }
 
};
 
 
 
} // end namespace llvm
 
 
 
namespace clang {
 
 
 
/// Wrapper around OptionalDirectoryEntryRef that degrades to 'const
 
/// DirectoryEntry*', facilitating incremental patches to propagate
 
/// DirectoryEntryRef.
 
///
 
/// This class can be used as return value or field where it's convenient for
 
/// an OptionalDirectoryEntryRef to degrade to a 'const DirectoryEntry*'. The
 
/// purpose is to avoid code churn due to dances like the following:
 
/// \code
 
/// // Old code.
 
/// lvalue = rvalue;
 
///
 
/// // Temporary code from an incremental patch.
 
/// OptionalDirectoryEntryRef MaybeF = rvalue;
 
/// lvalue = MaybeF ? &MaybeF.getDirectoryEntry() : nullptr;
 
///
 
/// // Final code.
 
/// lvalue = rvalue;
 
/// \endcode
 
///
 
/// FIXME: Once DirectoryEntryRef is "everywhere" and DirectoryEntry::LastRef
 
/// and DirectoryEntry::getName have been deleted, delete this class and
 
/// replace instances with OptionalDirectoryEntryRef.
 
class OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr
 
    : public OptionalDirectoryEntryRef {
 
public:
 
  OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr() = default;
 
  OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(
 
      OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &&) = default;
 
  OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(
 
      const OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &) = default;
 
  OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
 
  operator=(OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &&) = default;
 
  OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
 
  operator=(const OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &) = default;
 
 
 
  OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(std::nullopt_t) {}
 
  OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(DirectoryEntryRef Ref)
 
      : OptionalDirectoryEntryRef(Ref) {}
 
  OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(
 
      OptionalDirectoryEntryRef MaybeRef)
 
      : OptionalDirectoryEntryRef(MaybeRef) {}
 
 
 
  OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
 
  operator=(std::nullopt_t) {
 
    OptionalDirectoryEntryRef::operator=(std::nullopt);
 
    return *this;
 
  }
 
  OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &operator=(DirectoryEntryRef Ref) {
 
    OptionalDirectoryEntryRef::operator=(Ref);
 
    return *this;
 
  }
 
  OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
 
  operator=(OptionalDirectoryEntryRef MaybeRef) {
 
    OptionalDirectoryEntryRef::operator=(MaybeRef);
 
    return *this;
 
  }
 
 
 
  /// Degrade to 'const DirectoryEntry *' to allow  DirectoryEntry::LastRef and
 
  /// DirectoryEntry::getName have been deleted, delete this class and replace
 
  /// instances with OptionalDirectoryEntryRef
 
  operator const DirectoryEntry *() const {
 
    return has_value() ? &(*this)->getDirEntry() : nullptr;
 
  }
 
};
 
 
 
static_assert(std::is_trivially_copyable<
 
                  OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr>::value,
 
              "OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr should be "
 
              "trivially copyable");
 
 
 
} // end namespace clang
 
 
 
#endif // LLVM_CLANG_BASIC_DIRECTORYENTRY_H