<html><head><meta http-equiv="Content-Type" content="text/html charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div>Manuel,</div><div><br></div>This commit has caused breakage on our internal MSVC buildbot:<div><br></div><div><div>279>.\llvm\tools\clang\include\clang/AST/RecursiveASTVisitor.h(1715) : error C2872: 'clang' : ambiguous symbol</div><div>279> could be 'clang'</div><div>279> or 'clang::ento::clang'</div><div>279> .\llvm\tools\clang\include\clang/AST/RecursiveASTVisitor.h(1688) : while compiling class template member function 'bool clang::RecursiveASTVisitor<Derived>::TraverseFunctionHelper(clang::FunctionDecl *)'</div><div>279> with</div><div>279> [</div><div>279> Derived=clang::ASTContext::ParentMapASTVisitor</div><div>279> ]</div><div>279> .\llvm\tools\clang\include\clang/AST/RecursiveASTVisitor.h(1840) : while compiling class template member function 'bool clang::RecursiveASTVisitor<Derived>::TraverseGCCAsmStmt(clang::GCCAsmStmt *)'</div><div>279> with</div><div>279> [</div><div>279> Derived=clang::ASTContext::ParentMapASTVisitor</div><div>279> ]</div><div>279> .\llvm\tools\clang\include\clang/AST/RecursiveASTVisitor.h(522) : while compiling class template member function 'bool clang::RecursiveASTVisitor<Derived>::TraverseStmt(clang::Stmt *)'</div><div>279> with</div><div>279> [</div><div>279> Derived=clang::ASTContext::ParentMapASTVisitor</div><div>279> ]</div><div>279> .\llvm\tools\clang\include\clang/AST/ASTContext.h(2202) : see reference to class template instantiation 'clang::RecursiveASTVisitor<Derived>' being compiled</div><div>279> with</div><div>279> [</div><div>279> Derived=clang::ASTContext::ParentMapASTVisitor</div><div>279> ]</div><div>275> Creating library .\llvm\build\lib\Debug\clang-check.lib and object .\llvm\build\lib\Debug\clang-check.exp</div><div>2</div><div><div>On Feb 28, 2013, at 5:21 AM, Manuel Klimek <<a href="mailto:klimek@google.com">klimek@google.com</a>> wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div style="letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;">Author: klimek<br>Date: Thu Feb 28 07:21:39 2013<br>New Revision: 176251<br><br>URL:<span class="Apple-converted-space"> </span><a href="http://llvm.org/viewvc/llvm-project?rev=176251&view=rev">http://llvm.org/viewvc/llvm-project?rev=176251&view=rev</a><br>Log:<br>First step towards adding a parent map to the ASTContext.<br><br>This does not yet implement the LimitNode approach discussed.<br><br>The impact of this is an O(n) in the number of nodes in the AST<br>reduction of complexity for certain kinds of matchers (as otherwise the<br>parent map gets recreated for every new MatchFinder).<br><br>See FIXMEs in the comments for the direction of future work.<br><br>Added:<br> cfe/trunk/include/clang/AST/ASTTypeTraits.h<br> - copied, changed from r176245, cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h<br> cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp<br>Removed:<br> cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h<br>Modified:<br> cfe/trunk/include/clang/AST/ASTContext.h<br> cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h<br> cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp<br> cfe/trunk/unittests/AST/CMakeLists.txt<br> cfe/trunk/unittests/AST/MatchVerifier.h<br><br>Modified: cfe/trunk/include/clang/AST/ASTContext.h<br>URL:<span class="Apple-converted-space"> </span><a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=176251&r1=176250&r2=176251&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=176251&r1=176250&r2=176251&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/AST/ASTContext.h (original)<br>+++ cfe/trunk/include/clang/AST/ASTContext.h Thu Feb 28 07:21:39 2013<br>@@ -15,6 +15,7 @@<br>#ifndef LLVM_CLANG_AST_ASTCONTEXT_H<br>#define LLVM_CLANG_AST_ASTCONTEXT_H<br><br>+#include "clang/AST/ASTTypeTraits.h"<br>#include "clang/AST/CanonicalType.h"<br>#include "clang/AST/CommentCommandTraits.h"<br>#include "clang/AST/Decl.h"<br>@@ -22,6 +23,7 @@<br>#include "clang/AST/NestedNameSpecifier.h"<br>#include "clang/AST/PrettyPrinter.h"<br>#include "clang/AST/RawCommentList.h"<br>+#include "clang/AST/RecursiveASTVisitor.h"<br>#include "clang/AST/TemplateName.h"<br>#include "clang/AST/Type.h"<br>#include "clang/Basic/AddressSpaces.h"<br>@@ -382,6 +384,58 @@ public:<br> OwningPtr<ExternalASTSource> ExternalSource;<br> ASTMutationListener *Listener;<br><br>+ /// \brief Contains parents of a node.<br>+ typedef llvm::SmallVector<ast_type_traits::DynTypedNode, 1> ParentVector;<br>+<br>+ /// \brief Maps from a node to its parents.<br>+ typedef llvm::DenseMap<const void *, ParentVector> ParentMap;<br>+<br>+ /// \brief Returns the parents of the given node.<br>+ ///<br>+ /// Note that this will lazily compute the parents of all nodes<br>+ /// and store them for later retrieval. Thus, the first call is O(n)<br>+ /// in the number of AST nodes.<br>+ ///<br>+ /// Caveats and FIXMEs:<br>+ /// Calculating the parent map over all AST nodes will need to load the<br>+ /// full AST. This can be undesirable in the case where the full AST is<br>+ /// expensive to create (for example, when using precompiled header<br>+ /// preambles). Thus, there are good opportunities for optimization here.<br>+ /// One idea is to walk the given node downwards, looking for references<br>+ /// to declaration contexts - once a declaration context is found, compute<br>+ /// the parent map for the declaration context; if that can satisfy the<br>+ /// request, loading the whole AST can be avoided. Note that this is made<br>+ /// more complex by statements in templates having multiple parents - those<br>+ /// problems can be solved by building closure over the templated parts of<br>+ /// the AST, which also avoids touching large parts of the AST.<br>+ /// Additionally, we will want to add an interface to already give a hint<br>+ /// where to search for the parents, for example when looking at a statement<br>+ /// inside a certain function.<br>+ ///<br>+ /// 'NodeT' can be one of Decl, Stmt, Type, TypeLoc,<br>+ /// NestedNameSpecifier or NestedNameSpecifierLoc.<br>+ template <typename NodeT><br>+ ParentVector getParents(const NodeT &Node) {<br>+ return getParents(ast_type_traits::DynTypedNode::create(Node));<br>+ }<br>+<br>+ ParentVector getParents(const ast_type_traits::DynTypedNode &Node) {<br>+ assert(Node.getMemoizationData() &&<br>+ "Invariant broken: only nodes that support memoization may be "<br>+ "used in the parent map.");<br>+ if (!AllParents) {<br>+ // We always need to run over the whole translation unit, as<br>+ // hasAncestor can escape any subtree.<br>+ AllParents.reset(<br>+ ParentMapASTVisitor::buildMap(*getTranslationUnitDecl()));<br>+ }<br>+ ParentMap::const_iterator I = AllParents->find(Node.getMemoizationData());<br>+ if (I == AllParents->end()) {<br>+ return ParentVector();<br>+ }<br>+ return I->second;<br>+ }<br>+<br> const clang::PrintingPolicy &getPrintingPolicy() const {<br> return PrintingPolicy;<br> }<br>@@ -2136,8 +2190,81 @@ private:<br> friend class DeclContext;<br> friend class DeclarationNameTable;<br> void ReleaseDeclContextMaps();<br>+<br>+ /// \brief A \c RecursiveASTVisitor that builds a map from nodes to their<br>+ /// parents as defined by the \c RecursiveASTVisitor.<br>+ ///<br>+ /// Note that the relationship described here is purely in terms of AST<br>+ /// traversal - there are other relationships (for example declaration context)<br>+ /// in the AST that are better modeled by special matchers.<br>+ ///<br>+ /// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes.<br>+ class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> {<br>+ public:<br>+ /// \brief Builds and returns the translation unit's parent map.<br>+ ///<br>+ /// The caller takes ownership of the returned \c ParentMap.<br>+ static ParentMap *buildMap(TranslationUnitDecl &TU) {<br>+ ParentMapASTVisitor Visitor(new ParentMap);<br>+ Visitor.TraverseDecl(&TU);<br>+ return Visitor.Parents;<br>+ }<br>+<br>+ private:<br>+ typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase;<br>+<br>+ ParentMapASTVisitor(ParentMap *Parents) : Parents(Parents) {<br>+ }<br>+<br>+ bool shouldVisitTemplateInstantiations() const {<br>+ return true;<br>+ }<br>+ bool shouldVisitImplicitCode() const {<br>+ return true;<br>+ }<br>+ // Disables data recursion. We intercept Traverse* methods in the RAV, which<br>+ // are not triggered during data recursion.<br>+ bool shouldUseDataRecursionFor(clang::Stmt *S) const {<br>+ return false;<br>+ }<br>+<br>+ template <typename T><br>+ bool TraverseNode(T *Node, bool(VisitorBase:: *traverse) (T *)) {<br>+ if (Node == NULL)<br>+ return true;<br>+ if (ParentStack.size() > 0)<br>+ // FIXME: Currently we add the same parent multiple times, for example<br>+ // when we visit all subexpressions of template instantiations; this is<br>+ // suboptimal, bug benign: the only way to visit those is with<br>+ // hasAncestor / hasParent, and those do not create new matches.<br>+ // The plan is to enable DynTypedNode to be storable in a map or hash<br>+ // map. The main problem there is to implement hash functions /<br>+ // comparison operators for all types that DynTypedNode supports that<br>+ // do not have pointer identity.<br>+ (*Parents)[Node].push_back(ParentStack.back());<br>+ ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node));<br>+ bool Result = (this ->* traverse) (Node);<br>+ ParentStack.pop_back();<br>+ return Result;<br>+ }<br>+<br>+ bool TraverseDecl(Decl *DeclNode) {<br>+ return TraverseNode(DeclNode, &VisitorBase::TraverseDecl);<br>+ }<br>+<br>+ bool TraverseStmt(Stmt *StmtNode) {<br>+ return TraverseNode(StmtNode, &VisitorBase::TraverseStmt);<br>+ }<br>+<br>+ ParentMap *Parents;<br>+ llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack;<br>+<br>+ friend class RecursiveASTVisitor<ParentMapASTVisitor>;<br>+ };<br>+<br>+ llvm::OwningPtr<ParentMap> AllParents;<br>};<br>- <br>+<br>/// \brief Utility function for constructing a nullary selector.<br>static inline Selector GetNullarySelector(StringRef name, ASTContext& Ctx) {<br> IdentifierInfo* II = &Ctx.Idents.get(name);<br><br>Copied: cfe/trunk/include/clang/AST/ASTTypeTraits.h (from r176245, cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h)<br>URL:<span class="Apple-converted-space"> </span><a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTTypeTraits.h?p2=cfe/trunk/include/clang/AST/ASTTypeTraits.h&p1=cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h&r1=176245&r2=176251&rev=176251&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTTypeTraits.h?p2=cfe/trunk/include/clang/AST/ASTTypeTraits.h&p1=cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h&r1=176245&r2=176251&rev=176251&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h (original)<br>+++ cfe/trunk/include/clang/AST/ASTTypeTraits.h Thu Feb 28 07:21:39 2013<br>@@ -1,4 +1,4 @@<br>-//===--- ASTMatchersTypeTraits.h --------------------------------*- C++ -*-===//<br>+//===--- ASTTypeTraits.h ----------------------------------------*- C++ -*-===//<br>//<br>// The LLVM Compiler Infrastructure<br>//<br>@@ -12,8 +12,8 @@<br>//<br>//===----------------------------------------------------------------------===//<br><br>-#ifndef LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H<br>-#define LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H<br>+#ifndef LLVM_CLANG_AST_AST_TYPE_TRAITS_H<br>+#define LLVM_CLANG_AST_AST_TYPE_TRAITS_H<br><br>#include "clang/AST/Decl.h"<br>#include "clang/AST/Stmt.h"<br>@@ -88,8 +88,9 @@ private:<br> /// guaranteed to be unique pointers pointing to dedicated storage in the<br> /// AST. \c QualTypes on the other hand do not have storage or unique<br> /// pointers and thus need to be stored by value.<br>- llvm::AlignedCharArrayUnion<Decl*, QualType, TypeLoc, NestedNameSpecifierLoc><br>- Storage;<br>+ llvm::AlignedCharArrayUnion<Decl *, Stmt *, NestedNameSpecifier,<br>+ NestedNameSpecifierLoc, QualType, Type,<br>+ TypeLoc> Storage;<br>};<br><br>// FIXME: Pull out abstraction for the following.<br>@@ -207,4 +208,4 @@ inline const void *DynTypedNode::getMemo<br>} // end namespace ast_type_traits<br>} // end namespace clang<br><br>-#endif // LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H<br>+#endif // LLVM_CLANG_AST_AST_TYPE_TRAITS_H<br><br>Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h<br>URL:<span class="Apple-converted-space"> </span><a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=176251&r1=176250&r2=176251&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=176251&r1=176250&r2=176251&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h (original)<br>+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h Thu Feb 28 07:21:39 2013<br>@@ -35,13 +35,13 @@<br>#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H<br>#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H<br><br>-#include "clang/AST/Decl.h"<br>+#include "clang/AST/ASTTypeTraits.h"<br>#include "clang/AST/DeclCXX.h"<br>+#include "clang/AST/Decl.h"<br>#include "clang/AST/ExprCXX.h"<br>-#include "clang/AST/Stmt.h"<br>#include "clang/AST/StmtCXX.h"<br>+#include "clang/AST/Stmt.h"<br>#include "clang/AST/Type.h"<br>-#include "clang/ASTMatchers/ASTTypeTraits.h"<br>#include "llvm/ADT/VariadicFunction.h"<br>#include "llvm/Support/type_traits.h"<br>#include <map><br><br>Removed: cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h<br>URL:<span class="Apple-converted-space"> </span><a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h?rev=176250&view=auto">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h?rev=176250&view=auto</a><br>==============================================================================<br>--- cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h (original)<br>+++ cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h (removed)<br>@@ -1,210 +0,0 @@<br>-//===--- ASTMatchersTypeTraits.h --------------------------------*- C++ -*-===//<br>-//<br>-// The LLVM Compiler Infrastructure<br>-//<br>-// This file is distributed under the University of Illinois Open Source<br>-// License. See LICENSE.TXT for details.<br>-//<br>-//===----------------------------------------------------------------------===//<br>-//<br>-// Provides a dynamically typed node container that can be used to store<br>-// an AST base node at runtime in the same storage in a type safe way.<br>-//<br>-//===----------------------------------------------------------------------===//<br>-<br>-#ifndef LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H<br>-#define LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H<br>-<br>-#include "clang/AST/Decl.h"<br>-#include "clang/AST/Stmt.h"<br>-#include "clang/AST/TypeLoc.h"<br>-#include "llvm/Support/AlignOf.h"<br>-<br>-namespace clang {<br>-namespace ast_type_traits {<br>-<br>-/// \brief A dynamically typed AST node container.<br>-///<br>-/// Stores an AST node in a type safe way. This allows writing code that<br>-/// works with different kinds of AST nodes, despite the fact that they don't<br>-/// have a common base class.<br>-///<br>-/// Use \c create(Node) to create a \c DynTypedNode from an AST node,<br>-/// and \c get<T>() to retrieve the node as type T if the types match.<br>-///<br>-/// See \c NodeTypeTag for which node base types are currently supported;<br>-/// You can create DynTypedNodes for all nodes in the inheritance hierarchy of<br>-/// the supported base types.<br>-class DynTypedNode {<br>-public:<br>- /// \brief Creates a \c DynTypedNode from \c Node.<br>- template <typename T><br>- static DynTypedNode create(const T &Node) {<br>- return BaseConverter<T>::create(Node);<br>- }<br>-<br>- /// \brief Retrieve the stored node as type \c T.<br>- ///<br>- /// Returns NULL if the stored node does not have a type that is<br>- /// convertible to \c T.<br>- ///<br>- /// For types that have identity via their pointer in the AST<br>- /// (like \c Stmt and \c Decl) the returned pointer points to the<br>- /// referenced AST node.<br>- /// For other types (like \c QualType) the value is stored directly<br>- /// in the \c DynTypedNode, and the returned pointer points at<br>- /// the storage inside DynTypedNode. For those nodes, do not<br>- /// use the pointer outside the scope of the DynTypedNode.<br>- template <typename T><br>- const T *get() const {<br>- return BaseConverter<T>::get(Tag, Storage.buffer);<br>- }<br>-<br>- /// \brief Returns a pointer that identifies the stored AST node.<br>- ///<br>- /// Note that this is not supported by all AST nodes. For AST nodes<br>- /// that don't have a pointer-defined identity inside the AST, this<br>- /// method returns NULL.<br>- const void *getMemoizationData() const;<br>-<br>-private:<br>- /// \brief Takes care of converting from and to \c T.<br>- template <typename T, typename EnablerT = void> struct BaseConverter;<br>-<br>- /// \brief Supported base node types.<br>- enum NodeTypeTag {<br>- NT_Decl,<br>- NT_Stmt,<br>- NT_NestedNameSpecifier,<br>- NT_NestedNameSpecifierLoc,<br>- NT_QualType,<br>- NT_Type,<br>- NT_TypeLoc<br>- } Tag;<br>-<br>- /// \brief Stores the data of the node.<br>- ///<br>- /// Note that we can store \c Decls and \c Stmts by pointer as they are<br>- /// guaranteed to be unique pointers pointing to dedicated storage in the<br>- /// AST. \c QualTypes on the other hand do not have storage or unique<br>- /// pointers and thus need to be stored by value.<br>- llvm::AlignedCharArrayUnion<Decl*, QualType, TypeLoc, NestedNameSpecifierLoc><br>- Storage;<br>-};<br>-<br>-// FIXME: Pull out abstraction for the following.<br>-template<typename T> struct DynTypedNode::BaseConverter<T,<br>- typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> {<br>- static const T *get(NodeTypeTag Tag, const char Storage[]) {<br>- if (Tag == NT_Decl)<br>- return dyn_cast<T>(*reinterpret_cast<Decl*const*>(Storage));<br>- return NULL;<br>- }<br>- static DynTypedNode create(const Decl &Node) {<br>- DynTypedNode Result;<br>- Result.Tag = NT_Decl;<br>- new (Result.Storage.buffer) const Decl*(&Node);<br>- return Result;<br>- }<br>-};<br>-template<typename T> struct DynTypedNode::BaseConverter<T,<br>- typename llvm::enable_if<llvm::is_base_of<Stmt, T> >::type> {<br>- static const T *get(NodeTypeTag Tag, const char Storage[]) {<br>- if (Tag == NT_Stmt)<br>- return dyn_cast<T>(*reinterpret_cast<Stmt*const*>(Storage));<br>- return NULL;<br>- }<br>- static DynTypedNode create(const Stmt &Node) {<br>- DynTypedNode Result;<br>- Result.Tag = NT_Stmt;<br>- new (Result.Storage.buffer) const Stmt*(&Node);<br>- return Result;<br>- }<br>-};<br>-template<typename T> struct DynTypedNode::BaseConverter<T,<br>- typename llvm::enable_if<llvm::is_base_of<Type, T> >::type> {<br>- static const T *get(NodeTypeTag Tag, const char Storage[]) {<br>- if (Tag == NT_Type)<br>- return dyn_cast<T>(*reinterpret_cast<Type*const*>(Storage));<br>- return NULL;<br>- }<br>- static DynTypedNode create(const Type &Node) {<br>- DynTypedNode Result;<br>- Result.Tag = NT_Type;<br>- new (Result.Storage.buffer) const Type*(&Node);<br>- return Result;<br>- }<br>-};<br>-template<> struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> {<br>- static const NestedNameSpecifier *get(NodeTypeTag Tag, const char Storage[]) {<br>- if (Tag == NT_NestedNameSpecifier)<br>- return *reinterpret_cast<NestedNameSpecifier*const*>(Storage);<br>- return NULL;<br>- }<br>- static DynTypedNode create(const NestedNameSpecifier &Node) {<br>- DynTypedNode Result;<br>- Result.Tag = NT_NestedNameSpecifier;<br>- new (Result.Storage.buffer) const NestedNameSpecifier*(&Node);<br>- return Result;<br>- }<br>-};<br>-template<> struct DynTypedNode::BaseConverter<NestedNameSpecifierLoc, void> {<br>- static const NestedNameSpecifierLoc *get(NodeTypeTag Tag,<br>- const char Storage[]) {<br>- if (Tag == NT_NestedNameSpecifierLoc)<br>- return reinterpret_cast<const NestedNameSpecifierLoc*>(Storage);<br>- return NULL;<br>- }<br>- static DynTypedNode create(const NestedNameSpecifierLoc &Node) {<br>- DynTypedNode Result;<br>- Result.Tag = NT_NestedNameSpecifierLoc;<br>- new (Result.Storage.buffer) NestedNameSpecifierLoc(Node);<br>- return Result;<br>- }<br>-};<br>-template<> struct DynTypedNode::BaseConverter<QualType, void> {<br>- static const QualType *get(NodeTypeTag Tag, const char Storage[]) {<br>- if (Tag == NT_QualType)<br>- return reinterpret_cast<const QualType*>(Storage);<br>- return NULL;<br>- }<br>- static DynTypedNode create(const QualType &Node) {<br>- DynTypedNode Result;<br>- Result.Tag = NT_QualType;<br>- new (Result.Storage.buffer) QualType(Node);<br>- return Result;<br>- }<br>-};<br>-template<> struct DynTypedNode::BaseConverter<TypeLoc, void> {<br>- static const TypeLoc *get(NodeTypeTag Tag, const char Storage[]) {<br>- if (Tag == NT_TypeLoc)<br>- return reinterpret_cast<const TypeLoc*>(Storage);<br>- return NULL;<br>- }<br>- static DynTypedNode create(const TypeLoc &Node) {<br>- DynTypedNode Result;<br>- Result.Tag = NT_TypeLoc;<br>- new (Result.Storage.buffer) TypeLoc(Node);<br>- return Result;<br>- }<br>-};<br>-// The only operation we allow on unsupported types is \c get.<br>-// This allows to conveniently use \c DynTypedNode when having an arbitrary<br>-// AST node that is not supported, but prevents misuse - a user cannot create<br>-// a DynTypedNode from arbitrary types.<br>-template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {<br>- static const T *get(NodeTypeTag Tag, const char Storage[]) { return NULL; }<br>-};<br>-<br>-inline const void *DynTypedNode::getMemoizationData() const {<br>- switch (Tag) {<br>- case NT_Decl: return BaseConverter<Decl>::get(Tag, Storage.buffer);<br>- case NT_Stmt: return BaseConverter<Stmt>::get(Tag, Storage.buffer);<br>- default: return NULL;<br>- };<br>-}<br>-<br>-} // end namespace ast_type_traits<br>-} // end namespace clang<br>-<br>-#endif // LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H<br><br>Modified: cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp<br>URL:<span class="Apple-converted-space"> </span><a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp?rev=176251&r1=176250&r2=176251&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp?rev=176251&r1=176250&r2=176251&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp (original)<br>+++ cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp Thu Feb 28 07:21:39 2013<br>@@ -29,76 +29,6 @@ namespace {<br><br>typedef MatchFinder::MatchCallback MatchCallback;<br><br>-/// \brief A \c RecursiveASTVisitor that builds a map from nodes to their<br>-/// parents as defined by the \c RecursiveASTVisitor.<br>-///<br>-/// Note that the relationship described here is purely in terms of AST<br>-/// traversal - there are other relationships (for example declaration context)<br>-/// in the AST that are better modeled by special matchers.<br>-///<br>-/// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes.<br>-class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> {<br>-public:<br>- /// \brief Contains parents of a node.<br>- typedef SmallVector<ast_type_traits::DynTypedNode, 1> ParentVector;<br>-<br>- /// \brief Maps from a node to its parents.<br>- typedef llvm::DenseMap<const void *, ParentVector> ParentMap;<br>-<br>- /// \brief Builds and returns the translation unit's parent map.<br>- ///<br>- /// The caller takes ownership of the returned \c ParentMap.<br>- static ParentMap *buildMap(TranslationUnitDecl &TU) {<br>- ParentMapASTVisitor Visitor(new ParentMap);<br>- Visitor.TraverseDecl(&TU);<br>- return Visitor.Parents;<br>- }<br>-<br>-private:<br>- typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase;<br>-<br>- ParentMapASTVisitor(ParentMap *Parents) : Parents(Parents) {}<br>-<br>- bool shouldVisitTemplateInstantiations() const { return true; }<br>- bool shouldVisitImplicitCode() const { return true; }<br>- // Disables data recursion. We intercept Traverse* methods in the RAV, which<br>- // are not triggered during data recursion.<br>- bool shouldUseDataRecursionFor(clang::Stmt *S) const { return false; }<br>-<br>- template <typename T><br>- bool TraverseNode(T *Node, bool (VisitorBase::*traverse)(T*)) {<br>- if (Node == NULL)<br>- return true;<br>- if (ParentStack.size() > 0)<br>- // FIXME: Currently we add the same parent multiple times, for example<br>- // when we visit all subexpressions of template instantiations; this is<br>- // suboptimal, bug benign: the only way to visit those is with<br>- // hasAncestor / hasParent, and those do not create new matches.<br>- // The plan is to enable DynTypedNode to be storable in a map or hash<br>- // map. The main problem there is to implement hash functions /<br>- // comparison operators for all types that DynTypedNode supports that<br>- // do not have pointer identity.<br>- (*Parents)[Node].push_back(ParentStack.back());<br>- ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node));<br>- bool Result = (this->*traverse)(Node);<br>- ParentStack.pop_back();<br>- return Result;<br>- }<br>-<br>- bool TraverseDecl(Decl *DeclNode) {<br>- return TraverseNode(DeclNode, &VisitorBase::TraverseDecl);<br>- }<br>-<br>- bool TraverseStmt(Stmt *StmtNode) {<br>- return TraverseNode(StmtNode, &VisitorBase::TraverseStmt);<br>- }<br>-<br>- ParentMap *Parents;<br>- SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack;<br>-<br>- friend class RecursiveASTVisitor<ParentMapASTVisitor>;<br>-};<br>-<br>// We use memoization to avoid running the same matcher on the same<br>// AST node twice. This pair is the key for looking up match<br>// result. It consists of an ID of the MatcherInterface (for<br>@@ -458,12 +388,6 @@ public:<br> const DynTypedMatcher &Matcher,<br> BoundNodesTreeBuilder *Builder,<br> AncestorMatchMode MatchMode) {<br>- if (!Parents) {<br>- // We always need to run over the whole translation unit, as<br>- // \c hasAncestor can escape any subtree.<br>- Parents.reset(ParentMapASTVisitor::buildMap(<br>- *ActiveASTContext->getTranslationUnitDecl()));<br>- }<br> return matchesAncestorOfRecursively(Node, Matcher, Builder, MatchMode);<br> }<br><br>@@ -506,22 +430,21 @@ private:<br> assert(Node.getMemoizationData() &&<br> "Invariant broken: only nodes that support memoization may be "<br> "used in the parent map.");<br>- ParentMapASTVisitor::ParentMap::const_iterator I =<br>- Parents->find(Node.getMemoizationData());<br>- if (I == Parents->end()) {<br>+ ASTContext::ParentVector Parents = ActiveASTContext->getParents(Node);<br>+ if (Parents.empty()) {<br> assert(false && "Found node that is not in the parent map.");<br> return false;<br> }<br>- for (ParentMapASTVisitor::ParentVector::const_iterator AncestorI =<br>- I->second.begin(), AncestorE = I->second.end();<br>+ for (ASTContext::ParentVector::const_iterator AncestorI = Parents.begin(),<br>+ AncestorE = Parents.end();<br> AncestorI != AncestorE; ++AncestorI) {<br> if (Matcher.matches(*AncestorI, this, Builder))<br> return true;<br> }<br> if (MatchMode == ASTMatchFinder::AMM_ParentOnly)<br> return false;<br>- for (ParentMapASTVisitor::ParentVector::const_iterator AncestorI =<br>- I->second.begin(), AncestorE = I->second.end();<br>+ for (ASTContext::ParentVector::const_iterator AncestorI = Parents.begin(),<br>+ AncestorE = Parents.end();<br> AncestorI != AncestorE; ++AncestorI) {<br> if (matchesAncestorOfRecursively(*AncestorI, Matcher, Builder, MatchMode))<br> return true;<br>@@ -574,8 +497,6 @@ private:<br> // Maps (matcher, node) -> the match result for memoization.<br> typedef llvm::DenseMap<UntypedMatchInput, MemoizedMatchResult> MemoizationMap;<br> MemoizationMap ResultCache;<br>-<br>- OwningPtr<ParentMapASTVisitor::ParentMap> Parents;<br>};<br><br>// Returns true if the given class is directly or indirectly derived<br><br>Added: cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp<br>URL:<span class="Apple-converted-space"> </span><a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp?rev=176251&view=auto">http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp?rev=176251&view=auto</a><br>==============================================================================<br>--- cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp (added)<br>+++ cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp Thu Feb 28 07:21:39 2013<br>@@ -0,0 +1,71 @@<br>+//===- unittest/AST/ASTContextParentMapTest.cpp - AST parent map test -----===//<br>+//<br>+// The LLVM Compiler Infrastructure<br>+//<br>+// This file is distributed under the University of Illinois Open Source<br>+// License. See LICENSE.TXT for details.<br>+//<br>+//===----------------------------------------------------------------------===//<br>+//<br>+// Tests for the getParents(...) methods of ASTContext.<br>+//<br>+//===----------------------------------------------------------------------===//<br>+<br>+#include "clang/AST/ASTContext.h"<br>+#include "clang/ASTMatchers/ASTMatchFinder.h"<br>+#include "clang/ASTMatchers/ASTMatchers.h"<br>+#include "clang/Tooling/Tooling.h"<br>+#include "gtest/gtest.h"<br>+#include "MatchVerifier.h"<br>+<br>+namespace clang {<br>+namespace ast_matchers {<br>+<br>+using clang::tooling::newFrontendActionFactory;<br>+using clang::tooling::runToolOnCodeWithArgs;<br>+using clang::tooling::FrontendActionFactory;<br>+<br>+TEST(GetParents, ReturnsParentForDecl) {<br>+ MatchVerifier<Decl> Verifier;<br>+ EXPECT_TRUE(Verifier.match("class C { void f(); };",<br>+ methodDecl(hasParent(recordDecl(hasName("C"))))));<br>+}<br>+<br>+TEST(GetParents, ReturnsParentForStmt) {<br>+ MatchVerifier<Stmt> Verifier;<br>+ EXPECT_TRUE(Verifier.match("class C { void f() { if (true) {} } };",<br>+ ifStmt(hasParent(compoundStmt()))));<br>+}<br>+<br>+TEST(GetParents, ReturnsParentInsideTemplateInstantiations) {<br>+ MatchVerifier<Decl> DeclVerifier;<br>+ EXPECT_TRUE(DeclVerifier.match(<br>+ "template<typename T> struct C { void f() {} };"<br>+ "void g() { C<int> c; c.f(); }",<br>+ methodDecl(hasName("f"),<br>+ hasParent(recordDecl(isTemplateInstantiation())))));<br>+ EXPECT_TRUE(DeclVerifier.match(<br>+ "template<typename T> struct C { void f() {} };"<br>+ "void g() { C<int> c; c.f(); }",<br>+ methodDecl(hasName("f"),<br>+ hasParent(recordDecl(unless(isTemplateInstantiation()))))));<br>+ EXPECT_FALSE(DeclVerifier.match(<br>+ "template<typename T> struct C { void f() {} };"<br>+ "void g() { C<int> c; c.f(); }",<br>+ methodDecl(hasName("f"),<br>+ allOf(hasParent(recordDecl(unless(isTemplateInstantiation()))),<br>+ hasParent(recordDecl(isTemplateInstantiation()))))));<br>+}<br>+<br>+TEST(GetParents, ReturnsMultipleParentsInTemplateInstantiations) {<br>+ MatchVerifier<Stmt> TemplateVerifier;<br>+ EXPECT_TRUE(TemplateVerifier.match(<br>+ "template<typename T> struct C { void f() {} };"<br>+ "void g() { C<int> c; c.f(); }",<br>+ compoundStmt(<br>+ allOf(hasAncestor(recordDecl(isTemplateInstantiation())),<br>+ hasAncestor(recordDecl(unless(isTemplateInstantiation())))))));<br>+}<br>+<br>+} // end namespace ast_matchers<br>+} // end namespace clang<br><br>Modified: cfe/trunk/unittests/AST/CMakeLists.txt<br>URL:<span class="Apple-converted-space"> </span><a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/CMakeLists.txt?rev=176251&r1=176250&r2=176251&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/CMakeLists.txt?rev=176251&r1=176250&r2=176251&view=diff</a><br>==============================================================================<br>--- cfe/trunk/unittests/AST/CMakeLists.txt (original)<br>+++ cfe/trunk/unittests/AST/CMakeLists.txt Thu Feb 28 07:21:39 2013<br>@@ -1,4 +1,5 @@<br>add_clang_unittest(ASTTests<br>+ ASTContextParentMapTest.cpp<br> CommentLexer.cpp<br> CommentParser.cpp<br> DeclPrinterTest.cpp<br><br>Modified: cfe/trunk/unittests/AST/MatchVerifier.h<br>URL:<span class="Apple-converted-space"> </span><a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/MatchVerifier.h?rev=176251&r1=176250&r2=176251&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/MatchVerifier.h?rev=176251&r1=176250&r2=176251&view=diff</a><br>==============================================================================<br>--- cfe/trunk/unittests/AST/MatchVerifier.h (original)<br>+++ cfe/trunk/unittests/AST/MatchVerifier.h Thu Feb 28 07:21:39 2013<br>@@ -44,7 +44,7 @@ public:<br>protected:<br> virtual void run(const MatchFinder::MatchResult &Result);<br> virtual void verify(const MatchFinder::MatchResult &Result,<br>- const NodeType &Node) = 0;<br>+ const NodeType &Node) {}<br><br> void setFailure(const Twine &Result) {<br> Verified = false;<br><br><br>_______________________________________________<br>cfe-commits mailing list<br><a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br><a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a></div></blockquote></div><br></div></body></html>