]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/llvm/tools/clang/include/clang/AST/ASTTypeTraits.h
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / llvm / tools / clang / include / clang / AST / ASTTypeTraits.h
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 dynamically typed node container that can be used to store
11 //  an AST base node at runtime in the same storage in a type safe way.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #ifndef LLVM_CLANG_AST_AST_TYPE_TRAITS_H
16 #define LLVM_CLANG_AST_AST_TYPE_TRAITS_H
17
18 #include "clang/AST/Decl.h"
19 #include "clang/AST/Stmt.h"
20 #include "clang/AST/TypeLoc.h"
21 #include "llvm/Support/AlignOf.h"
22
23 namespace clang {
24 namespace ast_type_traits {
25
26 /// \brief A dynamically typed AST node container.
27 ///
28 /// Stores an AST node in a type safe way. This allows writing code that
29 /// works with different kinds of AST nodes, despite the fact that they don't
30 /// have a common base class.
31 ///
32 /// Use \c create(Node) to create a \c DynTypedNode from an AST node,
33 /// and \c get<T>() to retrieve the node as type T if the types match.
34 ///
35 /// See \c NodeTypeTag for which node base types are currently supported;
36 /// You can create DynTypedNodes for all nodes in the inheritance hierarchy of
37 /// the supported base types.
38 class DynTypedNode {
39 public:
40   /// \brief Creates a \c DynTypedNode from \c Node.
41   template <typename T>
42   static DynTypedNode create(const T &Node) {
43     return BaseConverter<T>::create(Node);
44   }
45
46   /// \brief Retrieve the stored node as type \c T.
47   ///
48   /// Returns NULL if the stored node does not have a type that is
49   /// convertible to \c T.
50   ///
51   /// For types that have identity via their pointer in the AST
52   /// (like \c Stmt and \c Decl) the returned pointer points to the
53   /// referenced AST node.
54   /// For other types (like \c QualType) the value is stored directly
55   /// in the \c DynTypedNode, and the returned pointer points at
56   /// the storage inside DynTypedNode. For those nodes, do not
57   /// use the pointer outside the scope of the DynTypedNode.
58   template <typename T>
59   const T *get() const {
60     return BaseConverter<T>::get(Tag, Storage.buffer);
61   }
62
63   /// \brief Returns a pointer that identifies the stored AST node.
64   ///
65   /// Note that this is not supported by all AST nodes. For AST nodes
66   /// that don't have a pointer-defined identity inside the AST, this
67   /// method returns NULL.
68   const void *getMemoizationData() const;
69
70 private:
71   /// \brief Takes care of converting from and to \c T.
72   template <typename T, typename EnablerT = void> struct BaseConverter;
73
74   /// \brief Supported base node types.
75   enum NodeTypeTag {
76     NT_Decl,
77     NT_Stmt,
78     NT_NestedNameSpecifier,
79     NT_NestedNameSpecifierLoc,
80     NT_QualType,
81     NT_Type,
82     NT_TypeLoc
83   } Tag;
84
85   /// \brief Stores the data of the node.
86   ///
87   /// Note that we can store \c Decls and \c Stmts by pointer as they are
88   /// guaranteed to be unique pointers pointing to dedicated storage in the
89   /// AST. \c QualTypes on the other hand do not have storage or unique
90   /// pointers and thus need to be stored by value.
91   llvm::AlignedCharArrayUnion<Decl *, Stmt *, NestedNameSpecifier,
92                               NestedNameSpecifierLoc, QualType, Type,
93                               TypeLoc> Storage;
94 };
95
96 // FIXME: Pull out abstraction for the following.
97 template<typename T> struct DynTypedNode::BaseConverter<T,
98     typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> {
99   static const T *get(NodeTypeTag Tag, const char Storage[]) {
100     if (Tag == NT_Decl)
101       return dyn_cast<T>(*reinterpret_cast<Decl*const*>(Storage));
102     return NULL;
103   }
104   static DynTypedNode create(const Decl &Node) {
105     DynTypedNode Result;
106     Result.Tag = NT_Decl;
107     new (Result.Storage.buffer) const Decl*(&Node);
108     return Result;
109   }
110 };
111 template<typename T> struct DynTypedNode::BaseConverter<T,
112     typename llvm::enable_if<llvm::is_base_of<Stmt, T> >::type> {
113   static const T *get(NodeTypeTag Tag, const char Storage[]) {
114     if (Tag == NT_Stmt)
115       return dyn_cast<T>(*reinterpret_cast<Stmt*const*>(Storage));
116     return NULL;
117   }
118   static DynTypedNode create(const Stmt &Node) {
119     DynTypedNode Result;
120     Result.Tag = NT_Stmt;
121     new (Result.Storage.buffer) const Stmt*(&Node);
122     return Result;
123   }
124 };
125 template<typename T> struct DynTypedNode::BaseConverter<T,
126     typename llvm::enable_if<llvm::is_base_of<Type, T> >::type> {
127   static const T *get(NodeTypeTag Tag, const char Storage[]) {
128     if (Tag == NT_Type)
129       return dyn_cast<T>(*reinterpret_cast<Type*const*>(Storage));
130     return NULL;
131   }
132   static DynTypedNode create(const Type &Node) {
133     DynTypedNode Result;
134     Result.Tag = NT_Type;
135     new (Result.Storage.buffer) const Type*(&Node);
136     return Result;
137   }
138 };
139 template<> struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> {
140   static const NestedNameSpecifier *get(NodeTypeTag Tag, const char Storage[]) {
141     if (Tag == NT_NestedNameSpecifier)
142       return *reinterpret_cast<NestedNameSpecifier*const*>(Storage);
143     return NULL;
144   }
145   static DynTypedNode create(const NestedNameSpecifier &Node) {
146     DynTypedNode Result;
147     Result.Tag = NT_NestedNameSpecifier;
148     new (Result.Storage.buffer) const NestedNameSpecifier*(&Node);
149     return Result;
150   }
151 };
152 template<> struct DynTypedNode::BaseConverter<NestedNameSpecifierLoc, void> {
153   static const NestedNameSpecifierLoc *get(NodeTypeTag Tag,
154                                            const char Storage[]) {
155     if (Tag == NT_NestedNameSpecifierLoc)
156       return reinterpret_cast<const NestedNameSpecifierLoc*>(Storage);
157     return NULL;
158   }
159   static DynTypedNode create(const NestedNameSpecifierLoc &Node) {
160     DynTypedNode Result;
161     Result.Tag = NT_NestedNameSpecifierLoc;
162     new (Result.Storage.buffer) NestedNameSpecifierLoc(Node);
163     return Result;
164   }
165 };
166 template<> struct DynTypedNode::BaseConverter<QualType, void> {
167   static const QualType *get(NodeTypeTag Tag, const char Storage[]) {
168     if (Tag == NT_QualType)
169       return reinterpret_cast<const QualType*>(Storage);
170     return NULL;
171   }
172   static DynTypedNode create(const QualType &Node) {
173     DynTypedNode Result;
174     Result.Tag = NT_QualType;
175     new (Result.Storage.buffer) QualType(Node);
176     return Result;
177   }
178 };
179 template<> struct DynTypedNode::BaseConverter<TypeLoc, void> {
180   static const TypeLoc *get(NodeTypeTag Tag, const char Storage[]) {
181     if (Tag == NT_TypeLoc)
182       return reinterpret_cast<const TypeLoc*>(Storage);
183     return NULL;
184   }
185   static DynTypedNode create(const TypeLoc &Node) {
186     DynTypedNode Result;
187     Result.Tag = NT_TypeLoc;
188     new (Result.Storage.buffer) TypeLoc(Node);
189     return Result;
190   }
191 };
192 // The only operation we allow on unsupported types is \c get.
193 // This allows to conveniently use \c DynTypedNode when having an arbitrary
194 // AST node that is not supported, but prevents misuse - a user cannot create
195 // a DynTypedNode from arbitrary types.
196 template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {
197   static const T *get(NodeTypeTag Tag, const char Storage[]) { return NULL; }
198 };
199
200 inline const void *DynTypedNode::getMemoizationData() const {
201   switch (Tag) {
202     case NT_Decl: return BaseConverter<Decl>::get(Tag, Storage.buffer);
203     case NT_Stmt: return BaseConverter<Stmt>::get(Tag, Storage.buffer);
204     default: return NULL;
205   };
206 }
207
208 } // end namespace ast_type_traits
209 } // end namespace clang
210
211 #endif // LLVM_CLANG_AST_AST_TYPE_TRAITS_H