ASTTypeTraits.h revision cf52ca6bb6dd76a1bd967bc422287fafafa1e45a
1//===--- ASTTypeTraits.h ----------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10//  Provides a dynamic type identifier and a dynamically typed node container
11//  that can be used to store an AST base node at runtime in the same storage in
12//  a type safe way.
13//
14//===----------------------------------------------------------------------===//
15
16#ifndef LLVM_CLANG_AST_AST_TYPE_TRAITS_H
17#define LLVM_CLANG_AST_AST_TYPE_TRAITS_H
18
19#include "clang/AST/ASTFwd.h"
20#include "clang/AST/Decl.h"
21#include "clang/AST/Stmt.h"
22#include "clang/AST/TypeLoc.h"
23#include "clang/Basic/LLVM.h"
24#include "llvm/Support/AlignOf.h"
25
26namespace clang {
27namespace ast_type_traits {
28
29/// \brief Kind identifier.
30///
31/// It can be constructed from any node kind and allows for runtime type
32/// hierarchy checks.
33/// Use getFromNodeKind<T>() to construct them.
34class ASTNodeKind {
35public:
36  /// \brief Empty identifier. It matches nothing.
37  ASTNodeKind() : KindId(NKI_None) {}
38
39  /// \brief Construct an identifier for T.
40  template <class T>
41  static ASTNodeKind getFromNodeKind() {
42    return ASTNodeKind(KindToKindId<T>::Id);
43  }
44
45  /// \brief Returns \c true if \c this and \c Other represent the same kind.
46  bool isSame(ASTNodeKind Other) const;
47
48  /// \brief Returns \c true if \c this is a base kind of (or same as) \c Other
49  bool isBaseOf(ASTNodeKind Other) const;
50
51  /// \brief String representation of the kind.
52  StringRef asStringRef() const;
53
54private:
55  /// \brief Kind ids.
56  ///
57  /// Includes all possible base and derived kinds.
58  enum NodeKindId {
59    NKI_None,
60    NKI_NestedNameSpecifier,
61    NKI_NestedNameSpecifierLoc,
62    NKI_QualType,
63    NKI_TypeLoc,
64    NKI_Decl,
65#define DECL(DERIVED, BASE) NKI_##DERIVED##Decl,
66#include "clang/AST/DeclNodes.inc"
67    NKI_Stmt,
68#define STMT(DERIVED, BASE) NKI_##DERIVED,
69#include "clang/AST/StmtNodes.inc"
70    NKI_Type,
71#define TYPE(DERIVED, BASE) NKI_##DERIVED##Type,
72#include "clang/AST/TypeNodes.def"
73    NKI_NumberOfKinds
74  };
75
76  /// \brief Use getFromNodeKind<T>() to construct the kind.
77  ASTNodeKind(NodeKindId KindId) : KindId(KindId) {}
78
79  /// \brief Returns \c true if \c Base is a base kind of (or same as) \c
80  ///   Derived
81  static bool isBaseOf(NodeKindId Base, NodeKindId Derived);
82
83  /// \brief Helper meta-function to convert a kind T to its enum value.
84  ///
85  /// This struct is specialized below for all known kinds.
86  template <class T> struct KindToKindId {
87    static const NodeKindId Id = NKI_None;
88  };
89
90  /// \brief Per kind info.
91  struct KindInfo {
92    /// \brief The id of the parent kind, or None if it has no parent.
93    NodeKindId ParentId;
94    /// \brief Name of the kind.
95    const char *Name;
96  };
97  static const KindInfo AllKindInfo[NKI_NumberOfKinds];
98
99  NodeKindId KindId;
100};
101
102#define KIND_TO_KIND_ID(Class)                                                 \
103  template <> struct ASTNodeKind::KindToKindId<Class> {                        \
104    static const NodeKindId Id = NKI_##Class;                                  \
105  };
106KIND_TO_KIND_ID(NestedNameSpecifier)
107KIND_TO_KIND_ID(NestedNameSpecifierLoc)
108KIND_TO_KIND_ID(QualType)
109KIND_TO_KIND_ID(TypeLoc)
110KIND_TO_KIND_ID(Decl)
111KIND_TO_KIND_ID(Stmt)
112KIND_TO_KIND_ID(Type)
113#define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl)
114#include "clang/AST/DeclNodes.inc"
115#define STMT(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED)
116#include "clang/AST/StmtNodes.inc"
117#define TYPE(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Type)
118#include "clang/AST/TypeNodes.def"
119#undef KIND_TO_KIND_ID
120
121/// \brief A dynamically typed AST node container.
122///
123/// Stores an AST node in a type safe way. This allows writing code that
124/// works with different kinds of AST nodes, despite the fact that they don't
125/// have a common base class.
126///
127/// Use \c create(Node) to create a \c DynTypedNode from an AST node,
128/// and \c get<T>() to retrieve the node as type T if the types match.
129///
130/// See \c NodeTypeTag for which node base types are currently supported;
131/// You can create DynTypedNodes for all nodes in the inheritance hierarchy of
132/// the supported base types.
133class DynTypedNode {
134public:
135  /// \brief Creates a \c DynTypedNode from \c Node.
136  template <typename T>
137  static DynTypedNode create(const T &Node) {
138    return BaseConverter<T>::create(Node);
139  }
140
141  /// \brief Retrieve the stored node as type \c T.
142  ///
143  /// Returns NULL if the stored node does not have a type that is
144  /// convertible to \c T.
145  ///
146  /// For types that have identity via their pointer in the AST
147  /// (like \c Stmt, \c Decl, \c Type and \c NestedNameSpecifier) the returned
148  /// pointer points to the referenced AST node.
149  /// For other types (like \c QualType) the value is stored directly
150  /// in the \c DynTypedNode, and the returned pointer points at
151  /// the storage inside DynTypedNode. For those nodes, do not
152  /// use the pointer outside the scope of the DynTypedNode.
153  template <typename T>
154  const T *get() const {
155    return BaseConverter<T>::get(NodeKind, Storage.buffer);
156  }
157
158  /// \brief Returns a pointer that identifies the stored AST node.
159  ///
160  /// Note that this is not supported by all AST nodes. For AST nodes
161  /// that don't have a pointer-defined identity inside the AST, this
162  /// method returns NULL.
163  const void *getMemoizationData() const;
164
165  /// @{
166  /// \brief Imposes an order on \c DynTypedNode.
167  ///
168  /// Supports comparison of nodes that support memoization.
169  /// FIXME: Implement comparsion for other node types (currently
170  /// only Stmt, Decl, Type and NestedNameSpecifier return memoization data).
171  bool operator<(const DynTypedNode &Other) const {
172    assert(getMemoizationData() && Other.getMemoizationData());
173    return getMemoizationData() < Other.getMemoizationData();
174  }
175  bool operator==(const DynTypedNode &Other) const {
176    // Nodes with different types cannot be equal.
177    if (!NodeKind.isSame(Other.NodeKind))
178      return false;
179
180    // FIXME: Implement for other types.
181    if (ASTNodeKind::getFromNodeKind<QualType>().isBaseOf(NodeKind)) {
182      return *get<QualType>() == *Other.get<QualType>();
183    }
184    assert(getMemoizationData() && Other.getMemoizationData());
185    return getMemoizationData() == Other.getMemoizationData();
186  }
187  bool operator!=(const DynTypedNode &Other) const {
188    return !operator==(Other);
189  }
190  /// @}
191
192private:
193  /// \brief Takes care of converting from and to \c T.
194  template <typename T, typename EnablerT = void> struct BaseConverter;
195
196  ASTNodeKind NodeKind;
197
198  /// \brief Stores the data of the node.
199  ///
200  /// Note that we can store \c Decls, \c Stmts, \c Types and
201  /// \c NestedNameSpecifiers by pointer as they are guaranteed to be unique
202  /// pointers pointing to dedicated storage in the AST. \c QualTypes on the
203  /// other hand do not have storage or unique pointers and thus need to be
204  /// stored by value.
205  llvm::AlignedCharArrayUnion<Decl *, Stmt *, Type *, NestedNameSpecifier *,
206                              NestedNameSpecifierLoc, QualType, TypeLoc>
207      Storage;
208};
209
210// FIXME: Pull out abstraction for the following.
211template<typename T> struct DynTypedNode::BaseConverter<T,
212    typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> {
213  static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
214    if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(NodeKind))
215      return dyn_cast<T>(*reinterpret_cast<Decl*const*>(Storage));
216    return NULL;
217  }
218  static DynTypedNode create(const Decl &Node) {
219    DynTypedNode Result;
220    Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
221    new (Result.Storage.buffer) const Decl*(&Node);
222    return Result;
223  }
224};
225template<typename T> struct DynTypedNode::BaseConverter<T,
226    typename llvm::enable_if<llvm::is_base_of<Stmt, T> >::type> {
227  static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
228    if (ASTNodeKind::getFromNodeKind<Stmt>().isBaseOf(NodeKind))
229      return dyn_cast<T>(*reinterpret_cast<Stmt*const*>(Storage));
230    return NULL;
231  }
232  static DynTypedNode create(const Stmt &Node) {
233    DynTypedNode Result;
234    Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
235    new (Result.Storage.buffer) const Stmt*(&Node);
236    return Result;
237  }
238};
239template<typename T> struct DynTypedNode::BaseConverter<T,
240    typename llvm::enable_if<llvm::is_base_of<Type, T> >::type> {
241  static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
242    if (ASTNodeKind::getFromNodeKind<Type>().isBaseOf(NodeKind))
243      return dyn_cast<T>(*reinterpret_cast<Type*const*>(Storage));
244    return NULL;
245  }
246  static DynTypedNode create(const Type &Node) {
247    DynTypedNode Result;
248    Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
249    new (Result.Storage.buffer) const Type*(&Node);
250    return Result;
251  }
252};
253template<> struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> {
254  static const NestedNameSpecifier *get(ASTNodeKind NodeKind,
255                                        const char Storage[]) {
256    if (ASTNodeKind::getFromNodeKind<NestedNameSpecifier>().isBaseOf(NodeKind))
257      return *reinterpret_cast<NestedNameSpecifier*const*>(Storage);
258    return NULL;
259  }
260  static DynTypedNode create(const NestedNameSpecifier &Node) {
261    DynTypedNode Result;
262    Result.NodeKind = ASTNodeKind::getFromNodeKind<NestedNameSpecifier>();
263    new (Result.Storage.buffer) const NestedNameSpecifier*(&Node);
264    return Result;
265  }
266};
267template<> struct DynTypedNode::BaseConverter<NestedNameSpecifierLoc, void> {
268  static const NestedNameSpecifierLoc *get(ASTNodeKind NodeKind,
269                                           const char Storage[]) {
270    if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isBaseOf(
271            NodeKind))
272      return reinterpret_cast<const NestedNameSpecifierLoc*>(Storage);
273    return NULL;
274  }
275  static DynTypedNode create(const NestedNameSpecifierLoc &Node) {
276    DynTypedNode Result;
277    Result.NodeKind = ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>();
278    new (Result.Storage.buffer) NestedNameSpecifierLoc(Node);
279    return Result;
280  }
281};
282template<> struct DynTypedNode::BaseConverter<QualType, void> {
283  static const QualType *get(ASTNodeKind NodeKind, const char Storage[]) {
284    if (ASTNodeKind::getFromNodeKind<QualType>().isBaseOf(NodeKind))
285      return reinterpret_cast<const QualType*>(Storage);
286    return NULL;
287  }
288  static DynTypedNode create(const QualType &Node) {
289    DynTypedNode Result;
290    Result.NodeKind = ASTNodeKind::getFromNodeKind<QualType>();
291    new (Result.Storage.buffer) QualType(Node);
292    return Result;
293  }
294};
295template<> struct DynTypedNode::BaseConverter<TypeLoc, void> {
296  static const TypeLoc *get(ASTNodeKind NodeKind, const char Storage[]) {
297    if (ASTNodeKind::getFromNodeKind<TypeLoc>().isBaseOf(NodeKind))
298      return reinterpret_cast<const TypeLoc*>(Storage);
299    return NULL;
300  }
301  static DynTypedNode create(const TypeLoc &Node) {
302    DynTypedNode Result;
303    Result.NodeKind = ASTNodeKind::getFromNodeKind<TypeLoc>();
304    new (Result.Storage.buffer) TypeLoc(Node);
305    return Result;
306  }
307};
308// The only operation we allow on unsupported types is \c get.
309// This allows to conveniently use \c DynTypedNode when having an arbitrary
310// AST node that is not supported, but prevents misuse - a user cannot create
311// a DynTypedNode from arbitrary types.
312template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {
313  static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
314    return NULL;
315  }
316};
317
318inline const void *DynTypedNode::getMemoizationData() const {
319  if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(NodeKind)) {
320    return BaseConverter<Decl>::get(NodeKind, Storage.buffer);
321  } else if (ASTNodeKind::getFromNodeKind<Stmt>().isBaseOf(NodeKind)) {
322    return BaseConverter<Stmt>::get(NodeKind, Storage.buffer);
323  } else if (ASTNodeKind::getFromNodeKind<Type>().isBaseOf(NodeKind)) {
324    return BaseConverter<Type>::get(NodeKind, Storage.buffer);
325  } else if (ASTNodeKind::getFromNodeKind<NestedNameSpecifier>().isBaseOf(NodeKind)) {
326    return BaseConverter<NestedNameSpecifier>::get(NodeKind, Storage.buffer);
327  }
328  return NULL;
329}
330
331} // end namespace ast_type_traits
332} // end namespace clang
333
334#endif // LLVM_CLANG_AST_AST_TYPE_TRAITS_H
335