r184331 - Enhancements for the DynTypedNode

Samuel Benzaquen sbenza at google.com
Wed Jun 19 11:45:25 PDT 2013


Author: sbenza
Date: Wed Jun 19 13:45:24 2013
New Revision: 184331

URL: http://llvm.org/viewvc/llvm-project?rev=184331&view=rev
Log:
Enhancements for the DynTypedNode

Added ASTNodeKind as a standalone way to represent node kinds and their hierarchy.
This change is to support ongoing work on D815.

Reviewers: klimek

CC: cfe-commits

Added:
    cfe/trunk/include/clang/AST/ASTFwd.h
    cfe/trunk/lib/AST/ASTTypeTraits.cpp
    cfe/trunk/unittests/AST/ASTTypeTraitsTest.cpp
Modified:
    cfe/trunk/include/clang/AST/ASTTypeTraits.h
    cfe/trunk/lib/AST/CMakeLists.txt
    cfe/trunk/unittests/AST/CMakeLists.txt

Added: cfe/trunk/include/clang/AST/ASTFwd.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTFwd.h?rev=184331&view=auto
==============================================================================
--- cfe/trunk/include/clang/AST/ASTFwd.h (added)
+++ cfe/trunk/include/clang/AST/ASTFwd.h Wed Jun 19 13:45:24 2013
@@ -0,0 +1,27 @@
+//===--- ASTFwd.h ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--------------------------------------------------------------===//
+///
+/// \file
+/// \brief Forward declaration of all AST node types.
+///
+//===-------------------------------------------------------------===//
+
+namespace clang {
+
+class Decl;
+#define DECL(DERIVED, BASE) class DERIVED##Decl;
+#include "clang/AST/DeclNodes.inc"
+class Stmt;
+#define STMT(DERIVED, BASE) class DERIVED;
+#include "clang/AST/StmtNodes.inc"
+class Type;
+#define TYPE(DERIVED, BASE) class DERIVED##Type;
+#include "clang/AST/TypeNodes.def"
+
+} // end namespace clang

Modified: cfe/trunk/include/clang/AST/ASTTypeTraits.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTTypeTraits.h?rev=184331&r1=184330&r2=184331&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTTypeTraits.h (original)
+++ cfe/trunk/include/clang/AST/ASTTypeTraits.h Wed Jun 19 13:45:24 2013
@@ -7,22 +7,117 @@
 //
 //===----------------------------------------------------------------------===//
 //
-//  Provides a dynamically typed node container that can be used to store
-//  an AST base node at runtime in the same storage in a type safe way.
+//  Provides a dynamic type identifier and a dynamically typed node container
+//  that can be used to store an AST base node at runtime in the same storage in
+//  a type safe way.
 //
 //===----------------------------------------------------------------------===//
 
 #ifndef LLVM_CLANG_AST_AST_TYPE_TRAITS_H
 #define LLVM_CLANG_AST_AST_TYPE_TRAITS_H
 
+#include "clang/AST/ASTFwd.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/Stmt.h"
 #include "clang/AST/TypeLoc.h"
