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