diff options
Diffstat (limited to 'include/clang/ASTMatchers/ASTMatchersInternal.h')
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchersInternal.h | 786 |
1 files changed, 580 insertions, 206 deletions
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h index 30691ad8f912..69cee2eb5dfd 100644 --- a/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -36,12 +36,13 @@ #define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H #include "clang/AST/ASTTypeTraits.h" -#include "clang/AST/DeclCXX.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" -#include "clang/AST/StmtCXX.h" #include "clang/AST/Stmt.h" +#include "clang/AST/StmtCXX.h" #include "clang/AST/Type.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/VariadicFunction.h" #include "llvm/Support/type_traits.h" #include <map> @@ -60,7 +61,6 @@ class BoundNodes; namespace internal { -class BoundNodesTreeBuilder; /// \brief Internal version of BoundNodes. Holds all the bound nodes. class BoundNodesMap { public: @@ -71,9 +71,6 @@ public: void addNode(StringRef ID, const T* Node) { NodeMap[ID] = ast_type_traits::DynTypedNode::create(*Node); } - void addNode(StringRef ID, ast_type_traits::DynTypedNode Node) { - NodeMap[ID] = Node; - } /// \brief Returns the AST node bound to \c ID. /// @@ -88,29 +85,39 @@ public: return It->second.get<T>(); } - /// \brief Copies all ID/Node pairs to BoundNodesTreeBuilder \c Builder. - void copyTo(BoundNodesTreeBuilder *Builder) const; + ast_type_traits::DynTypedNode getNode(StringRef ID) const { + IDToNodeMap::const_iterator It = NodeMap.find(ID); + if (It == NodeMap.end()) { + return ast_type_traits::DynTypedNode(); + } + return It->second; + } - /// \brief Copies all ID/Node pairs to BoundNodesMap \c Other. - void copyTo(BoundNodesMap *Other) const; + /// \brief Imposes an order on BoundNodesMaps. + bool operator<(const BoundNodesMap &Other) const { + return NodeMap < Other.NodeMap; + } -private: /// \brief A map from IDs to the bound nodes. + /// + /// Note that we're using std::map here, as for memoization: + /// - we need a comparison operator + /// - we need an assignment operator typedef std::map<std::string, ast_type_traits::DynTypedNode> IDToNodeMap; + const IDToNodeMap &getMap() const { + return NodeMap; + } + +private: IDToNodeMap NodeMap; }; -/// \brief A tree of bound nodes in match results. -/// -/// If a match can contain multiple matches on the same node with different -/// matching subexpressions, BoundNodesTree contains a branch for each of -/// those matching subexpressions. +/// \brief Creates BoundNodesTree objects. /// -/// BoundNodesTree's are created during the matching process; when a match -/// is found, we iterate over the tree and create a BoundNodes object containing -/// the union of all bound nodes on the path from the root to a each leaf. -class BoundNodesTree { +/// The tree builder is used during the matching process to insert the bound +/// nodes from the Id matcher. +class BoundNodesTreeBuilder { public: /// \brief A visitor interface to visit all BoundNodes results for a /// BoundNodesTree. @@ -124,63 +131,36 @@ public: virtual void visitMatch(const BoundNodes& BoundNodesView) = 0; }; - BoundNodesTree(); - - /// \brief Create a BoundNodesTree from pre-filled maps of bindings. - BoundNodesTree(const BoundNodesMap& Bindings, - const std::vector<BoundNodesTree> RecursiveBindings); + /// \brief Add a binding from an id to a node. + template <typename T> void setBinding(const std::string &Id, const T *Node) { + if (Bindings.empty()) + Bindings.push_back(BoundNodesMap()); + for (unsigned i = 0, e = Bindings.size(); i != e; ++i) + Bindings[i].addNode(Id, Node); + } - /// \brief Adds all bound nodes to \c Builder. - void copyTo(BoundNodesTreeBuilder* Builder) const; + /// \brief Adds a branch in the tree. + void addMatch(const BoundNodesTreeBuilder &Bindings); /// \brief Visits all matches that this BoundNodesTree represents. /// /// The ownership of 'ResultVisitor' remains at the caller. void visitMatches(Visitor* ResultVisitor); -private: - void visitMatchesRecursively( - Visitor* ResultVistior, - const BoundNodesMap& AggregatedBindings); - - // FIXME: Find out whether we want to use different data structures here - - // first benchmarks indicate that it doesn't matter though. - - BoundNodesMap Bindings; - - std::vector<BoundNodesTree> RecursiveBindings; -}; - -/// \brief Creates BoundNodesTree objects. -/// -/// The tree builder is used during the matching process to insert the bound -/// nodes from the Id matcher. -class BoundNodesTreeBuilder { -public: - BoundNodesTreeBuilder(); - - /// \brief Add a binding from an id to a node. - template <typename T> - void setBinding(const std::string &Id, const T *Node) { - Bindings.addNode(Id, Node); - } - void setBinding(const std::string &Id, ast_type_traits::DynTypedNode Node) { - Bindings.addNode(Id, Node); + template <typename ExcludePredicate> + bool removeBindings(const ExcludePredicate &Predicate) { + Bindings.erase(std::remove_if(Bindings.begin(), Bindings.end(), Predicate), + Bindings.end()); + return !Bindings.empty(); } - /// \brief Adds a branch in the tree. - void addMatch(const BoundNodesTree& Bindings); - - /// \brief Returns a BoundNodes object containing all current bindings. - BoundNodesTree build() const; + /// \brief Imposes an order on BoundNodesTreeBuilders. + bool operator<(const BoundNodesTreeBuilder &Other) const { + return Bindings < Other.Bindings; + } private: - BoundNodesTreeBuilder(const BoundNodesTreeBuilder &) LLVM_DELETED_FUNCTION; - void operator=(const BoundNodesTreeBuilder &) LLVM_DELETED_FUNCTION; - - BoundNodesMap Bindings; - - std::vector<BoundNodesTree> RecursiveBindings; + SmallVector<BoundNodesMap, 16> Bindings; }; class ASTMatchFinder; @@ -225,24 +205,6 @@ private: } }; -/// \brief Base class for all matchers that works on a \c DynTypedNode. -/// -/// Matcher implementations will check whether the \c DynTypedNode is -/// convertible into the respecitve types and then do the actual match -/// on the actual node, or return false if it is not convertible. -class DynTypedMatcher { -public: - virtual ~DynTypedMatcher() {} - - /// \brief Returns true if the matcher matches the given \c DynNode. - virtual bool matches(const ast_type_traits::DynTypedNode DynNode, - ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder) const = 0; - - /// \brief Returns a unique ID for the matcher. - virtual uint64_t getID() const = 0; -}; - /// \brief Wrapper of a MatcherInterface<T> *that allows copying. /// /// A Matcher<Base> can be used anywhere a Matcher<Derived> is @@ -252,7 +214,7 @@ public: /// operator rather than a type hierarchy to be able to templatize the /// type hierarchy instead of spelling it out. template <typename T> -class Matcher : public DynTypedMatcher { +class Matcher { public: /// \brief Takes ownership of the provided implementation pointer. explicit Matcher(MatcherInterface<T> *Implementation) @@ -282,7 +244,13 @@ public: bool matches(const T &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { - return Implementation->matches(Node, Finder, Builder); + if (Implementation->matches(Node, Finder, Builder)) + return true; + // Delete all bindings when a matcher does not match. + // This prevents unexpected exposure of bound nodes in unmatches + // branches of the match tree. + *Builder = BoundNodesTreeBuilder(); + return false; } /// \brief Returns an ID that uniquely identifies the matcher. @@ -292,15 +260,6 @@ public: return reinterpret_cast<uint64_t>(Implementation.getPtr()); } - /// \brief Returns whether the matcher matches on the given \c DynNode. - virtual bool matches(const ast_type_traits::DynTypedNode DynNode, - ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder) const { - const T *Node = DynNode.get<T>(); - if (!Node) return false; - return matches(*Node, Finder, Builder); - } - /// \brief Allows the conversion of a \c Matcher<Type> to a \c /// Matcher<QualType>. /// @@ -353,6 +312,217 @@ inline Matcher<T> makeMatcher(MatcherInterface<T> *Implementation) { return Matcher<T>(Implementation); } +template <typename T> class BindableMatcher; + +/// \brief Matcher that works on a \c DynTypedNode. +/// +/// It is constructed from a \c Matcher<T> object and redirects most calls to +/// underlying matcher. +/// It checks whether the \c DynTypedNode is convertible into the type of the +/// underlying matcher and then do the actual match on the actual node, or +/// return false if it is not convertible. +class DynTypedMatcher { +public: + /// \brief Construct from a \c Matcher<T>. Copies the matcher. + template <typename T> inline DynTypedMatcher(const Matcher<T> &M); + + /// \brief Construct from a bindable \c Matcher<T>. Copies the matcher. + /// + /// This version enables \c tryBind() on the \c DynTypedMatcher. + template <typename T> inline DynTypedMatcher(const BindableMatcher<T> &M); + + /// \brief Returns true if the matcher matches the given \c DynNode. + bool matches(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { + return Storage->matches(DynNode, Finder, Builder); + } + + /// \brief Bind the specified \p ID to the matcher. + /// \return A new matcher with the \p ID bound to it if this matcher supports + /// binding. Otherwise, returns an empty \c Optional<>. + llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const { + return Storage->tryBind(ID); + } + + /// \brief Returns a unique \p ID for the matcher. + uint64_t getID() const { return Storage->getID(); } + + /// \brief Returns the type this matcher works on. + /// + /// \c matches() will always return false unless the node passed is of this + /// or a derived type. + ast_type_traits::ASTNodeKind getSupportedKind() const { + return Storage->getSupportedKind(); + } + + /// \brief Returns \c true if the passed \c DynTypedMatcher can be converted + /// to a \c Matcher<T>. + /// + /// This method verifies that the underlying matcher in \c Other can process + /// nodes of types T. + template <typename T> bool canConvertTo() const { + return getSupportedKind().isBaseOf( + ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); + } + + /// \brief Construct a \c Matcher<T> interface around the dynamic matcher. + /// + /// This method asserts that \c canConvertTo() is \c true. Callers + /// should call \c canConvertTo() first to make sure that \c this is + /// compatible with T. + template <typename T> Matcher<T> convertTo() const { + assert(canConvertTo<T>()); + return unconditionalConvertTo<T>(); + } + + /// \brief Same as \c convertTo(), but does not check that the underlying + /// matcher can handle a value of T. + /// + /// If it is not compatible, then this matcher will never match anything. + template <typename T> Matcher<T> unconditionalConvertTo() const { + return Matcher<T>(new WrappedMatcher<T>(*this)); + } + +private: + class MatcherStorage : public RefCountedBaseVPTR { + public: + MatcherStorage(ast_type_traits::ASTNodeKind SupportedKind, uint64_t ID) + : SupportedKind(SupportedKind), ID(ID) {} + virtual ~MatcherStorage(); + + virtual bool matches(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const = 0; + + virtual llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const = 0; + + ast_type_traits::ASTNodeKind getSupportedKind() const { + return SupportedKind; + } + + uint64_t getID() const { return ID; } + + private: + const ast_type_traits::ASTNodeKind SupportedKind; + const uint64_t ID; + }; + + /// \brief Typed implementation of \c MatcherStorage. + template <typename T> class TypedMatcherStorage; + + /// \brief Simple MatcherInterface<T> wrapper around a DynTypedMatcher. + template <typename T> class WrappedMatcher; + + IntrusiveRefCntPtr<const MatcherStorage> Storage; +}; + +template <typename T> +class DynTypedMatcher::TypedMatcherStorage : public MatcherStorage { +public: + TypedMatcherStorage(const Matcher<T> &Other, bool AllowBind) + : MatcherStorage(ast_type_traits::ASTNodeKind::getFromNodeKind<T>(), + Other.getID()), + InnerMatcher(Other), AllowBind(AllowBind) {} + + bool matches(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const + LLVM_OVERRIDE { + if (const T *Node = DynNode.get<T>()) { + return InnerMatcher.matches(*Node, Finder, Builder); + } + return false; + } + + llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const LLVM_OVERRIDE { + if (!AllowBind) + return llvm::Optional<DynTypedMatcher>(); + return DynTypedMatcher(BindableMatcher<T>(InnerMatcher).bind(ID)); + } + +private: + const Matcher<T> InnerMatcher; + const bool AllowBind; +}; + +template <typename T> +inline DynTypedMatcher::DynTypedMatcher(const Matcher<T> &M) + : Storage(new TypedMatcherStorage<T>(M, false)) {} + +template <typename T> +inline DynTypedMatcher::DynTypedMatcher(const BindableMatcher<T> &M) + : Storage(new TypedMatcherStorage<T>(M, true)) {} + +template <typename T> +class DynTypedMatcher::WrappedMatcher : public MatcherInterface<T> { +public: + explicit WrappedMatcher(const DynTypedMatcher &Matcher) : Inner(Matcher) {} + virtual ~WrappedMatcher() {} + + bool matches(const T &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + return Inner.matches(ast_type_traits::DynTypedNode::create(Node), Finder, + Builder); + } + +private: + const DynTypedMatcher Inner; +}; + +/// \brief Specialization of the conversion functions for QualType. +/// +/// These specializations provide the Matcher<Type>->Matcher<QualType> +/// conversion that the static API does. +template <> inline bool DynTypedMatcher::canConvertTo<QualType>() const { + const ast_type_traits::ASTNodeKind SourceKind = getSupportedKind(); + return SourceKind.isSame( + ast_type_traits::ASTNodeKind::getFromNodeKind<Type>()) || + SourceKind.isSame( + ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>()); +} + +template <> +inline Matcher<QualType> DynTypedMatcher::convertTo<QualType>() const { + assert(canConvertTo<QualType>()); + const ast_type_traits::ASTNodeKind SourceKind = getSupportedKind(); + if (SourceKind.isSame( + ast_type_traits::ASTNodeKind::getFromNodeKind<Type>())) { + // We support implicit conversion from Matcher<Type> to Matcher<QualType> + return unconditionalConvertTo<Type>(); + } + return unconditionalConvertTo<QualType>(); +} + +/// \brief Finds the first node in a range that matches the given matcher. +template <typename MatcherT, typename IteratorT> +bool matchesFirstInRange(const MatcherT &Matcher, IteratorT Start, + IteratorT End, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) { + for (IteratorT I = Start; I != End; ++I) { + BoundNodesTreeBuilder Result(*Builder); + if (Matcher.matches(*I, Finder, &Result)) { + *Builder = Result; + return true; + } + } + return false; +} + +/// \brief Finds the first node in a pointer range that matches the given +/// matcher. +template <typename MatcherT, typename IteratorT> +bool matchesFirstInPointerRange(const MatcherT &Matcher, IteratorT Start, + IteratorT End, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) { + for (IteratorT I = Start; I != End; ++I) { + BoundNodesTreeBuilder Result(*Builder); + if (Matcher.matches(**I, Finder, &Result)) { + *Builder = Result; + return true; + } + } + return false; +} + /// \brief Metafunction to determine if type T has a member called getDecl. template <typename T> struct has_getDecl { struct Default { int getDecl; }; @@ -632,6 +802,94 @@ protected: AncestorMatchMode MatchMode) = 0; }; +/// \brief A type-list implementation. +/// +/// A list is declared as a tree of type list nodes, where the leafs are the +/// types. +/// However, it is used as a "linked list" of types, by using the ::head and +/// ::tail typedefs. +/// Each node supports up to 4 children (instead of just 2) to reduce the +/// nesting required by large lists. +template <typename T1 = void, typename T2 = void, typename T3 = void, + typename T4 = void> +struct TypeList { + /// \brief Implementation detail. Combined with the specializations below, + /// this typedef allows for flattening of nested structures. + typedef TypeList<T1, T2, T3, T4> self; + + /// \brief The first type on the list. + typedef T1 head; + + /// \brief A sub list with the tail. ie everything but the head. + /// + /// This type is used to do recursion. TypeList<>/EmptyTypeList indicates the + /// end of the list. + typedef typename TypeList<T2, T3, T4>::self tail; +}; + +/// \brief Template specialization to allow nested lists. +/// +/// First element is a typelist. Pop its first element. +template <typename Sub1, typename Sub2, typename Sub3, typename Sub4, + typename T2, typename T3, typename T4> +struct TypeList<TypeList<Sub1, Sub2, Sub3, Sub4>, T2, T3, + T4> : public TypeList<Sub1, + typename TypeList<Sub2, Sub3, Sub4>::self, + typename TypeList<T2, T3, T4>::self> {}; + +/// \brief Template specialization to allow nested lists. +/// +/// First element is an empty typelist. Skip it. +template <typename T2, typename T3, typename T4> +struct TypeList<TypeList<>, T2, T3, T4> : public TypeList<T2, T3, T4> { +}; + +/// \brief The empty type list. +typedef TypeList<> EmptyTypeList; + +/// \brief Helper meta-function to determine if some type \c T is present or +/// a parent type in the list. +template <typename AnyTypeList, typename T> +struct TypeListContainsSuperOf { + static const bool value = + llvm::is_base_of<typename AnyTypeList::head, T>::value || + TypeListContainsSuperOf<typename AnyTypeList::tail, T>::value; +}; +template <typename T> +struct TypeListContainsSuperOf<EmptyTypeList, T> { + static const bool value = false; +}; + +/// \brief A "type list" that contains all types. +/// +/// Useful for matchers like \c anything and \c unless. +typedef TypeList< + TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc>, + TypeList<QualType, Type, TypeLoc, CXXCtorInitializer> > AllNodeBaseTypes; + +/// \brief Helper meta-function to extract the argument out of a function of +/// type void(Arg). +/// +/// See AST_POLYMORPHIC_SUPPORTED_TYPES_* for details. +template <class T> struct ExtractFunctionArgMeta; +template <class T> struct ExtractFunctionArgMeta<void(T)> { + typedef T type; +}; + +/// \brief Default type lists for ArgumentAdaptingMatcher matchers. +typedef AllNodeBaseTypes AdaptativeDefaultFromTypes; +typedef TypeList<TypeList<Decl, Stmt, NestedNameSpecifier>, + TypeList<NestedNameSpecifierLoc, TypeLoc, QualType> > +AdaptativeDefaultToTypes; + +/// \brief All types that are supported by HasDeclarationMatcher above. +typedef TypeList<TypeList<CallExpr, CXXConstructExpr, DeclRefExpr, EnumType>, + TypeList<InjectedClassNameType, LabelStmt, MemberExpr>, + TypeList<QualType, RecordType, TagType>, + TypeList<TemplateSpecializationType, TemplateTypeParmType, + TypedefType, UnresolvedUsingType> > +HasDeclarationSupportedTypes; + /// \brief Converts a \c Matcher<T> to a matcher of desired type \c To by /// "adapting" a \c To into a \c T. /// @@ -646,19 +904,33 @@ protected: /// If a matcher does not need knowledge about the inner type, prefer to use /// PolymorphicMatcherWithParam1. template <template <typename ToArg, typename FromArg> class ArgumentAdapterT, - typename T> -class ArgumentAdaptingMatcher { -public: - explicit ArgumentAdaptingMatcher(const Matcher<T> &InnerMatcher) - : InnerMatcher(InnerMatcher) {} + typename FromTypes = AdaptativeDefaultFromTypes, + typename ToTypes = AdaptativeDefaultToTypes> +struct ArgumentAdaptingMatcherFunc { + template <typename T> class Adaptor { + public: + explicit Adaptor(const Matcher<T> &InnerMatcher) + : InnerMatcher(InnerMatcher) {} - template <typename To> - operator Matcher<To>() const { - return Matcher<To>(new ArgumentAdapterT<To, T>(InnerMatcher)); + typedef ToTypes ReturnTypes; + + template <typename To> operator Matcher<To>() const { + return Matcher<To>(new ArgumentAdapterT<To, T>(InnerMatcher)); + } + + private: + const Matcher<T> InnerMatcher; + }; + + template <typename T> + static Adaptor<T> create(const Matcher<T> &InnerMatcher) { + return Adaptor<T>(InnerMatcher); } -private: - const Matcher<T> InnerMatcher; + template <typename T> + Adaptor<T> operator()(const Matcher<T> &InnerMatcher) const { + return create(InnerMatcher); + } }; /// \brief A PolymorphicMatcherWithParamN<MatcherT, P1, ..., PN> object can be @@ -673,24 +945,33 @@ private: /// - PolymorphicMatcherWithParam1<ValueEqualsMatcher, int>(42) /// creates an object that can be used as a Matcher<T> for any type T /// where a ValueEqualsMatcher<T, int>(42) can be constructed. -template <template <typename T> class MatcherT> +template <template <typename T> class MatcherT, + typename ReturnTypesF = void(AllNodeBaseTypes)> class PolymorphicMatcherWithParam0 { public: + typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes; template <typename T> operator Matcher<T>() const { + TOOLING_COMPILE_ASSERT((TypeListContainsSuperOf<ReturnTypes, T>::value), + right_polymorphic_conversion); return Matcher<T>(new MatcherT<T>()); } }; template <template <typename T, typename P1> class MatcherT, - typename P1> + typename P1, + typename ReturnTypesF = void(AllNodeBaseTypes)> class PolymorphicMatcherWithParam1 { public: explicit PolymorphicMatcherWithParam1(const P1 &Param1) : Param1(Param1) {} + typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes; + template <typename T> operator Matcher<T>() const { + TOOLING_COMPILE_ASSERT((TypeListContainsSuperOf<ReturnTypes, T>::value), + right_polymorphic_conversion); return Matcher<T>(new MatcherT<T, P1>(Param1)); } @@ -699,14 +980,19 @@ private: }; template <template <typename T, typename P1, typename P2> class MatcherT, - typename P1, typename P2> + typename P1, typename P2, + typename ReturnTypesF = void(AllNodeBaseTypes)> class PolymorphicMatcherWithParam2 { public: PolymorphicMatcherWithParam2(const P1 &Param1, const P2 &Param2) : Param1(Param1), Param2(Param2) {} + typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes; + template <typename T> operator Matcher<T>() const { + TOOLING_COMPILE_ASSERT((TypeListContainsSuperOf<ReturnTypes, T>::value), + right_polymorphic_conversion); return Matcher<T>(new MatcherT<T, P1, P2>(Param1, Param2)); } @@ -737,27 +1023,6 @@ public: } }; -/// \brief Provides a MatcherInterface<T> for a Matcher<To> that matches if T is -/// dyn_cast'able into To and the given Matcher<To> matches on the dyn_cast'ed -/// node. -template <typename T, typename To> -class DynCastMatcher : public MatcherInterface<T> { -public: - explicit DynCastMatcher(const Matcher<To> &InnerMatcher) - : InnerMatcher(InnerMatcher) {} - - virtual bool matches(const T &Node, - ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder) const { - const To *InnerMatchValue = dyn_cast<To>(&Node); - return InnerMatchValue != NULL && - InnerMatcher.matches(*InnerMatchValue, Finder, Builder); - } - -private: - const Matcher<To> InnerMatcher; -}; - /// \brief Matcher<T> that wraps an inner Matcher<T> and binds the matched node /// to an ID if the inner matcher matches on the node. template <typename T> @@ -790,7 +1055,8 @@ private: template <typename T> class BindableMatcher : public Matcher<T> { public: - BindableMatcher(MatcherInterface<T> *Implementation) + explicit BindableMatcher(const Matcher<T> &M) : Matcher<T>(M) {} + explicit BindableMatcher(MatcherInterface<T> *Implementation) : Matcher<T>(Implementation) {} /// \brief Returns a matcher that will bind the matched node on a match. @@ -867,108 +1133,172 @@ public: virtual bool matches(const T &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { - return !InnerMatcher.matches(Node, Finder, Builder); + // The 'unless' matcher will always discard the result: + // If the inner matcher doesn't match, unless returns true, + // but the inner matcher cannot have bound anything. + // If the inner matcher matches, the result is false, and + // any possible binding will be discarded. + // We still need to hand in all the bound nodes up to this + // point so the inner matcher can depend on bound nodes, + // and we need to actively discard the bound nodes, otherwise + // the inner matcher will reset the bound nodes if it doesn't + // match, but this would be inversed by 'unless'. + BoundNodesTreeBuilder Discard(*Builder); + return !InnerMatcher.matches(Node, Finder, &Discard); } private: const Matcher<T> InnerMatcher; }; -/// \brief Matches nodes of type T for which both provided matchers match. -/// -/// Type arguments MatcherT1 and MatcherT2 are required by -/// PolymorphicMatcherWithParam2 but not actually used. They will -/// always be instantiated with types convertible to Matcher<T>. -template <typename T, typename MatcherT1, typename MatcherT2> -class AllOfMatcher : public MatcherInterface<T> { +/// \brief VariadicOperatorMatcher related types. +/// @{ + +/// \brief Function signature for any variadic operator. It takes the inner +/// matchers as an array of DynTypedMatcher. +typedef bool (*VariadicOperatorFunction)( + const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); + +/// \brief \c MatcherInterface<T> implementation for an variadic operator. +template <typename T> +class VariadicOperatorMatcherInterface : public MatcherInterface<T> { public: - AllOfMatcher(const Matcher<T> &InnerMatcher1, const Matcher<T> &InnerMatcher2) - : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {} + VariadicOperatorMatcherInterface(VariadicOperatorFunction Func, + ArrayRef<const Matcher<T> *> InputMatchers) + : Func(Func) { + for (size_t i = 0, e = InputMatchers.size(); i != e; ++i) { + InnerMatchers.push_back(*InputMatchers[i]); + } + } - virtual bool matches(const T &Node, - ASTMatchFinder *Finder, + virtual bool matches(const T &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { - return InnerMatcher1.matches(Node, Finder, Builder) && - InnerMatcher2.matches(Node, Finder, Builder); + return Func(ast_type_traits::DynTypedNode::create(Node), Finder, Builder, + InnerMatchers); } private: - const Matcher<T> InnerMatcher1; - const Matcher<T> InnerMatcher2; + const VariadicOperatorFunction Func; + std::vector<DynTypedMatcher> InnerMatchers; }; -/// \brief Matches nodes of type T for which at least one of the two provided -/// matchers matches. +/// \brief "No argument" placeholder to use as template paratemers. +struct VariadicOperatorNoArg {}; + +/// \brief Polymorphic matcher object that uses a \c VariadicOperatorFunction +/// operator. /// -/// Type arguments MatcherT1 and MatcherT2 are -/// required by PolymorphicMatcherWithParam2 but not actually -/// used. They will always be instantiated with types convertible to -/// Matcher<T>. -template <typename T, typename MatcherT1, typename MatcherT2> -class EachOfMatcher : public MatcherInterface<T> { +/// Input matchers can have any type (including other polymorphic matcher +/// types), and the actual Matcher<T> is generated on demand with an implicit +/// coversion operator. +template <typename P1, typename P2, + typename P3 = VariadicOperatorNoArg, + typename P4 = VariadicOperatorNoArg, + typename P5 = VariadicOperatorNoArg> +class VariadicOperatorMatcher { public: - EachOfMatcher(const Matcher<T> &InnerMatcher1, - const Matcher<T> &InnerMatcher2) - : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) { + VariadicOperatorMatcher(VariadicOperatorFunction Func, const P1 &Param1, + const P2 &Param2, + const P3 &Param3 = VariadicOperatorNoArg(), + const P4 &Param4 = VariadicOperatorNoArg(), + const P5 &Param5 = VariadicOperatorNoArg()) + : Func(Func), Param1(Param1), Param2(Param2), Param3(Param3), + Param4(Param4), Param5(Param5) {} + + template <typename T> operator Matcher<T>() const { + Matcher<T> *Array[5]; + size_t Size = 0; + + addMatcher<T>(Param1, Array, Size); + addMatcher<T>(Param2, Array, Size); + addMatcher<T>(Param3, Array, Size); + addMatcher<T>(Param4, Array, Size); + addMatcher<T>(Param5, Array, Size); + Matcher<T> Result(new VariadicOperatorMatcherInterface<T>( + Func, ArrayRef<const Matcher<T> *>(Array, Size))); + for (size_t i = 0, e = Size; i != e; ++i) delete Array[i]; + return Result; } - virtual bool matches(const T &Node, ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder) const { - BoundNodesTreeBuilder Builder1; - bool Matched1 = InnerMatcher1.matches(Node, Finder, &Builder1); - if (Matched1) - Builder->addMatch(Builder1.build()); - - BoundNodesTreeBuilder Builder2; - bool Matched2 = InnerMatcher2.matches(Node, Finder, &Builder2); - if (Matched2) - Builder->addMatch(Builder2.build()); - - return Matched1 || Matched2; +private: + template <typename T> + static void addMatcher(const Matcher<T> &M, Matcher<T> **Array, + size_t &Size) { + Array[Size++] = new Matcher<T>(M); } -private: - const Matcher<T> InnerMatcher1; - const Matcher<T> InnerMatcher2; + /// \brief Overload to ignore \c VariadicOperatorNoArg arguments. + template <typename T> + static void addMatcher(VariadicOperatorNoArg, Matcher<T> **Array, + size_t &Size) {} + + const VariadicOperatorFunction Func; + const P1 Param1; + const P2 Param2; + const P3 Param3; + const P4 Param4; + const P5 Param5; }; -/// \brief Matches nodes of type T for which at least one of the two provided -/// matchers matches. +/// \brief Overloaded function object to generate VariadicOperatorMatcher +/// objects from arbitrary matchers. /// -/// Type arguments MatcherT1 and MatcherT2 are -/// required by PolymorphicMatcherWithParam2 but not actually -/// used. They will always be instantiated with types convertible to -/// Matcher<T>. -template <typename T, typename MatcherT1, typename MatcherT2> -class AnyOfMatcher : public MatcherInterface<T> { -public: - AnyOfMatcher(const Matcher<T> &InnerMatcher1, const Matcher<T> &InnerMatcher2) - : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {} +/// It supports 2-5 argument overloaded operator(). More can be added if needed. +struct VariadicOperatorMatcherFunc { + VariadicOperatorFunction Func; - virtual bool matches(const T &Node, - ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder) const { - return InnerMatcher1.matches(Node, Finder, Builder) || - InnerMatcher2.matches(Node, Finder, Builder); + template <typename M1, typename M2> + VariadicOperatorMatcher<M1, M2> operator()(const M1 &P1, const M2 &P2) const { + return VariadicOperatorMatcher<M1, M2>(Func, P1, P2); + } + template <typename M1, typename M2, typename M3> + VariadicOperatorMatcher<M1, M2, M3> operator()(const M1 &P1, const M2 &P2, + const M3 &P3) const { + return VariadicOperatorMatcher<M1, M2, M3>(Func, P1, P2, P3); + } + template <typename M1, typename M2, typename M3, typename M4> + VariadicOperatorMatcher<M1, M2, M3, M4> + operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) const { + return VariadicOperatorMatcher<M1, M2, M3, M4>(Func, P1, P2, P3, P4); + } + template <typename M1, typename M2, typename M3, typename M4, typename M5> + VariadicOperatorMatcher<M1, M2, M3, M4, M5> + operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, + const M5 &P5) const { + return VariadicOperatorMatcher<M1, M2, M3, M4, M5>(Func, P1, P2, P3, P4, + P5); } - -private: - const Matcher<T> InnerMatcher1; - const Matcher<T> InnerMatcher2; }; +/// @} + +/// \brief Matches nodes for which all provided matchers match. +bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder, + ArrayRef<DynTypedMatcher> InnerMatchers); + +/// \brief Matches nodes for which at least one of the provided matchers +/// matches, but doesn't stop at the first match. +bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder, + ArrayRef<DynTypedMatcher> InnerMatchers); + +/// \brief Matches nodes for which at least one of the provided matchers +/// matches. +bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder, + ArrayRef<DynTypedMatcher> InnerMatchers); + /// \brief Creates a Matcher<T> that matches if all inner matchers match. template<typename T> BindableMatcher<T> makeAllOfComposite( ArrayRef<const Matcher<T> *> InnerMatchers) { - if (InnerMatchers.empty()) - return BindableMatcher<T>(new TrueMatcher<T>); - MatcherInterface<T> *InnerMatcher = new TrueMatcher<T>; - for (int i = InnerMatchers.size() - 1; i >= 0; --i) { - InnerMatcher = new AllOfMatcher<T, Matcher<T>, Matcher<T> >( - *InnerMatchers[i], makeMatcher(InnerMatcher)); - } - return BindableMatcher<T>(InnerMatcher); + return BindableMatcher<T>(new VariadicOperatorMatcherInterface<T>( + AllOfVariadicOperator, InnerMatchers)); } /// \brief Creates a Matcher<T> that matches if @@ -980,8 +1310,8 @@ BindableMatcher<T> makeAllOfComposite( template<typename T, typename InnerT> BindableMatcher<T> makeDynCastAllOfComposite( ArrayRef<const Matcher<InnerT> *> InnerMatchers) { - return BindableMatcher<T>(new DynCastMatcher<T, InnerT>( - makeAllOfComposite(InnerMatchers))); + return BindableMatcher<T>(DynTypedMatcher(makeAllOfComposite(InnerMatchers)) + .unconditionalConvertTo<T>()); } /// \brief Matches nodes of type T that have at least one descendant node of @@ -1233,9 +1563,53 @@ private: TypeLoc (T::*TraverseFunction)() const; }; -template <typename T, typename InnerT> -T makeTypeAllOfComposite(ArrayRef<const Matcher<InnerT> *> InnerMatchers) { - return T(makeAllOfComposite<InnerT>(InnerMatchers)); +/// \brief Converts a \c Matcher<InnerT> to a \c Matcher<OuterT>, where +/// \c OuterT is any type that is supported by \c Getter. +/// +/// \code Getter<OuterT>::value() \endcode returns a +/// \code InnerTBase (OuterT::*)() \endcode, which is used to adapt a \c OuterT +/// object into a \c InnerT +template <typename InnerTBase, + template <typename OuterT> class Getter, + template <typename OuterT> class MatcherImpl, + typename ReturnTypesF> +class TypeTraversePolymorphicMatcher { +private: + typedef TypeTraversePolymorphicMatcher<InnerTBase, Getter, MatcherImpl, + ReturnTypesF> Self; + static Self create(ArrayRef<const Matcher<InnerTBase> *> InnerMatchers); + +public: + typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes; + + explicit TypeTraversePolymorphicMatcher( + ArrayRef<const Matcher<InnerTBase> *> InnerMatchers) + : InnerMatcher(makeAllOfComposite(InnerMatchers)) {} + + template <typename OuterT> operator Matcher<OuterT>() const { + return Matcher<OuterT>( + new MatcherImpl<OuterT>(InnerMatcher, Getter<OuterT>::value())); + } + + struct Func : public llvm::VariadicFunction<Self, Matcher<InnerTBase>, + &Self::create> { + Func() {} + }; + +private: + const Matcher<InnerTBase> InnerMatcher; +}; + +// Define the create() method out of line to silence a GCC warning about +// the struct "Func" having greater visibility than its base, which comes from +// using the flag -fvisibility-inlines-hidden. +template <typename InnerTBase, template <typename OuterT> class Getter, + template <typename OuterT> class MatcherImpl, typename ReturnTypesF> +TypeTraversePolymorphicMatcher<InnerTBase, Getter, MatcherImpl, ReturnTypesF> +TypeTraversePolymorphicMatcher< + InnerTBase, Getter, MatcherImpl, + ReturnTypesF>::create(ArrayRef<const Matcher<InnerTBase> *> InnerMatchers) { + return Self(InnerMatchers); } } // end namespace internal |