+#include "clang/Basic/LLVM.h"
 #include "llvm/Support/AlignOf.h"
 
 namespace clang {
 namespace ast_type_traits {
 
+/// \brief Kind identifier.
+///
+/// It can be constructed from any node kind and allows for runtime type
+/// hierarchy checks.
+/// Use getFromNodeKind<T>() to construct them.
+class ASTNodeKind {
+public:
+  /// \brief Empty identifier. It matches nothing.
+  ASTNodeKind() : KindId(NKI_None) {}
+
+  /// \brief Construct an identifier for T.
+  template <class T>
+  static ASTNodeKind getFromNodeKind() {
+    return ASTNodeKind(KindToKindId<T>::Id);
+  }
+
+  /// \brief Returns \c true if \c this and \c Other represent the same kind.
+  bool isSame(ASTNodeKind Other);
+
+  /// \brief Returns \c true if \c this is a base kind of (or same as) \c Other
+  bool isBaseOf(ASTNodeKind Other);
+
+  /// \brief String representation of the kind.
+  StringRef asStringRef() const;
+
+private:
+  /// \brief Kind ids.
+  ///
+  /// Includes all possible base and derived kinds.
+  enum NodeKindId {
+    NKI_None,
+    NKI_NestedNameSpecifier,
+    NKI_NestedNameSpecifierLoc,
+    NKI_QualType,
+    NKI_TypeLoc,
+    NKI_Decl,
+#define DECL(DERIVED, BASE) NKI_##DERIVED##Decl,
+#include "clang/AST/DeclNodes.inc"
+    NKI_Stmt,
+#define STMT(DERIVED, BASE) NKI_##DERIVED,
+#include "clang/AST/StmtNodes.inc"
+    NKI_Type,
+#define TYPE(DERIVED, BASE) NKI_##DERIVED##Type,
+#include "clang/AST/TypeNodes.def"
+    NKI_NumberOfKinds
+  };
+
+  /// \brief Use getFromNodeKind<T>() to construct the kind.
+  ASTNodeKind(NodeKindId KindId) : KindId(KindId) {}
+
+  /// \brief Returns \c true if \c Base is a base kind of (or same as) \c
+  ///   Derived
+  static bool isBaseOf(NodeKindId Base, NodeKindId Derived);
+
+  /// \brief Helper meta-function to convert a kind T to its enum value.
+  ///
+  /// This struct is specialized below for all known kinds.
+  template <class T> struct KindToKindId {
+    static const NodeKindId Id = NKI_None;
+  };
+
+  /// \brief Per kind info.
+  struct KindInfo {
+    /// \brief The id of the parent kind, or None if it has no parent.
+    NodeKindId ParentId;
+    /// \brief Name of the kind.
+    const char *Name;
+  };
+  static const KindInfo AllKindInfo[NKI_NumberOfKinds];
+
+  NodeKindId KindId;
+};
+
+#define KIND_TO_KIND_ID(Class)                                                 \
+  template <> struct ASTNodeKind::KindToKindId<Class> {                        \
+    static const NodeKindId Id = NKI_##Class;                                  \
+  };
+KIND_TO_KIND_ID(NestedNameSpecifier)
+KIND_TO_KIND_ID(NestedNameSpecifierLoc)
+KIND_TO_KIND_ID(QualType)
+KIND_TO_KIND_ID(TypeLoc)
+KIND_TO_KIND_ID(Decl)
+KIND_TO_KIND_ID(Stmt)
+KIND_TO_KIND_ID(Type)
+#define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl)
+#include "clang/AST/DeclNodes.inc"
+#define STMT(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED)
+#include "clang/AST/StmtNodes.inc"
+#define TYPE(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Type)
+#include "clang/AST/TypeNodes.def"
+#undef KIND_TO_KIND_ID
+
 /// \brief A dynamically typed AST node container.
 ///
 /// Stores an AST node in a type safe way. This allows writing code that
@@ -57,7 +152,7 @@ public:
   /// use the pointer outside the scope of the DynTypedNode.
   template <typename T>
   const T *get() const {
-    return BaseConverter<T>::get(Tag, Storage.buffer);
+    return BaseConverter<T>::get(NodeKind, Storage.buffer);
   }
 
   /// \brief Returns a pointer that identifies the stored AST node.
@@ -90,16 +185,7 @@ private:
   /// \brief Takes care of converting from and to \c T.
   template <typename T, typename EnablerT = void> struct BaseConverter;
 
-  /// \brief Supported base node types.
-  enum NodeTypeTag {
-    NT_Decl,
-    NT_Stmt,
-    NT_NestedNameSpecifier,
-    NT_NestedNameSpecifierLoc,
-    NT_QualType,
-    NT_Type,
-    NT_TypeLoc
-  } Tag;
+  ASTNodeKind NodeKind;
 
   /// \brief Stores the data of the node.
   ///
@@ -107,103 +193,105 @@ private:
   /// guaranteed to be unique pointers pointing to dedicated storage in the
   /// AST. \c QualTypes on the other hand do not have storage or unique
   /// pointers and thus need to be stored by value.
-  llvm::AlignedCharArrayUnion<Decl *, Stmt *, NestedNameSpecifier,
-                              NestedNameSpecifierLoc, QualType, Type,
+  llvm::AlignedCharArrayUnion<Decl *, Stmt *, NestedNameSpecifier *,
+                              NestedNameSpecifierLoc, QualType, Type *,
                               TypeLoc> Storage;
 };
 
 // FIXME: Pull out abstraction for the following.
 template<typename T> struct DynTypedNode::BaseConverter<T,
     typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> {
-  static const T *get(NodeTypeTag Tag, const char Storage[]) {
-    if (Tag == NT_Decl)
+  static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
+    if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(NodeKind))
       return dyn_cast<T>(*reinterpret_cast<Decl*const*>(Storage));
     return NULL;
   }
   static DynTypedNode create(const Decl &Node) {
     DynTypedNode Result;
-    Result.Tag = NT_Decl;
+    Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
     new (Result.Storage.buffer) const Decl*(&Node);
     return Result;
   }
 };
 template<typename T> struct DynTypedNode::BaseConverter<T,
     typename llvm::enable_if<llvm::is_base_of<Stmt, T> >::type> {
-  static const T *get(NodeTypeTag Tag, const char Storage[]) {
-    if (Tag == NT_Stmt)
+  static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
+    if (ASTNodeKind::getFromNodeKind<Stmt>().isBaseOf(NodeKind))
       return dyn_cast<T>(*reinterpret_cast<Stmt*const*>(Storage));
     return NULL;
   }
   static DynTypedNode create(const Stmt &Node) {
     DynTypedNode Result;
-    Result.Tag = NT_Stmt;
+    Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
     new (Result.Storage.buffer) const Stmt*(&Node);
     return Result;
   }
 };
 template<typename T> struct DynTypedNode::BaseConverter<T,
     typename llvm::enable_if<llvm::is_base_of<Type, T> >::type> {
-  static const T *get(NodeTypeTag Tag, const char Storage[]) {
-    if (Tag == NT_Type)
+  static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
+    if (ASTNodeKind::getFromNodeKind<Type>().isBaseOf(NodeKind))
       return dyn_cast<T>(*reinterpret_cast<Type*const*>(Storage));
     return NULL;
   }
   static DynTypedNode create(const Type &Node) {
     DynTypedNode Result;
-    Result.Tag = NT_Type;
+    Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
     new (Result.Storage.buffer) const Type*(&Node);
     return Result;
   }
 };
 template<> struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> {
-  static const NestedNameSpecifier *get(NodeTypeTag Tag, const char Storage[]) {
-    if (Tag == NT_NestedNameSpecifier)
+  static const NestedNameSpecifier *get(ASTNodeKind NodeKind,
+                                        const char Storage[]) {
+    if (ASTNodeKind::getFromNodeKind<NestedNameSpecifier>().isBaseOf(NodeKind))
       return *reinterpret_cast<NestedNameSpecifier*const*>(Storage);
     return NULL;
   }
   static DynTypedNode create(const NestedNameSpecifier &Node) {
     DynTypedNode Result;
-    Result.Tag = NT_NestedNameSpecifier;
+    Result.NodeKind = ASTNodeKind::getFromNodeKind<NestedNameSpecifier>();
     new (Result.Storage.buffer) const NestedNameSpecifier*(&Node);
     return Result;
   }
 };
 template<> struct DynTypedNode::BaseConverter<NestedNameSpecifierLoc, void> {
-  static const NestedNameSpecifierLoc *get(NodeTypeTag Tag,
+  static const NestedNameSpecifierLoc *get(ASTNodeKind NodeKind,
                                            const char Storage[]) {
-    if (Tag == NT_NestedNameSpecifierLoc)
+    if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isBaseOf(
+            NodeKind))
       return reinterpret_cast<const NestedNameSpecifierLoc*>(Storage);
     return NULL;
   }
   static DynTypedNode create(const NestedNameSpecifierLoc &Node) {
     DynTypedNode Result;
-    Result.Tag = NT_NestedNameSpecifierLoc;
+    Result.NodeKind = ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>();
     new (Result.Storage.buffer) NestedNameSpecifierLoc(Node);
     return Result;
   }
 };
 template<> struct DynTypedNode::BaseConverter<QualType, void> {
-  static const QualType *get(NodeTypeTag Tag, const char Storage[]) {
-    if (Tag == NT_QualType)
+  static const QualType *get(ASTNodeKind NodeKind, const char Storage[]) {
+    if (ASTNodeKind::getFromNodeKind<QualType>().isBaseOf(NodeKind))
       return reinterpret_cast<const QualType*>(Storage);
     return NULL;
   }
   static DynTypedNode create(const QualType &Node) {
     DynTypedNode Result;
-    Result.Tag = NT_QualType;
+    Result.NodeKind = ASTNodeKind::getFromNodeKind<QualType>();
     new (Result.Storage.buffer) QualType(Node);
     return Result;
   }
 };
 template<> struct DynTypedNode::BaseConverter<TypeLoc, void> {
-  static const TypeLoc *get(NodeTypeTag Tag, const char Storage[]) {
-    if (Tag == NT_TypeLoc)
+  static const TypeLoc *get(ASTNodeKind NodeKind, const char Storage[]) {
+    if (ASTNodeKind::getFromNodeKind<TypeLoc>().isBaseOf(NodeKind))
       return reinterpret_cast<const TypeLoc*>(Storage);
     return NULL;
   }
   static DynTypedNode create(const TypeLoc &Node) {
     DynTypedNode Result;
-    Result.Tag = NT_TypeLoc;
+    Result.NodeKind = ASTNodeKind::getFromNodeKind<TypeLoc>();
     new (Result.Storage.buffer) TypeLoc(Node);
     return Result;
   }
@@ -213,15 +301,18 @@ template<> struct DynTypedNode::BaseConv
 // AST node that is not supported, but prevents misuse - a user cannot create
 // a DynTypedNode from arbitrary types.
 template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {
-  static const T *get(NodeTypeTag Tag, const char Storage[]) { return NULL; }
+  static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
+    return NULL;
+  }
 };
 
 inline const void *DynTypedNode::getMemoizationData() const {
-  switch (Tag) {
-    case NT_Decl: return BaseConverter<Decl>::get(Tag, Storage.buffer);
-    case NT_Stmt: return BaseConverter<Stmt>::get(Tag, Storage.buffer);
-    default: return NULL;
-  };
+  if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(NodeKind)) {
+    return BaseConverter<Decl>::get(NodeKind, Storage.buffer);
+  } else if (ASTNodeKind::getFromNodeKind<Stmt>().isBaseOf(NodeKind)) {
+    return BaseConverter<Stmt>::get(NodeKind, Storage.buffer);
+  }
+  return NULL;
 }
 
 } // end namespace ast_type_traits

Added: cfe/trunk/lib/AST/ASTTypeTraits.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTTypeTraits.cpp?rev=184331&view=auto
==============================================================================
--- cfe/trunk/lib/AST/ASTTypeTraits.cpp (added)
+++ cfe/trunk/lib/AST/ASTTypeTraits.cpp Wed Jun 19 13:45:24 2013
@@ -0,0 +1,56 @@
+//===--- ASTTypeTraits.cpp --------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  Provides a dynamic type identifier and a dynamically typed node container
+//  that can be used to store an AST base node at runtime in the same storage in
+//  a type safe way.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTTypeTraits.h"
+
+namespace clang {
+namespace ast_type_traits {
+
+const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = {
+  { NKI_None, "<None>" },
+  { NKI_None, "NestedNameSpecifier" },
+  { NKI_None, "NestedNameSpecifierLoc" },
+  { NKI_None, "QualType" },
+  { NKI_None, "TypeLoc" },
+  { NKI_None, "Decl" },
+#define DECL(DERIVED, BASE) { NKI_##BASE, #DERIVED "Decl" },
+#include "clang/AST/DeclNodes.inc"
+  { NKI_None, "Stmt" },
+#define STMT(DERIVED, BASE) { NKI_##BASE, #DERIVED },
+#include "clang/AST/StmtNodes.inc"
+  { NKI_None, "Type" },
+#define TYPE(DERIVED, BASE) { NKI_##BASE, #DERIVED "Type" },
+#include "clang/AST/TypeNodes.def"
+};
+
+bool ASTNodeKind::isBaseOf(ASTNodeKind Other) {
+  return isBaseOf(KindId, Other.KindId);
+}
+
+bool ASTNodeKind::isSame(ASTNodeKind Other) {
+  return KindId != NKI_None && KindId == Other.KindId;
+}
+
+bool ASTNodeKind::isBaseOf(NodeKindId Base, NodeKindId Derived) {
+  if (Base == NKI_None || Derived == NKI_None) return false;
+  while (Derived != Base && Derived != NKI_None)
+    Derived = AllKindInfo[Derived].ParentId;
+  return Derived == Base;
+}
+
+StringRef ASTNodeKind::asStringRef() const { return AllKindInfo[KindId].Name; }
+
+} // end namespace ast_type_traits
+} // end namespace clang

Modified: cfe/trunk/lib/AST/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CMakeLists.txt?rev=184331&r1=184330&r2=184331&view=diff
==============================================================================
--- cfe/trunk/lib/AST/CMakeLists.txt (original)
+++ cfe/trunk/lib/AST/CMakeLists.txt Wed Jun 19 13:45:24 2013
@@ -7,6 +7,7 @@ add_clang_library(clangAST
   ASTDiagnostic.cpp
   ASTDumper.cpp
   ASTImporter.cpp
+  ASTTypeTraits.cpp
   AttrImpl.cpp
   CXXInheritance.cpp
   Comment.cpp

Added: cfe/trunk/unittests/AST/ASTTypeTraitsTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/ASTTypeTraitsTest.cpp?rev=184331&view=auto
==============================================================================
--- cfe/trunk/unittests/AST/ASTTypeTraitsTest.cpp (added)
+++ cfe/trunk/unittests/AST/ASTTypeTraitsTest.cpp Wed Jun 19 13:45:24 2013
@@ -0,0 +1,62 @@
+//===- unittest/AST/ASTTypeTraits.cpp - AST type traits unit tests ------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--------------------------------------------------------------------===//
+
+
+#include "clang/AST/ASTTypeTraits.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_type_traits {
+
+TEST(ASTNodeKind, NoKind) {
+  EXPECT_FALSE(ASTNodeKind().isBaseOf(ASTNodeKind()));
+  EXPECT_FALSE(ASTNodeKind().isSame(ASTNodeKind()));
+}
+
+template <typename T> static ASTNodeKind DNT() {
+  return ASTNodeKind::getFromNodeKind<T>();
+}
+
+TEST(ASTNodeKind, Bases) {
+  EXPECT_TRUE(DNT<Decl>().isBaseOf(DNT<VarDecl>()));
+  EXPECT_FALSE(DNT<Decl>().isSame(DNT<VarDecl>()));
+  EXPECT_FALSE(DNT<VarDecl>().isBaseOf(DNT<Decl>()));
+
+  EXPECT_TRUE(DNT<Decl>().isSame(DNT<Decl>()));
+}
+
+TEST(ASTNodeKind, SameBase) {
+  EXPECT_TRUE(DNT<Expr>().isBaseOf(DNT<CallExpr>()));
+  EXPECT_TRUE(DNT<Expr>().isBaseOf(DNT<BinaryOperator>()));
+  EXPECT_FALSE(DNT<CallExpr>().isBaseOf(DNT<BinaryOperator>()));
+  EXPECT_FALSE(DNT<BinaryOperator>().isBaseOf(DNT<CallExpr>()));
+}
+
+TEST(ASTNodeKind, DiffBase) {
+  EXPECT_FALSE(DNT<Expr>().isBaseOf(DNT<ArrayType>()));
+  EXPECT_FALSE(DNT<QualType>().isBaseOf(DNT<FunctionDecl>()));
+  EXPECT_FALSE(DNT<Type>().isSame(DNT<QualType>()));
+}
+
+struct Foo {};
+
+TEST(ASTNodeKind, UnknownKind) {
+  // We can construct one, but it is nowhere in the hierarchy.
+  EXPECT_FALSE(DNT<Foo>().isSame(DNT<Foo>()));
+}
+
+TEST(ASTNodeKind, Name) {
+  EXPECT_EQ("Decl", DNT<Decl>().asStringRef());
+  EXPECT_EQ("CallExpr", DNT<CallExpr>().asStringRef());
+  EXPECT_EQ("ConstantArrayType", DNT<ConstantArrayType>().asStringRef());
+  EXPECT_EQ("<None>", ASTNodeKind().asStringRef());
+}
+
+}  // namespace ast_type_traits
+}  // namespace clang

Modified: cfe/trunk/unittests/AST/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/CMakeLists.txt?rev=184331&r1=184330&r2=184331&view=diff
==============================================================================
--- cfe/trunk/unittests/AST/CMakeLists.txt (original)
+++ cfe/trunk/unittests/AST/CMakeLists.txt Wed Jun 19 13:45:24 2013
@@ -1,5 +1,6 @@
 add_clang_unittest(ASTTests
   ASTContextParentMapTest.cpp
+  ASTTypeTraitsTest.cpp
   CommentLexer.cpp
   CommentParser.cpp
   DeclPrinterTest.cpp





More information about the cfe-commits mailing list