238 lines
7.3 KiB
C++
238 lines
7.3 KiB
C++
//===- 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;
|
|
};
|
|
|
|
/// 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;
|
|
explicit 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 = optional_none_tag();
|
|
|
|
public:
|
|
MapEntryOptionalStorage() = default;
|
|
|
|
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:
|
|
using StorageImpl::StorageImpl;
|
|
|
|
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 {
|
|
|
|
template <> struct PointerLikeTypeTraits<clang::DirectoryEntryRef> {
|
|
static inline void *getAsVoidPointer(clang::DirectoryEntryRef Dir) {
|
|
return const_cast<clang::DirectoryEntryRef::MapEntry *>(&Dir.getMapEntry());
|
|
}
|
|
|
|
static inline clang::DirectoryEntryRef getFromVoidPointer(void *Ptr) {
|
|
return clang::DirectoryEntryRef(
|
|
*reinterpret_cast<const clang::DirectoryEntryRef::MapEntry *>(Ptr));
|
|
}
|
|
|
|
static constexpr int NumLowBitsAvailable = PointerLikeTypeTraits<
|
|
const clang::DirectoryEntryRef::MapEntry *>::NumLowBitsAvailable;
|
|
};
|
|
|
|
/// 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
|
|
|
|
#endif // LLVM_CLANG_BASIC_DIRECTORYENTRY_H
|