Skip to content

Commit

Permalink
[AST] Add CanonicalDeclPtr<T>.
Browse files Browse the repository at this point in the history
Summary:
CanonicalDeclPtr<T> is just like a T*, except it calls
T::getCanonicalDecl() on construction.

This is useful as the key in a "set of canonical Decls" -- it's much
less error-prone than calling getCanonicalDecl() every time you touch
the set.

Reviewers: rnk

Subscribers: cfe-commits, tra

Differential Revision: https://reviews.llvm.org/D25703

llvm-svn: 284644
  • Loading branch information
Justin Lebar committed Oct 19, 2016
1 parent 9730ae9 commit 2271ba2
Showing 1 changed file with 63 additions and 1 deletion.
64 changes: 63 additions & 1 deletion clang/include/clang/AST/Redeclarable.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,68 @@ class Mergeable {
bool isFirstDecl() const { return getFirstDecl() == this; }
};

}
/// A wrapper class around a pointer that always points to its canonical
/// declaration.
///
/// CanonicalDeclPtr<decl_type> behaves just like decl_type*, except we call
/// decl_type::getCanonicalDecl() on construction.
///
/// This is useful for hashtables that you want to be keyed on a declaration's
/// canonical decl -- if you use CanonicalDeclPtr as the key, you don't need to
/// remember to call getCanonicalDecl() everywhere.
template <typename decl_type> class CanonicalDeclPtr {
public:
CanonicalDeclPtr() : Ptr(nullptr) {}
CanonicalDeclPtr(decl_type *Ptr)
: Ptr(Ptr ? Ptr->getCanonicalDecl() : nullptr) {}
CanonicalDeclPtr(const CanonicalDeclPtr &) = default;
CanonicalDeclPtr &operator=(const CanonicalDeclPtr &) = default;

operator decl_type *() { return Ptr; }
operator const decl_type *() const { return Ptr; }

decl_type *operator->() { return Ptr; }
const decl_type *operator->() const { return Ptr; }

decl_type &operator*() { return *Ptr; }
const decl_type &operator*() const { return *Ptr; }

private:
friend struct llvm::DenseMapInfo<CanonicalDeclPtr<decl_type>>;

decl_type *Ptr;
};
} // namespace clang

namespace llvm {
template <typename decl_type>
struct DenseMapInfo<clang::CanonicalDeclPtr<decl_type>> {
using CanonicalDeclPtr = clang::CanonicalDeclPtr<decl_type>;
using BaseInfo = DenseMapInfo<decl_type *>;

static CanonicalDeclPtr getEmptyKey() {
// Construct our CanonicalDeclPtr this way because the regular constructor
// would dereference P.Ptr, which is not allowed.
CanonicalDeclPtr P;
P.Ptr = BaseInfo::getEmptyKey();
return P;
}

static CanonicalDeclPtr getTombstoneKey() {
CanonicalDeclPtr P;
P.Ptr = BaseInfo::getTombstoneKey();
return P;
}

static unsigned getHashValue(const CanonicalDeclPtr &P) {
return BaseInfo::getHashValue(P);
}

static bool isEqual(const CanonicalDeclPtr &LHS,
const CanonicalDeclPtr &RHS) {
return BaseInfo::isEqual(LHS, RHS);
}
};
} // namespace llvm

#endif

0 comments on commit 2271ba2

Please sign in to comment.