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