diff options
Diffstat (limited to 'include/clang/ASTMatchers')
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchFinder.h | 21 | ||||
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchers.h | 718 | ||||
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchersInternal.h | 786 | ||||
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchersMacros.h | 189 | ||||
-rw-r--r-- | include/clang/ASTMatchers/Dynamic/Diagnostics.h | 185 | ||||
-rw-r--r-- | include/clang/ASTMatchers/Dynamic/Parser.h | 151 | ||||
-rw-r--r-- | include/clang/ASTMatchers/Dynamic/Registry.h | 75 | ||||
-rw-r--r-- | include/clang/ASTMatchers/Dynamic/VariantValue.h | 261 |
8 files changed, 1802 insertions, 584 deletions
diff --git a/include/clang/ASTMatchers/ASTMatchFinder.h b/include/clang/ASTMatchers/ASTMatchFinder.h index 870a39b..db0a83d 100644 --- a/include/clang/ASTMatchers/ASTMatchFinder.h +++ b/include/clang/ASTMatchers/ASTMatchFinder.h @@ -97,6 +97,11 @@ public: /// /// Optionally override to do per translation unit tasks. virtual void onStartOfTranslationUnit() {} + + /// \brief Called at the end of each translation unit. + /// + /// Optionally override to do per translation unit tasks. + virtual void onEndOfTranslationUnit() {} }; /// \brief Called when parsing is finished. Intended for testing only. @@ -131,6 +136,17 @@ public: MatchCallback *Action); /// @} + /// \brief Adds a matcher to execute when running over the AST. + /// + /// This is similar to \c addMatcher(), but it uses the dynamic interface. It + /// is more flexible, but the lost type information enables a caller to pass + /// a matcher that cannot match anything. + /// + /// \returns \c true if the matcher is a valid top-level matcher, \c false + /// otherwise. + bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, + MatchCallback *Action); + /// \brief Creates a clang ASTConsumer that finds all matches. clang::ASTConsumer *newASTConsumer(); @@ -147,6 +163,9 @@ public: ASTContext &Context); /// @} + /// \brief Finds all matches in the given AST. + void matchAST(ASTContext &Context); + /// \brief Registers a callback to notify the end of parsing. /// /// The provided closure is called after parsing is done, before the AST is @@ -157,7 +176,7 @@ public: private: /// \brief For each \c DynTypedMatcher a \c MatchCallback that will be called /// when it matches. - std::vector<std::pair<const internal::DynTypedMatcher*, MatchCallback*> > + std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> > MatcherCallbackPairs; /// \brief Called when parsing is done. diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index ab62dd0..0a3157d 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/include/clang/ASTMatchers/ASTMatchers.h @@ -45,6 +45,7 @@ #ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H #define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H +#include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" #include "clang/ASTMatchers/ASTMatchersInternal.h" #include "clang/ASTMatchers/ASTMatchersMacros.h" @@ -85,6 +86,16 @@ public: } /// @} + /// \brief Type of mapping from binding identifiers to bound nodes. This type + /// is an associative container with a key type of \c std::string and a value + /// type of \c clang::ast_type_traits::DynTypedNode + typedef internal::BoundNodesMap::IDToNodeMap IDToNodeMap; + + /// \brief Retrieve mapping from binding identifiers to bound nodes. + const IDToNodeMap &getMap() const { + return MyBoundNodes.getMap(); + } + private: /// \brief Create BoundNodes from a pre-filled map of bindings. BoundNodes(internal::BoundNodesMap &MyBoundNodes) @@ -92,7 +103,7 @@ private: internal::BoundNodesMap MyBoundNodes; - friend class internal::BoundNodesTree; + friend class internal::BoundNodesTreeBuilder; }; /// \brief If the provided matcher matches a node, binds the node to \c ID. @@ -204,6 +215,28 @@ const internal::VariadicDynCastAllOfMatcher< Decl, ClassTemplateSpecializationDecl> classTemplateSpecializationDecl; +/// \brief Matches declarator declarations (field, variable, function +/// and non-type template parameter declarations). +/// +/// Given +/// \code +/// class X { int y; }; +/// \endcode +/// declaratorDecl() +/// matches \c int y. +const internal::VariadicDynCastAllOfMatcher<Decl, DeclaratorDecl> + declaratorDecl; + +/// \brief Matches parameter variable declarations. +/// +/// Given +/// \code +/// void f(int x); +/// \endcode +/// parmVarDecl() +/// matches \c int x. +const internal::VariadicDynCastAllOfMatcher<Decl, ParmVarDecl> parmVarDecl; + /// \brief Matches C++ access specifier declarations. /// /// Given @@ -219,6 +252,17 @@ const internal::VariadicDynCastAllOfMatcher< Decl, AccessSpecDecl> accessSpecDecl; +/// \brief Matches constructor initializers. +/// +/// Examples matches \c i(42). +/// \code +/// class C { +/// C() : i(42) {} +/// int i; +/// }; +/// \endcode +const internal::VariadicAllOfMatcher<CXXCtorInitializer> ctorInitializer; + /// \brief Matches public C++ declarations. /// /// Given @@ -281,12 +325,9 @@ AST_MATCHER(Decl, isPrivate) { /// matches the specialization \c A<int> AST_MATCHER_P(ClassTemplateSpecializationDecl, hasAnyTemplateArgument, internal::Matcher<TemplateArgument>, InnerMatcher) { - const TemplateArgumentList &List = Node.getTemplateArgs(); - for (unsigned i = 0; i < List.size(); ++i) { - if (InnerMatcher.matches(List.get(i), Finder, Builder)) - return true; - } - return false; + llvm::ArrayRef<TemplateArgument> List = Node.getTemplateArgs().asArray(); + return matchesFirstInRange(InnerMatcher, List.begin(), List.end(), Finder, + Builder); } /// \brief Matches expressions that match InnerMatcher after any implicit casts @@ -520,6 +561,16 @@ const internal::VariadicDynCastAllOfMatcher< Decl, FunctionTemplateDecl> functionTemplateDecl; +/// \brief Matches friend declarations. +/// +/// Given +/// \code +/// class X { friend void foo(); }; +/// \endcode +/// friendDecl() +/// matches 'friend void foo()'. +const internal::VariadicDynCastAllOfMatcher<Decl, FriendDecl> friendDecl; + /// \brief Matches statements. /// /// Given @@ -607,6 +658,21 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, InitListExpr> initListExpr; /// matches \code using X::x \endcode const internal::VariadicDynCastAllOfMatcher<Decl, UsingDecl> usingDecl; +/// \brief Matches unresolved using value declarations. +/// +/// Given +/// \code +/// template<typename X> +/// class C : private X { +/// using X::x; +/// }; +/// \endcode +/// unresolvedUsingValueDecl() +/// matches \code using X::x \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + UnresolvedUsingValueDecl> unresolvedUsingValueDecl; + /// \brief Matches constructor call expressions (including implicit ones). /// /// Example matches string(ptr, n) and ptr within arguments of f @@ -621,6 +687,18 @@ const internal::VariadicDynCastAllOfMatcher< Stmt, CXXConstructExpr> constructExpr; +/// \brief Matches unresolved constructor call expressions. +/// +/// Example matches T(t) in return statement of f +/// (matcher = unresolvedConstructExpr()) +/// \code +/// template <typename T> +/// void f(const T& t) { return T(t); } +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXUnresolvedConstructExpr> unresolvedConstructExpr; + /// \brief Matches implicit and explicit this expressions. /// /// Example matches the implicit this expression in "return i". @@ -894,6 +972,26 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchStmt> switchStmt; /// matches 'case 42: break;' and 'default: break;'. const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchCase> switchCase; +/// \brief Matches case statements inside switch statements. +/// +/// Given +/// \code +/// switch(a) { case 42: break; default: break; } +/// \endcode +/// caseStmt() +/// matches 'case 42: break;'. +const internal::VariadicDynCastAllOfMatcher<Stmt, CaseStmt> caseStmt; + +/// \brief Matches default statements inside switch statements. +/// +/// Given +/// \code +/// switch(a) { case 42: break; default: break; } +/// \endcode +/// defaultStmt() +/// matches 'default: break;'. +const internal::VariadicDynCastAllOfMatcher<Stmt, DefaultStmt> defaultStmt; + /// \brief Matches compound statements. /// /// Example matches '{}' and '{{}}'in 'for (;;) {{}}' @@ -981,15 +1079,25 @@ const internal::VariadicDynCastAllOfMatcher< Stmt, CharacterLiteral> characterLiteral; -/// \brief Matches integer literals of all sizes / encodings. -/// -/// Not matching character-encoded integers such as L'a'. +/// \brief Matches integer literals of all sizes / encodings, e.g. +/// 1, 1L, 0x1 and 1U. /// -/// Example matches 1, 1L, 0x1, 1U +/// Does not match character-encoded integers such as L'a'. const internal::VariadicDynCastAllOfMatcher< Stmt, IntegerLiteral> integerLiteral; +/// \brief Matches float literals of all sizes / encodings, e.g. +/// 1.0, 1.0f, 1.0L and 1e10. +/// +/// Does not match implicit conversions such as +/// \code +/// float a = 10; +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + FloatingLiteral> floatLiteral; + /// \brief Matches user defined literal operator call. /// /// Example match: "foo"_suffix @@ -1171,6 +1279,16 @@ const internal::VariadicDynCastAllOfMatcher< Stmt, CXXFunctionalCastExpr> functionalCastExpr; +/// \brief Matches functional cast expressions having N != 1 arguments +/// +/// Example: Matches Foo(bar, bar) +/// \code +/// Foo h = Foo(bar, bar); +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXTemporaryObjectExpr> temporaryObjectExpr; + /// \brief Matches \c QualTypes in the clang AST. const internal::VariadicAllOfMatcher<QualType> qualType; @@ -1199,93 +1317,23 @@ const internal::VariadicAllOfMatcher<TypeLoc> typeLoc; /// \c b. /// /// Usable as: Any Matcher -template <typename M1, typename M2> -internal::PolymorphicMatcherWithParam2<internal::EachOfMatcher, M1, M2> -eachOf(const M1 &P1, const M2 &P2) { - return internal::PolymorphicMatcherWithParam2<internal::EachOfMatcher, M1, - M2>(P1, P2); -} - -/// \brief Various overloads for the anyOf matcher. -/// @{ +const internal::VariadicOperatorMatcherFunc eachOf = { + internal::EachOfVariadicOperator +}; /// \brief Matches if any of the given matchers matches. /// /// Usable as: Any Matcher -template<typename M1, typename M2> -internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M1, M2> -anyOf(const M1 &P1, const M2 &P2) { - return internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, - M1, M2 >(P1, P2); -} -template<typename M1, typename M2, typename M3> -internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M1, - internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M2, M3> > -anyOf(const M1 &P1, const M2 &P2, const M3 &P3) { - return anyOf(P1, anyOf(P2, P3)); -} -template<typename M1, typename M2, typename M3, typename M4> -internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M1, - internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M2, - internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, - M3, M4> > > -anyOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) { - return anyOf(P1, anyOf(P2, anyOf(P3, P4))); -} -template<typename M1, typename M2, typename M3, typename M4, typename M5> -internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M1, - internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M2, - internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M3, - internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, - M4, M5> > > > -anyOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5) { - return anyOf(P1, anyOf(P2, anyOf(P3, anyOf(P4, P5)))); -} - -/// @} - -/// \brief Various overloads for the allOf matcher. -/// @{ +const internal::VariadicOperatorMatcherFunc anyOf = { + internal::AnyOfVariadicOperator +}; /// \brief Matches if all given matchers match. /// /// Usable as: Any Matcher -template <typename M1, typename M2> -internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, M1, M2> -allOf(const M1 &P1, const M2 &P2) { - return internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, M1, M2>( - P1, P2); -} -template <typename M1, typename M2, typename M3> -internal::PolymorphicMatcherWithParam2< - internal::AllOfMatcher, M1, - internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, M2, M3> > -allOf(const M1 &P1, const M2 &P2, const M3 &P3) { - return allOf(P1, allOf(P2, P3)); -} -template <typename M1, typename M2, typename M3, typename M4> -internal::PolymorphicMatcherWithParam2< - internal::AllOfMatcher, M1, - internal::PolymorphicMatcherWithParam2< - internal::AllOfMatcher, M2, internal::PolymorphicMatcherWithParam2< - internal::AllOfMatcher, M3, M4> > > -allOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) { - return allOf(P1, allOf(P2, P3, P4)); -} -template <typename M1, typename M2, typename M3, typename M4, typename M5> -internal::PolymorphicMatcherWithParam2< - internal::AllOfMatcher, M1, - internal::PolymorphicMatcherWithParam2< - internal::AllOfMatcher, M2, - internal::PolymorphicMatcherWithParam2< - internal::AllOfMatcher, M3, - internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, M4, - M5> > > > -allOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5) { - return allOf(P1, allOf(P2, P3, P4, P5)); -} - -/// @} +const internal::VariadicOperatorMatcherFunc allOf = { + internal::AllOfVariadicOperator +}; /// \brief Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL) /// @@ -1412,10 +1460,13 @@ AST_MATCHER_P(NamedDecl, matchesName, std::string, RegExp) { /// /// Usable as: Matcher<CXXOperatorCallExpr>, Matcher<CXXMethodDecl> inline internal::PolymorphicMatcherWithParam1< - internal::HasOverloadedOperatorNameMatcher, StringRef> + internal::HasOverloadedOperatorNameMatcher, StringRef, + AST_POLYMORPHIC_SUPPORTED_TYPES_2(CXXOperatorCallExpr, CXXMethodDecl)> hasOverloadedOperatorName(const StringRef Name) { return internal::PolymorphicMatcherWithParam1< - internal::HasOverloadedOperatorNameMatcher, StringRef>(Name); + internal::HasOverloadedOperatorNameMatcher, StringRef, + AST_POLYMORPHIC_SUPPORTED_TYPES_2(CXXOperatorCallExpr, CXXMethodDecl)>( + Name); } /// \brief Matches C++ classes that are directly or indirectly derived from @@ -1445,24 +1496,25 @@ AST_MATCHER_P(CXXRecordDecl, isDerivedFrom, } /// \brief Overloaded method as shortcut for \c isDerivedFrom(hasName(...)). -inline internal::Matcher<CXXRecordDecl> isDerivedFrom(StringRef BaseName) { +AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDerivedFrom, StringRef, BaseName, 1) { assert(!BaseName.empty()); - return isDerivedFrom(hasName(BaseName)); + return isDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder); } /// \brief Similar to \c isDerivedFrom(), but also matches classes that directly /// match \c Base. -inline internal::Matcher<CXXRecordDecl> isSameOrDerivedFrom( - internal::Matcher<NamedDecl> Base) { - return anyOf(Base, isDerivedFrom(Base)); +AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, + internal::Matcher<NamedDecl>, Base, 0) { + return Matcher<CXXRecordDecl>(anyOf(Base, isDerivedFrom(Base))) + .matches(Node, Finder, Builder); } /// \brief Overloaded method as shortcut for /// \c isSameOrDerivedFrom(hasName(...)). -inline internal::Matcher<CXXRecordDecl> isSameOrDerivedFrom( - StringRef BaseName) { +AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, StringRef, BaseName, + 1) { assert(!BaseName.empty()); - return isSameOrDerivedFrom(hasName(BaseName)); + return isSameOrDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder); } /// \brief Matches the first method of a class or struct that satisfies \c @@ -1478,12 +1530,8 @@ inline internal::Matcher<CXXRecordDecl> isSameOrDerivedFrom( /// but not \c B. AST_MATCHER_P(CXXRecordDecl, hasMethod, internal::Matcher<CXXMethodDecl>, InnerMatcher) { - for (CXXRecordDecl::method_iterator I = Node.method_begin(), - E = Node.method_end(); - I != E; ++I) - if (InnerMatcher.matches(**I, Finder, Builder)) - return true; - return false; + return matchesFirstInPointerRange(InnerMatcher, Node.method_begin(), + Node.method_end(), Finder, Builder); } /// \brief Matches AST nodes that have child AST nodes that match the @@ -1499,12 +1547,8 @@ AST_MATCHER_P(CXXRecordDecl, hasMethod, internal::Matcher<CXXMethodDecl>, /// ChildT must be an AST base type. /// /// Usable as: Any Matcher -template <typename ChildT> -internal::ArgumentAdaptingMatcher<internal::HasMatcher, ChildT> has( - const internal::Matcher<ChildT> &ChildMatcher) { - return internal::ArgumentAdaptingMatcher<internal::HasMatcher, - ChildT>(ChildMatcher); -} +const internal::ArgumentAdaptingMatcherFunc<internal::HasMatcher> +LLVM_ATTRIBUTE_UNUSED has = {}; /// \brief Matches AST nodes that have descendant AST nodes that match the /// provided matcher. @@ -1520,13 +1564,8 @@ internal::ArgumentAdaptingMatcher<internal::HasMatcher, ChildT> has( /// DescendantT must be an AST base type. /// /// Usable as: Any Matcher -template <typename DescendantT> -internal::ArgumentAdaptingMatcher<internal::HasDescendantMatcher, DescendantT> -hasDescendant(const internal::Matcher<DescendantT> &DescendantMatcher) { - return internal::ArgumentAdaptingMatcher< - internal::HasDescendantMatcher, - DescendantT>(DescendantMatcher); -} +const internal::ArgumentAdaptingMatcherFunc<internal::HasDescendantMatcher> +LLVM_ATTRIBUTE_UNUSED hasDescendant = {}; /// \brief Matches AST nodes that have child AST nodes that match the /// provided matcher. @@ -1544,13 +1583,8 @@ hasDescendant(const internal::Matcher<DescendantT> &DescendantMatcher) { /// matches instead of only on the first one. /// /// Usable as: Any Matcher -template <typename ChildT> -internal::ArgumentAdaptingMatcher<internal::ForEachMatcher, ChildT> forEach( - const internal::Matcher<ChildT> &ChildMatcher) { - return internal::ArgumentAdaptingMatcher< - internal::ForEachMatcher, - ChildT>(ChildMatcher); -} +const internal::ArgumentAdaptingMatcherFunc<internal::ForEachMatcher> +LLVM_ATTRIBUTE_UNUSED forEach = {}; /// \brief Matches AST nodes that have descendant AST nodes that match the /// provided matcher. @@ -1576,15 +1610,8 @@ internal::ArgumentAdaptingMatcher<internal::ForEachMatcher, ChildT> forEach( /// \endcode /// /// Usable as: Any Matcher -template <typename DescendantT> -internal::ArgumentAdaptingMatcher<internal::ForEachDescendantMatcher, - DescendantT> -forEachDescendant( - const internal::Matcher<DescendantT> &DescendantMatcher) { - return internal::ArgumentAdaptingMatcher< - internal::ForEachDescendantMatcher, - DescendantT>(DescendantMatcher); -} +const internal::ArgumentAdaptingMatcherFunc<internal::ForEachDescendantMatcher> +LLVM_ATTRIBUTE_UNUSED forEachDescendant = {}; /// \brief Matches if the node or any descendant matches. /// @@ -1602,10 +1629,7 @@ forEachDescendant( /// /// Usable as: Any Matcher template <typename T> -internal::PolymorphicMatcherWithParam2< - internal::EachOfMatcher, internal::Matcher<T>, - internal::ArgumentAdaptingMatcher<internal::ForEachDescendantMatcher, T> > -findAll(const internal::Matcher<T> &Matcher) { +internal::Matcher<T> findAll(const internal::Matcher<T> &Matcher) { return eachOf(Matcher, forEachDescendant(Matcher)); } @@ -1619,13 +1643,9 @@ findAll(const internal::Matcher<T> &Matcher) { /// \c compoundStmt(hasParent(ifStmt())) matches "{ int x = 43; }". /// /// Usable as: Any Matcher -template <typename ParentT> -internal::ArgumentAdaptingMatcher<internal::HasParentMatcher, ParentT> -hasParent(const internal::Matcher<ParentT> &ParentMatcher) { - return internal::ArgumentAdaptingMatcher< - internal::HasParentMatcher, - ParentT>(ParentMatcher); -} +const internal::ArgumentAdaptingMatcherFunc< + internal::HasParentMatcher, internal::TypeList<Decl, Stmt>, + internal::TypeList<Decl, Stmt> > LLVM_ATTRIBUTE_UNUSED hasParent = {}; /// \brief Matches AST nodes that have an ancestor that matches the provided /// matcher. @@ -1638,13 +1658,9 @@ hasParent(const internal::Matcher<ParentT> &ParentMatcher) { /// \c expr(integerLiteral(hasAncestor(ifStmt()))) matches \c 42, but not 43. /// /// Usable as: Any Matcher -template <typename AncestorT> -internal::ArgumentAdaptingMatcher<internal::HasAncestorMatcher, AncestorT> -hasAncestor(const internal::Matcher<AncestorT> &AncestorMatcher) { - return internal::ArgumentAdaptingMatcher< - internal::HasAncestorMatcher, - AncestorT>(AncestorMatcher); -} +const internal::ArgumentAdaptingMatcherFunc< + internal::HasAncestorMatcher, internal::TypeList<Decl, Stmt>, + internal::TypeList<Decl, Stmt> > LLVM_ATTRIBUTE_UNUSED hasAncestor = {}; /// \brief Matches if the provided matcher does not match. /// @@ -1662,22 +1678,31 @@ unless(const M &InnerMatcher) { internal::NotMatcher, M>(InnerMatcher); } -/// \brief Matches a type if the declaration of the type matches the given -/// matcher. +/// \brief Matches a node if the declaration associated with that node +/// matches the given matcher. +/// +/// The associated declaration is: +/// - for type nodes, the declaration of the underlying type +/// - for CallExpr, the declaration of the callee +/// - for MemberExpr, the declaration of the referenced member +/// - for CXXConstructExpr, the declaration of the constructor /// -/// In addition to being usable as Matcher<TypedefType>, also usable as -/// Matcher<T> for any T supporting the getDecl() member function. e.g. various -/// subtypes of clang::Type. +/// Also usable as Matcher<T> for any T supporting the getDecl() member +/// function. e.g. various subtypes of clang::Type and various expressions. /// -/// Usable as: Matcher<QualType>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, -/// Matcher<MemberExpr>, Matcher<TypedefType>, -/// Matcher<TemplateSpecializationType> -inline internal::PolymorphicMatcherWithParam1< internal::HasDeclarationMatcher, - internal::Matcher<Decl> > - hasDeclaration(const internal::Matcher<Decl> &InnerMatcher) { +/// Usable as: Matcher<CallExpr>, Matcher<CXXConstructExpr>, +/// Matcher<DeclRefExpr>, Matcher<EnumType>, Matcher<InjectedClassNameType>, +/// Matcher<LabelStmt>, Matcher<MemberExpr>, Matcher<QualType>, +/// Matcher<RecordType>, Matcher<TagType>, +/// Matcher<TemplateSpecializationType>, Matcher<TemplateTypeParmType>, +/// Matcher<TypedefType>, Matcher<UnresolvedUsingType> +inline internal::PolymorphicMatcherWithParam1< + internal::HasDeclarationMatcher, internal::Matcher<Decl>, + void(internal::HasDeclarationSupportedTypes)> +hasDeclaration(const internal::Matcher<Decl> &InnerMatcher) { return internal::PolymorphicMatcherWithParam1< - internal::HasDeclarationMatcher, - internal::Matcher<Decl> >(InnerMatcher); + internal::HasDeclarationMatcher, internal::Matcher<Decl>, + void(internal::HasDeclarationSupportedTypes)>(InnerMatcher); } /// \brief Matches on the implicit object argument of a member call expression. @@ -1728,9 +1753,9 @@ AST_MATCHER_P(CallExpr, callee, internal::Matcher<Stmt>, /// class Y { public: void x(); }; /// void z() { Y y; y.x(); /// \endcode -inline internal::Matcher<CallExpr> callee( - const internal::Matcher<Decl> &InnerMatcher) { - return callExpr(hasDeclaration(InnerMatcher)); +AST_MATCHER_P_OVERLOAD(CallExpr, callee, internal::Matcher<Decl>, InnerMatcher, + 1) { + return callExpr(hasDeclaration(InnerMatcher)).matches(Node, Finder, Builder); } /// \brief Matches if the expression's or declaration's type matches a type @@ -1742,11 +1767,9 @@ inline internal::Matcher<CallExpr> callee( /// class X {}; /// void y(X &x) { x; X z; } /// \endcode -AST_POLYMORPHIC_MATCHER_P(hasType, internal::Matcher<QualType>, - InnerMatcher) { - TOOLING_COMPILE_ASSERT((llvm::is_base_of<Expr, NodeType>::value || - llvm::is_base_of<ValueDecl, NodeType>::value), - instantiated_with_wrong_types); +AST_POLYMORPHIC_MATCHER_P_OVERLOAD( + hasType, AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl), + internal::Matcher<QualType>, InnerMatcher, 0) { return InnerMatcher.matches(Node.getType(), Finder, Builder); } @@ -1767,11 +1790,27 @@ AST_POLYMORPHIC_MATCHER_P(hasType, internal::Matcher<QualType>, /// \endcode /// /// Usable as: Matcher<Expr>, Matcher<ValueDecl> -inline internal::PolymorphicMatcherWithParam1< - internal::matcher_hasType0Matcher, - internal::Matcher<QualType> > -hasType(const internal::Matcher<Decl> &InnerMatcher) { - return hasType(qualType(hasDeclaration(InnerMatcher))); +AST_POLYMORPHIC_MATCHER_P_OVERLOAD( + hasType, AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl), + internal::Matcher<Decl>, InnerMatcher, 1) { + return qualType(hasDeclaration(InnerMatcher)) + .matches(Node.getType(), Finder, Builder); +} + +/// \brief Matches if the type location of the declarator decl's type matches +/// the inner matcher. +/// +/// Given +/// \code +/// int x; +/// \endcode +/// declaratorDecl(hasTypeLoc(loc(asString("int")))) +/// matches int x +AST_MATCHER_P(DeclaratorDecl, hasTypeLoc, internal::Matcher<TypeLoc>, Inner) { + if (!Node.getTypeSourceInfo()) + // This happens for example for implicit destructors. + return false; + return Inner.matches(Node.getTypeSourceInfo()->getTypeLoc(), Finder, Builder); } /// \brief Matches if the matched type is represented by the given string. @@ -1804,9 +1843,10 @@ AST_MATCHER_P( } /// \brief Overloaded to match the pointee type's declaration. -inline internal::Matcher<QualType> pointsTo( - const internal::Matcher<Decl> &InnerMatcher) { - return pointsTo(qualType(hasDeclaration(InnerMatcher))); +AST_MATCHER_P_OVERLOAD(QualType, pointsTo, internal::Matcher<Decl>, + InnerMatcher, 1) { + return pointsTo(qualType(hasDeclaration(InnerMatcher))) + .matches(Node, Finder, Builder); } /// \brief Matches if the matched type is a reference type and the referenced @@ -1841,13 +1881,16 @@ AST_MATCHER_P(QualType, references, internal::Matcher<QualType>, /// varDecl(hasType(qualType(hasCanonicalType(referenceType())))))) does. AST_MATCHER_P(QualType, hasCanonicalType, internal::Matcher<QualType>, InnerMatcher) { + if (Node.isNull()) + return false; return InnerMatcher.matches(Node.getCanonicalType(), Finder, Builder); } /// \brief Overloaded to match the referenced type's declaration. -inline internal::Matcher<QualType> references( - const internal::Matcher<Decl> &InnerMatcher) { - return references(qualType(hasDeclaration(InnerMatcher))); +AST_MATCHER_P_OVERLOAD(QualType, references, internal::Matcher<Decl>, + InnerMatcher, 1) { + return references(qualType(hasDeclaration(InnerMatcher))) + .matches(Node, Finder, Builder); } AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument, @@ -1859,17 +1902,19 @@ AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument, /// \brief Matches if the expression's type either matches the specified /// matcher, or is a pointer to a type that matches the InnerMatcher. -inline internal::Matcher<CXXMemberCallExpr> thisPointerType( - const internal::Matcher<QualType> &InnerMatcher) { +AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType, + internal::Matcher<QualType>, InnerMatcher, 0) { return onImplicitObjectArgument( - anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher)))); + anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher)))) + .matches(Node, Finder, Builder); } /// \brief Overloaded to match the type's declaration. -inline internal::Matcher<CXXMemberCallExpr> thisPointerType( - const internal::Matcher<Decl> &InnerMatcher) { +AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType, + internal::Matcher<Decl>, InnerMatcher, 1) { return onImplicitObjectArgument( - anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher)))); + anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher)))) + .matches(Node, Finder, Builder); } /// \brief Matches a DeclRefExpr that refers to a declaration that matches the @@ -1953,11 +1998,9 @@ AST_MATCHER_P( /// void f(int x, int y); /// f(0, 0); /// \endcode -AST_POLYMORPHIC_MATCHER_P(argumentCountIs, unsigned, N) { - TOOLING_COMPILE_ASSERT((llvm::is_base_of<CallExpr, NodeType>::value || - llvm::is_base_of<CXXConstructExpr, - NodeType>::value), - instantiated_with_wrong_types); +AST_POLYMORPHIC_MATCHER_P(argumentCountIs, AST_POLYMORPHIC_SUPPORTED_TYPES_2( + CallExpr, CXXConstructExpr), + unsigned, N) { return Node.getNumArgs() == N; } @@ -1970,11 +2013,9 @@ AST_POLYMORPHIC_MATCHER_P(argumentCountIs, unsigned, N) { /// void x(int) { int y; x(y); } /// \endcode AST_POLYMORPHIC_MATCHER_P2( - hasArgument, unsigned, N, internal::Matcher<Expr>, InnerMatcher) { - TOOLING_COMPILE_ASSERT((llvm::is_base_of<CallExpr, NodeType>::value || - llvm::is_base_of<CXXConstructExpr, - NodeType>::value), - instantiated_with_wrong_types); + hasArgument, + AST_POLYMORPHIC_SUPPORTED_TYPES_2(CallExpr, CXXConstructExpr), + unsigned, N, internal::Matcher<Expr>, InnerMatcher) { return (N < Node.getNumArgs() && InnerMatcher.matches( *Node.getArg(N)->IgnoreParenImpCasts(), Finder, Builder)); @@ -2037,13 +2078,8 @@ AST_MATCHER_P2(DeclStmt, containsDeclaration, unsigned, N, /// record matches Foo, hasAnyConstructorInitializer matches foo_(1) AST_MATCHER_P(CXXConstructorDecl, hasAnyConstructorInitializer, internal::Matcher<CXXCtorInitializer>, InnerMatcher) { - for (CXXConstructorDecl::init_const_iterator I = Node.init_begin(); - I != Node.init_end(); ++I) { - if (InnerMatcher.matches(**I, Finder, Builder)) { - return true; - } - } - return false; + return matchesFirstInPointerRange(InnerMatcher, Node.init_begin(), + Node.init_end(), Finder, Builder); } /// \brief Matches the field declaration of a constructor initializer. @@ -2086,7 +2122,7 @@ AST_MATCHER_P(CXXCtorInitializer, withInitializer, InnerMatcher.matches(*NodeAsExpr, Finder, Builder)); } -/// \brief Matches a contructor initializer if it is explicitly written in +/// \brief Matches a constructor initializer if it is explicitly written in /// code (as opposed to implicitly added by the compiler). /// /// Given @@ -2120,15 +2156,19 @@ AST_MATCHER(CXXConstructorDecl, isImplicit) { /// matches x(1, y, 42) /// with hasAnyArgument(...) /// matching y -AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, internal::Matcher<Expr>, - InnerMatcher) { - TOOLING_COMPILE_ASSERT((llvm::is_base_of<CallExpr, NodeType>::value || - llvm::is_base_of<CXXConstructExpr, - NodeType>::value), - instantiated_with_wrong_types); +/// +/// FIXME: Currently this will ignore parentheses and implicit casts on +/// the argument before applying the inner matcher. We'll want to remove +/// this to allow for greater control by the user once \c ignoreImplicit() +/// has been implemented. +AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, AST_POLYMORPHIC_SUPPORTED_TYPES_2( + CallExpr, CXXConstructExpr), + internal::Matcher<Expr>, InnerMatcher) { for (unsigned I = 0; I < Node.getNumArgs(); ++I) { - if (InnerMatcher.matches(*Node.getArg(I)->IgnoreParenImpCasts(), - Finder, Builder)) { + BoundNodesTreeBuilder Result(*Builder); + if (InnerMatcher.matches(*Node.getArg(I)->IgnoreParenImpCasts(), Finder, + &Result)) { + *Builder = Result; return true; } } @@ -2167,12 +2207,8 @@ AST_MATCHER_P2(FunctionDecl, hasParameter, /// matching int y AST_MATCHER_P(FunctionDecl, hasAnyParameter, internal::Matcher<ParmVarDecl>, InnerMatcher) { - for (unsigned I = 0; I < Node.getNumParams(); ++I) { - if (InnerMatcher.matches(*Node.getParamDecl(I), Finder, Builder)) { - return true; - } - } - return false; + return matchesFirstInPointerRange(InnerMatcher, Node.param_begin(), + Node.param_end(), Finder, Builder); } /// \brief Matches \c FunctionDecls that have a specific parameter count. @@ -2222,27 +2258,68 @@ AST_MATCHER(FunctionDecl, isExternC) { /// \code /// if (true) {} /// \endcode -AST_POLYMORPHIC_MATCHER_P(hasCondition, internal::Matcher<Expr>, - InnerMatcher) { - TOOLING_COMPILE_ASSERT( - (llvm::is_base_of<IfStmt, NodeType>::value) || - (llvm::is_base_of<ForStmt, NodeType>::value) || - (llvm::is_base_of<WhileStmt, NodeType>::value) || - (llvm::is_base_of<DoStmt, NodeType>::value) || - (llvm::is_base_of<ConditionalOperator, NodeType>::value), - has_condition_requires_if_statement_conditional_operator_or_loop); +AST_POLYMORPHIC_MATCHER_P( + hasCondition, AST_POLYMORPHIC_SUPPORTED_TYPES_5( + IfStmt, ForStmt, WhileStmt, DoStmt, ConditionalOperator), + internal::Matcher<Expr>, InnerMatcher) { const Expr *const Condition = Node.getCond(); return (Condition != NULL && InnerMatcher.matches(*Condition, Finder, Builder)); } +namespace internal { +struct NotEqualsBoundNodePredicate { + bool operator()(const internal::BoundNodesMap &Nodes) const { + return Nodes.getNode(ID) != Node; + } + std::string ID; + ast_type_traits::DynTypedNode Node; +}; +} // namespace internal + +/// \brief Matches if a node equals a previously bound node. +/// +/// Matches a node if it equals the node previously bound to \p ID. +/// +/// Given +/// \code +/// class X { int a; int b; }; +/// \endcode +/// recordDecl( +/// has(fieldDecl(hasName("a"), hasType(type().bind("t")))), +/// has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t")))))) +/// matches the class \c X, as \c a and \c b have the same type. +/// +/// Note that when multiple matches are involved via \c forEach* matchers, +/// \c equalsBoundNodes acts as a filter. +/// For example: +/// compoundStmt( +/// forEachDescendant(varDecl().bind("d")), +/// forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d")))))) +/// will trigger a match for each combination of variable declaration +/// and reference to that variable declaration within a compound statement. +AST_POLYMORPHIC_MATCHER_P(equalsBoundNode, AST_POLYMORPHIC_SUPPORTED_TYPES_4( + Stmt, Decl, Type, QualType), + std::string, ID) { + // FIXME: Figure out whether it makes sense to allow this + // on any other node types. + // For *Loc it probably does not make sense, as those seem + // unique. For NestedNameSepcifier it might make sense, as + // those also have pointer identity, but I'm not sure whether + // they're ever reused. + internal::NotEqualsBoundNodePredicate Predicate; + Predicate.ID = ID; + Predicate.Node = ast_type_traits::DynTypedNode::create(Node); + return Builder->removeBindings(Predicate); +} + /// \brief Matches the condition variable statement in an if statement. /// /// Given /// \code /// if (A* a = GetAPointer()) {} /// \endcode -/// hasConditionVariableStatment(...) +/// hasConditionVariableStatement(...) /// matches 'A* a = GetAPointer()'. AST_MATCHER_P(IfStmt, hasConditionVariableStatement, internal::Matcher<DeclStmt>, InnerMatcher) { @@ -2296,13 +2373,9 @@ AST_MATCHER_P(ArraySubscriptExpr, hasBase, /// matches 'for (;;) {}' /// with compoundStmt() /// matching '{}' -AST_POLYMORPHIC_MATCHER_P(hasBody, internal::Matcher<Stmt>, - InnerMatcher) { - TOOLING_COMPILE_ASSERT( - (llvm::is_base_of<DoStmt, NodeType>::value) || - (llvm::is_base_of<ForStmt, NodeType>::value) || - (llvm::is_base_of<WhileStmt, NodeType>::value), - has_body_requires_for_while_or_do_statement); +AST_POLYMORPHIC_MATCHER_P( + hasBody, AST_POLYMORPHIC_SUPPORTED_TYPES_3(DoStmt, ForStmt, WhileStmt), + internal::Matcher<Stmt>, InnerMatcher) { const Stmt *const Statement = Node.getBody(); return (Statement != NULL && InnerMatcher.matches(*Statement, Finder, Builder)); @@ -2321,12 +2394,8 @@ AST_POLYMORPHIC_MATCHER_P(hasBody, internal::Matcher<Stmt>, /// matching '{}' AST_MATCHER_P(CompoundStmt, hasAnySubstatement, internal::Matcher<Stmt>, InnerMatcher) { - for (CompoundStmt::const_body_iterator It = Node.body_begin(); - It != Node.body_end(); - ++It) { - if (InnerMatcher.matches(**It, Finder, Builder)) return true; - } - return false; + return matchesFirstInPointerRange(InnerMatcher, Node.body_begin(), + Node.body_end(), Finder, Builder); } /// \brief Checks that a compound statement contains a specific number of @@ -2367,11 +2436,9 @@ equals(const ValueT &Value) { /// \code /// !(a || b) /// \endcode -AST_POLYMORPHIC_MATCHER_P(hasOperatorName, std::string, Name) { - TOOLING_COMPILE_ASSERT( - (llvm::is_base_of<BinaryOperator, NodeType>::value) || - (llvm::is_base_of<UnaryOperator, NodeType>::value), - has_condition_requires_if_statement_or_conditional_operator); +AST_POLYMORPHIC_MATCHER_P(hasOperatorName, AST_POLYMORPHIC_SUPPORTED_TYPES_2( + BinaryOperator, UnaryOperator), + std::string, Name) { return Name == Node.getOpcodeStr(Node.getOpcode()); } @@ -2493,12 +2560,8 @@ AST_MATCHER_P(ConditionalOperator, hasFalseExpression, /// \endcode /// /// Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl> -AST_POLYMORPHIC_MATCHER(isDefinition) { - TOOLING_COMPILE_ASSERT( - (llvm::is_base_of<TagDecl, NodeType>::value) || - (llvm::is_base_of<VarDecl, NodeType>::value) || - (llvm::is_base_of<FunctionDecl, NodeType>::value), - is_definition_requires_isThisDeclarationADefinition_method); +AST_POLYMORPHIC_MATCHER(isDefinition, AST_POLYMORPHIC_SUPPORTED_TYPES_3( + TagDecl, VarDecl, FunctionDecl)) { return Node.isThisDeclarationADefinition(); } @@ -2540,6 +2603,21 @@ AST_MATCHER(CXXMethodDecl, isVirtual) { return Node.isVirtual(); } +/// \brief Matches if the given method declaration is const. +/// +/// Given +/// \code +/// struct A { +/// void foo() const; +/// void bar(); +/// }; +/// \endcode +/// +/// methodDecl(isConst()) matches A::foo() but not A::bar() +AST_MATCHER(CXXMethodDecl, isConst) { + return Node.isConst(); +} + /// \brief Matches if the given method declaration overrides another method. /// /// Given @@ -2672,12 +2750,8 @@ AST_MATCHER_P(MemberExpr, hasObjectExpression, /// matches \code using X::b \endcode AST_MATCHER_P(UsingDecl, hasAnyUsingShadowDecl, internal::Matcher<UsingShadowDecl>, InnerMatcher) { - for (UsingDecl::shadow_iterator II = Node.shadow_begin(); - II != Node.shadow_end(); ++II) { - if (InnerMatcher.matches(**II, Finder, Builder)) - return true; - } - return false; + return matchesFirstInPointerRange(InnerMatcher, Node.shadow_begin(), + Node.shadow_end(), Finder, Builder); } /// \brief Matches a using shadow declaration where the target declaration is @@ -2720,11 +2794,9 @@ AST_MATCHER_P(UsingShadowDecl, hasTargetDecl, /// does not match, as X<A> is an explicit template specialization. /// /// Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl> -AST_POLYMORPHIC_MATCHER(isTemplateInstantiation) { - TOOLING_COMPILE_ASSERT((llvm::is_base_of<FunctionDecl, NodeType>::value) || - (llvm::is_base_of<VarDecl, NodeType>::value) || - (llvm::is_base_of<CXXRecordDecl, NodeType>::value), - requires_getTemplateSpecializationKind_method); +AST_POLYMORPHIC_MATCHER( + isTemplateInstantiation, + AST_POLYMORPHIC_SUPPORTED_TYPES_3(FunctionDecl, VarDecl, CXXRecordDecl)) { return (Node.getTemplateSpecializationKind() == TSK_ImplicitInstantiation || Node.getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition); @@ -2742,11 +2814,9 @@ AST_POLYMORPHIC_MATCHER(isTemplateInstantiation) { /// matches the specialization A<int>(). /// /// Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl> -AST_POLYMORPHIC_MATCHER(isExplicitTemplateSpecialization) { - TOOLING_COMPILE_ASSERT((llvm::is_base_of<FunctionDecl, NodeType>::value) || - (llvm::is_base_of<VarDecl, NodeType>::value) || - (llvm::is_base_of<CXXRecordDecl, NodeType>::value), - requires_getTemplateSpecializationKind_method); +AST_POLYMORPHIC_MATCHER( + isExplicitTemplateSpecialization, + AST_POLYMORPHIC_SUPPORTED_TYPES_3(FunctionDecl, VarDecl, CXXRecordDecl)) { return (Node.getTemplateSpecializationKind() == TSK_ExplicitSpecialization); } @@ -2807,7 +2877,9 @@ AST_TYPE_MATCHER(ComplexType, complexType); /// matches "int b[7]" /// /// Usable as: Matcher<ArrayType>, Matcher<ComplexType> -AST_TYPELOC_TRAVERSE_MATCHER(hasElementType, getElement); +AST_TYPELOC_TRAVERSE_MATCHER( + hasElementType, getElement, + AST_POLYMORPHIC_SUPPORTED_TYPES_2(ArrayType, ComplexType)); /// \brief Matches C arrays with a specified constant size. /// @@ -2914,7 +2986,8 @@ AST_TYPE_MATCHER(AtomicType, atomicType); /// matches "_Atomic(int) i" /// /// Usable as: Matcher<AtomicType> -AST_TYPELOC_TRAVERSE_MATCHER(hasValueType, getValue); +AST_TYPELOC_TRAVERSE_MATCHER(hasValueType, getValue, + AST_POLYMORPHIC_SUPPORTED_TYPES_1(AtomicType)); /// \brief Matches types nodes representing C++11 auto types. /// @@ -2942,7 +3015,8 @@ AST_TYPE_MATCHER(AutoType, autoType); /// matches "auto a" /// /// Usable as: Matcher<AutoType> -AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType); +AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType, + AST_POLYMORPHIC_SUPPORTED_TYPES_1(AutoType)); /// \brief Matches \c FunctionType nodes. /// @@ -2979,7 +3053,8 @@ AST_TYPE_MATCHER(ParenType, parenType); /// \c ptr_to_func but not \c ptr_to_array. /// /// Usable as: Matcher<ParenType> -AST_TYPE_TRAVERSE_MATCHER(innerType, getInnerType); +AST_TYPE_TRAVERSE_MATCHER(innerType, getInnerType, + AST_POLYMORPHIC_SUPPORTED_TYPES_1(ParenType)); /// \brief Matches block pointer types, i.e. types syntactically represented as /// "void (^)(int)". @@ -3073,7 +3148,10 @@ AST_TYPE_MATCHER(RValueReferenceType, rValueReferenceType); /// /// Usable as: Matcher<BlockPointerType>, Matcher<MemberPointerType>, /// Matcher<PointerType>, Matcher<ReferenceType> -AST_TYPELOC_TRAVERSE_MATCHER(pointee, getPointee); +AST_TYPELOC_TRAVERSE_MATCHER( + pointee, getPointee, + AST_POLYMORPHIC_SUPPORTED_TYPES_4(BlockPointerType, MemberPointerType, + PointerType, ReferenceType)); /// \brief Matches typedef types. /// @@ -3100,6 +3178,16 @@ AST_TYPE_MATCHER(TypedefType, typedefType); /// instantiation in \c A and the type of the variable declaration in \c B. AST_TYPE_MATCHER(TemplateSpecializationType, templateSpecializationType); +/// \brief Matches types nodes representing unary type transformations. +/// +/// Given: +/// \code +/// typedef __underlying_type(T) type; +/// \endcode +/// unaryTransformType() +/// matches "__underlying_type(T)" +AST_TYPE_MATCHER(UnaryTransformType, unaryTransformType); + /// \brief Matches record types (e.g. structs, classes). /// /// Given @@ -3331,6 +3419,80 @@ AST_MATCHER_P_OVERLOAD(Stmt, equalsNode, Stmt*, Other, 1) { /// @} +/// \brief Matches each case or default statement belonging to the given switch +/// statement. This matcher may produce multiple matches. +/// +/// Given +/// \code +/// switch (1) { case 1: case 2: default: switch (2) { case 3: case 4: ; } } +/// \endcode +/// switchStmt(forEachSwitchCase(caseStmt().bind("c"))).bind("s") +/// matches four times, with "c" binding each of "case 1:", "case 2:", +/// "case 3:" and "case 4:", and "s" respectively binding "switch (1)", +/// "switch (1)", "switch (2)" and "switch (2)". +AST_MATCHER_P(SwitchStmt, forEachSwitchCase, internal::Matcher<SwitchCase>, + InnerMatcher) { + BoundNodesTreeBuilder Result; + // FIXME: getSwitchCaseList() does not necessarily guarantee a stable + // iteration order. We should use the more general iterating matchers once + // they are capable of expressing this matcher (for example, it should ignore + // case statements belonging to nested switch statements). + bool Matched = false; + for (const SwitchCase *SC = Node.getSwitchCaseList(); SC; + SC = SC->getNextSwitchCase()) { + BoundNodesTreeBuilder CaseBuilder(*Builder); + bool CaseMatched = InnerMatcher.matches(*SC, Finder, &CaseBuilder); + if (CaseMatched) { + Matched = true; + Result.addMatch(CaseBuilder); + } + } + *Builder = Result; + return Matched; +} + +/// \brief Matches each constructor initializer in a constructor definition. +/// +/// Given +/// \code +/// class A { A() : i(42), j(42) {} int i; int j; }; +/// \endcode +/// constructorDecl(forEachConstructorInitializer(forField(decl().bind("x")))) +/// will trigger two matches, binding for 'i' and 'j' respectively. +AST_MATCHER_P(CXXConstructorDecl, forEachConstructorInitializer, + internal::Matcher<CXXCtorInitializer>, InnerMatcher) { + BoundNodesTreeBuilder Result; + bool Matched = false; + for (CXXConstructorDecl::init_const_iterator I = Node.init_begin(), + E = Node.init_end(); + I != E; ++I) { + BoundNodesTreeBuilder InitBuilder(*Builder); + if (InnerMatcher.matches(**I, Finder, &InitBuilder)) { + Matched = true; + Result.addMatch(InitBuilder); + } + } + *Builder = Result; + return Matched; +} + +/// \brief If the given case statement does not use the GNU case range +/// extension, matches the constant given in the statement. +/// +/// Given +/// \code +/// switch (1) { case 1: case 1+1: case 3 ... 4: ; } +/// \endcode +/// caseStmt(hasCaseConstant(integerLiteral())) +/// matches "case 1:" +AST_MATCHER_P(CaseStmt, hasCaseConstant, internal::Matcher<Expr>, + InnerMatcher) { + if (Node.getRHS()) + return false; + + return InnerMatcher.matches(*Node.getLHS(), Finder, Builder); +} + } // end namespace ast_matchers } // end namespace clang diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h index 30691ad..69cee2e 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 diff --git a/include/clang/ASTMatchers/ASTMatchersMacros.h b/include/clang/ASTMatchers/ASTMatchersMacros.h index f5ca26b..b5d5303 100644 --- a/include/clang/ASTMatchers/ASTMatchersMacros.h +++ b/include/clang/ASTMatchers/ASTMatchersMacros.h @@ -49,23 +49,19 @@ /// /// The code should return true if 'Node' matches. #define AST_MATCHER(Type, DefineMatcher) \ - AST_MATCHER_OVERLOAD(Type, DefineMatcher, 0) - -#define AST_MATCHER_OVERLOAD(Type, DefineMatcher, OverloadId) \ namespace internal { \ - class matcher_##DefineMatcher##OverloadId##Matcher \ - : public MatcherInterface<Type> { \ + class matcher_##DefineMatcher##Matcher : public MatcherInterface<Type> { \ public: \ - explicit matcher_##DefineMatcher##OverloadId##Matcher() {} \ + explicit matcher_##DefineMatcher##Matcher() {} \ virtual bool matches(const Type &Node, ASTMatchFinder *Finder, \ BoundNodesTreeBuilder *Builder) const; \ }; \ } \ inline internal::Matcher<Type> DefineMatcher() { \ return internal::makeMatcher( \ - new internal::matcher_##DefineMatcher##OverloadId##Matcher()); \ + new internal::matcher_##DefineMatcher##Matcher()); \ } \ - inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \ + inline bool internal::matcher_##DefineMatcher##Matcher::matches( \ const Type &Node, ASTMatchFinder *Finder, \ BoundNodesTreeBuilder *Builder) const @@ -93,10 +89,10 @@ public: \ explicit matcher_##DefineMatcher##OverloadId##Matcher( \ const ParamType &A##Param) \ - : Param(A##Param) { \ - } \ + : Param(A##Param) {} \ virtual bool matches(const Type &Node, ASTMatchFinder *Finder, \ BoundNodesTreeBuilder *Builder) const; \ + \ private: \ const ParamType Param; \ }; \ @@ -105,6 +101,8 @@ return internal::makeMatcher( \ new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param)); \ } \ + typedef internal::Matcher<Type>(&DefineMatcher##_Type##OverloadId)( \ + const ParamType &Param); \ inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \ const Type &Node, ASTMatchFinder *Finder, \ BoundNodesTreeBuilder *Builder) const @@ -136,53 +134,70 @@ public: \ matcher_##DefineMatcher##OverloadId##Matcher(const ParamType1 &A##Param1, \ const ParamType2 &A##Param2) \ - : Param1(A##Param1), Param2(A##Param2) { \ - } \ + : Param1(A##Param1), Param2(A##Param2) {} \ virtual bool matches(const Type &Node, ASTMatchFinder *Finder, \ BoundNodesTreeBuilder *Builder) const; \ + \ private: \ const ParamType1 Param1; \ const ParamType2 Param2; \ }; \ } \ - inline internal::Matcher<Type> \ - DefineMatcher(const ParamType1 &Param1, const ParamType2 &Param2) { \ + inline internal::Matcher<Type> DefineMatcher(const ParamType1 &Param1, \ + const ParamType2 &Param2) { \ return internal::makeMatcher( \ new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param1, \ Param2)); \ } \ + typedef internal::Matcher<Type>(&DefineMatcher##_Type##OverloadId)( \ + const ParamType1 &Param1, const ParamType2 &Param2); \ inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \ const Type &Node, ASTMatchFinder *Finder, \ BoundNodesTreeBuilder *Builder) const +/// \brief Construct a type-list to be passed to the AST_POLYMORPHIC_MATCHER* +/// macros. +/// +/// You can't pass something like \c TypeList<Foo, Bar> to a macro, because it +/// will look at that as two arguments. However, you can pass +/// \c void(TypeList<Foo, Bar>), which works thanks to the parenthesis. +/// The \c PolymorphicMatcherWithParam* classes will unpack the function type to +/// extract the TypeList object. +#define AST_POLYMORPHIC_SUPPORTED_TYPES_1(t1) void(internal::TypeList<t1>) +#define AST_POLYMORPHIC_SUPPORTED_TYPES_2(t1, t2) \ + void(internal::TypeList<t1, t2>) +#define AST_POLYMORPHIC_SUPPORTED_TYPES_3(t1, t2, t3) \ + void(internal::TypeList<t1, t2, t3>) +#define AST_POLYMORPHIC_SUPPORTED_TYPES_4(t1, t2, t3, t4) \ + void(internal::TypeList<t1, t2, t3, t4>) +#define AST_POLYMORPHIC_SUPPORTED_TYPES_5(t1, t2, t3, t4, t5) \ + void(internal::TypeList<t1, t2, t3, internal::TypeList<t4, t5> >) + /// \brief AST_POLYMORPHIC_MATCHER(DefineMatcher) { ... } /// defines a single-parameter function named DefineMatcher() that is /// polymorphic in the return type. /// /// The variables are the same as for AST_MATCHER, but NodeType will be deduced /// from the calling context. -#define AST_POLYMORPHIC_MATCHER(DefineMatcher) \ - AST_POLYMORPHIC_MATCHER_OVERLOAD(DefineMatcher, 0) - -#define AST_POLYMORPHIC_MATCHER_OVERLOAD(DefineMatcher, OverloadId) \ +#define AST_POLYMORPHIC_MATCHER(DefineMatcher, ReturnTypesF) \ namespace internal { \ template <typename NodeType> \ - class matcher_##DefineMatcher##OverloadId##Matcher \ - : public MatcherInterface<NodeType> { \ + class matcher_##DefineMatcher##Matcher : public MatcherInterface<NodeType> { \ public: \ virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder, \ BoundNodesTreeBuilder *Builder) const; \ }; \ } \ inline internal::PolymorphicMatcherWithParam0< \ - internal::matcher_##DefineMatcher##OverloadId##Matcher> DefineMatcher() {\ + internal::matcher_##DefineMatcher##Matcher, ReturnTypesF> \ + DefineMatcher() { \ return internal::PolymorphicMatcherWithParam0< \ - internal::matcher_##DefineMatcher##OverloadId##Matcher>(); \ + internal::matcher_##DefineMatcher##Matcher, ReturnTypesF>(); \ } \ template <typename NodeType> \ - bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \ - NodeType>::matches(const NodeType &Node, ASTMatchFinder *Finder, \ - BoundNodesTreeBuilder *Builder) const + bool internal::matcher_##DefineMatcher##Matcher<NodeType>::matches( \ + const NodeType &Node, ASTMatchFinder *Finder, \ + BoundNodesTreeBuilder *Builder) const /// \brief AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) { ... } /// defines a single-parameter function named DefineMatcher() that is @@ -193,11 +208,13 @@ /// of the matcher Matcher<NodeType> returned by the function matcher(). /// /// FIXME: Pull out common code with above macro? -#define AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) \ - AST_POLYMORPHIC_MATCHER_P_OVERLOAD(DefineMatcher, ParamType, Param, 0) +#define AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ReturnTypesF, ParamType, \ + Param) \ + AST_POLYMORPHIC_MATCHER_P_OVERLOAD(DefineMatcher, ReturnTypesF, ParamType, \ + Param, 0) -#define AST_POLYMORPHIC_MATCHER_P_OVERLOAD(DefineMatcher, ParamType, Param, \ - OverloadId) \ +#define AST_POLYMORPHIC_MATCHER_P_OVERLOAD(DefineMatcher, ReturnTypesF, \ + ParamType, Param, OverloadId) \ namespace internal { \ template <typename NodeType, typename ParamT> \ class matcher_##DefineMatcher##OverloadId##Matcher \ @@ -205,21 +222,25 @@ public: \ explicit matcher_##DefineMatcher##OverloadId##Matcher( \ const ParamType &A##Param) \ - : Param(A##Param) { \ - } \ + : Param(A##Param) {} \ virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder, \ BoundNodesTreeBuilder *Builder) const; \ + \ private: \ const ParamType Param; \ }; \ } \ inline internal::PolymorphicMatcherWithParam1< \ - internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType> \ - DefineMatcher(const ParamType &Param) { \ + internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType, \ + ReturnTypesF> DefineMatcher(const ParamType &Param) { \ return internal::PolymorphicMatcherWithParam1< \ - internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType>( \ - Param); \ + internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType, \ + ReturnTypesF>(Param); \ } \ + typedef internal::PolymorphicMatcherWithParam1< \ + internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType, \ + ReturnTypesF>(&DefineMatcher##_Type##OverloadId)( \ + const ParamType &Param); \ template <typename NodeType, typename ParamT> \ bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \ NodeType, ParamT>::matches(const NodeType &Node, ASTMatchFinder *Finder, \ @@ -233,13 +254,14 @@ /// The variables are the same as for AST_MATCHER_P2, with the /// addition of NodeType, which specifies the node type of the matcher /// Matcher<NodeType> returned by the function DefineMatcher(). -#define AST_POLYMORPHIC_MATCHER_P2(DefineMatcher, ParamType1, Param1, \ - ParamType2, Param2) \ - AST_POLYMORPHIC_MATCHER_P2_OVERLOAD(DefineMatcher, ParamType1, Param1, \ - ParamType2, Param2, 0) +#define AST_POLYMORPHIC_MATCHER_P2(DefineMatcher, ReturnTypesF, ParamType1, \ + Param1, ParamType2, Param2) \ + AST_POLYMORPHIC_MATCHER_P2_OVERLOAD(DefineMatcher, ReturnTypesF, ParamType1, \ + Param1, ParamType2, Param2, 0) -#define AST_POLYMORPHIC_MATCHER_P2_OVERLOAD(DefineMatcher, ParamType1, Param1, \ - ParamType2, Param2, OverloadId) \ +#define AST_POLYMORPHIC_MATCHER_P2_OVERLOAD(DefineMatcher, ReturnTypesF, \ + ParamType1, Param1, ParamType2, \ + Param2, OverloadId) \ namespace internal { \ template <typename NodeType, typename ParamT1, typename ParamT2> \ class matcher_##DefineMatcher##OverloadId##Matcher \ @@ -247,10 +269,10 @@ public: \ matcher_##DefineMatcher##OverloadId##Matcher(const ParamType1 &A##Param1, \ const ParamType2 &A##Param2) \ - : Param1(A##Param1), Param2(A##Param2) { \ - } \ + : Param1(A##Param1), Param2(A##Param2) {} \ virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder, \ BoundNodesTreeBuilder *Builder) const; \ + \ private: \ const ParamType1 Param1; \ const ParamType2 Param2; \ @@ -258,12 +280,16 @@ } \ inline internal::PolymorphicMatcherWithParam2< \ internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \ - ParamType2> \ - DefineMatcher(const ParamType1 &Param1, const ParamType2 &Param2) { \ + ParamType2, ReturnTypesF> DefineMatcher(const ParamType1 &Param1, \ + const ParamType2 &Param2) { \ return internal::PolymorphicMatcherWithParam2< \ internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \ - ParamType2>(Param1, Param2); \ + ParamType2, ReturnTypesF>(Param1, Param2); \ } \ + typedef internal::PolymorphicMatcherWithParam2< \ + internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \ + ParamType2, ReturnTypesF>(&DefineMatcher##_Type##OverloadId)( \ + const ParamType1 &Param1, const ParamType2 &Param2); \ template <typename NodeType, typename ParamT1, typename ParamT2> \ bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \ NodeType, ParamT1, ParamT2>::matches( \ @@ -282,64 +308,29 @@ /// to another. /// /// For a specific \c SpecificType, the traversal is done using -/// \c SpecificType::FunctionName. The existance of such a function determines +/// \c SpecificType::FunctionName. The existence of such a function determines /// whether a corresponding matcher can be used on \c SpecificType. -#define AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName) \ - class Polymorphic##MatcherName##TypeMatcher { \ - public: \ - Polymorphic##MatcherName##TypeMatcher( \ - const internal::Matcher<QualType> &InnerMatcher) \ - : InnerMatcher(InnerMatcher) { \ - } \ - template <typename T> operator internal:: Matcher< T>() { \ - return internal::Matcher<T>(new internal::TypeTraverseMatcher<T>( \ - InnerMatcher, &T::FunctionName)); \ - } \ - private: \ - const internal::Matcher<QualType> InnerMatcher; \ - } \ - ; \ - class Variadic##MatcherName##TypeTraverseMatcher \ - : public llvm::VariadicFunction< \ - Polymorphic##MatcherName##TypeMatcher, internal::Matcher<QualType>, \ - internal::makeTypeAllOfComposite< \ - Polymorphic##MatcherName##TypeMatcher, QualType> > { \ - public: \ - Variadic##MatcherName##TypeTraverseMatcher() { \ - } \ +#define AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName, ReturnTypesF) \ + namespace internal { \ + template <typename T> struct TypeMatcher##MatcherName##Getter { \ + static QualType (T::*value())() const { return &T::FunctionName; } \ + }; \ } \ - ; \ - const Variadic##MatcherName##TypeTraverseMatcher MatcherName + const internal::TypeTraversePolymorphicMatcher< \ + QualType, internal::TypeMatcher##MatcherName##Getter, \ + internal::TypeTraverseMatcher, ReturnTypesF>::Func MatcherName /// \brief AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName) works /// identical to \c AST_TYPE_TRAVERSE_MATCHER but operates on \c TypeLocs. -#define AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName) \ - class Polymorphic##MatcherName##TypeLocMatcher { \ - public: \ - Polymorphic##MatcherName##TypeLocMatcher( \ - const internal::Matcher<TypeLoc> &InnerMatcher) \ - : InnerMatcher(InnerMatcher) { \ - } \ - template <typename T> operator internal:: Matcher< T>() { \ - return internal::Matcher<T>( \ - new internal::TypeLocTraverseMatcher<T>(InnerMatcher, \ - &T::FunctionName##Loc)); \ - } \ - private: \ - const internal::Matcher<TypeLoc> InnerMatcher; \ - } \ - ; \ - class Variadic##MatcherName##TypeLocTraverseMatcher \ - : public llvm::VariadicFunction< \ - Polymorphic##MatcherName##TypeLocMatcher, internal::Matcher<TypeLoc>,\ - internal::makeTypeAllOfComposite< \ - Polymorphic##MatcherName##TypeLocMatcher, TypeLoc> > { \ - public: \ - Variadic##MatcherName##TypeLocTraverseMatcher() { \ - } \ +#define AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName, ReturnTypesF) \ + namespace internal { \ + template <typename T> struct TypeLocMatcher##MatcherName##Getter { \ + static TypeLoc (T::*value())() const { return &T::FunctionName##Loc; } \ + }; \ } \ - ; \ - const Variadic##MatcherName##TypeLocTraverseMatcher MatcherName##Loc; \ - AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type) + const internal::TypeTraversePolymorphicMatcher< \ + TypeLoc, internal::TypeLocMatcher##MatcherName##Getter, \ + internal::TypeLocTraverseMatcher, ReturnTypesF>::Func MatcherName##Loc; \ + AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type, ReturnTypesF) #endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H diff --git a/include/clang/ASTMatchers/Dynamic/Diagnostics.h b/include/clang/ASTMatchers/Dynamic/Diagnostics.h new file mode 100644 index 0000000..aec0c0e --- /dev/null +++ b/include/clang/ASTMatchers/Dynamic/Diagnostics.h @@ -0,0 +1,185 @@ +//===--- Diagnostics.h - Helper class for error diagnostics -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Diagnostics class to manage error messages. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H +#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H + +#include <string> +#include <vector> + +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +struct SourceLocation { + SourceLocation() : Line(), Column() {} + unsigned Line; + unsigned Column; +}; + +struct SourceRange { + SourceLocation Start; + SourceLocation End; +}; + +/// \brief A VariantValue instance annotated with its parser context. +struct ParserValue { + ParserValue() : Text(), Range(), Value() {} + StringRef Text; + SourceRange Range; + VariantValue Value; +}; + +/// \brief Helper class to manage error messages. +class Diagnostics { +public: + /// \brief Parser context types. + enum ContextType { + CT_MatcherArg = 0, + CT_MatcherConstruct = 1 + }; + + /// \brief All errors from the system. + enum ErrorType { + ET_None = 0, + + ET_RegistryNotFound = 1, + ET_RegistryWrongArgCount = 2, + ET_RegistryWrongArgType = 3, + ET_RegistryNotBindable = 4, + ET_RegistryAmbiguousOverload = 5, + + ET_ParserStringError = 100, + ET_ParserNoOpenParen = 101, + ET_ParserNoCloseParen = 102, + ET_ParserNoComma = 103, + ET_ParserNoCode = 104, + ET_ParserNotAMatcher = 105, + ET_ParserInvalidToken = 106, + ET_ParserMalformedBindExpr = 107, + ET_ParserTrailingCode = 108, + ET_ParserUnsignedError = 109, + ET_ParserOverloadedType = 110 + }; + + /// \brief Helper stream class. + class ArgStream { + public: + ArgStream(std::vector<std::string> *Out) : Out(Out) {} + template <class T> ArgStream &operator<<(const T &Arg) { + return operator<<(Twine(Arg)); + } + ArgStream &operator<<(const Twine &Arg); + + private: + std::vector<std::string> *Out; + }; + + /// \brief Class defining a parser context. + /// + /// Used by the parser to specify (possibly recursive) contexts where the + /// parsing/construction can fail. Any error triggered within a context will + /// keep information about the context chain. + /// This class should be used as a RAII instance in the stack. + struct Context { + public: + /// \brief About to call the constructor for a matcher. + enum ConstructMatcherEnum { ConstructMatcher }; + Context(ConstructMatcherEnum, Diagnostics *Error, StringRef MatcherName, + const SourceRange &MatcherRange); + /// \brief About to recurse into parsing one argument for a matcher. + enum MatcherArgEnum { MatcherArg }; + Context(MatcherArgEnum, Diagnostics *Error, StringRef MatcherName, + const SourceRange &MatcherRange, unsigned ArgNumber); + ~Context(); + + private: + Diagnostics *const Error; + }; + + /// \brief Context for overloaded matcher construction. + /// + /// This context will take care of merging all errors that happen within it + /// as "candidate" overloads for the same matcher. + struct OverloadContext { + public: + OverloadContext(Diagnostics* Error); + ~OverloadContext(); + + /// \brief Revert all errors that happened within this context. + void revertErrors(); + + private: + Diagnostics *const Error; + unsigned BeginIndex; + }; + + /// \brief Add an error to the diagnostics. + /// + /// All the context information will be kept on the error message. + /// \return a helper class to allow the caller to pass the arguments for the + /// error message, using the << operator. + ArgStream addError(const SourceRange &Range, ErrorType Error); + + /// \brief Information stored for one frame of the context. + struct ContextFrame { + ContextType Type; + SourceRange Range; + std::vector<std::string> Args; + }; + + /// \brief Information stored for each error found. + struct ErrorContent { + std::vector<ContextFrame> ContextStack; + struct Message { + SourceRange Range; + ErrorType Type; + std::vector<std::string> Args; + }; + std::vector<Message> Messages; + }; + ArrayRef<ErrorContent> errors() const { return Errors; } + + /// \brief Returns a simple string representation of each error. + /// + /// Each error only shows the error message without any context. + void printToStream(llvm::raw_ostream &OS) const; + std::string toString() const; + + /// \brief Returns the full string representation of each error. + /// + /// Each error message contains the full context. + void printToStreamFull(llvm::raw_ostream &OS) const; + std::string toStringFull() const; + +private: + /// \brief Helper function used by the constructors of ContextFrame. + ArgStream pushContextFrame(ContextType Type, SourceRange Range); + + std::vector<ContextFrame> ContextStack; + std::vector<ErrorContent> Errors; +}; + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H diff --git a/include/clang/ASTMatchers/Dynamic/Parser.h b/include/clang/ASTMatchers/Dynamic/Parser.h new file mode 100644 index 0000000..bb6ac76 --- /dev/null +++ b/include/clang/ASTMatchers/Dynamic/Parser.h @@ -0,0 +1,151 @@ +//===--- Parser.h - Matcher expression parser -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Simple matcher expression parser. +/// +/// The parser understands matcher expressions of the form: +/// MatcherName(Arg0, Arg1, ..., ArgN) +/// as well as simple types like strings. +/// The parser does not know how to process the matchers. It delegates this task +/// to a Sema object received as an argument. +/// +/// \code +/// Grammar for the expressions supported: +/// <Expression> := <Literal> | <MatcherExpression> +/// <Literal> := <StringLiteral> | <Unsigned> +/// <StringLiteral> := "quoted string" +/// <Unsigned> := [0-9]+ +/// <MatcherExpression> := <MatcherName>(<ArgumentList>) | +/// <MatcherName>(<ArgumentList>).bind(<StringLiteral>) +/// <MatcherName> := [a-zA-Z]+ +/// <ArgumentList> := <Expression> | <Expression>,<ArgumentList> +/// \endcode +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H +#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H + +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +/// \brief Matcher expression parser. +class Parser { +public: + /// \brief Interface to connect the parser with the registry and more. + /// + /// The parser uses the Sema instance passed into + /// parseMatcherExpression() to handle all matcher tokens. The simplest + /// processor implementation would simply call into the registry to create + /// the matchers. + /// However, a more complex processor might decide to intercept the matcher + /// creation and do some extra work. For example, it could apply some + /// transformation to the matcher by adding some id() nodes, or could detect + /// specific matcher nodes for more efficient lookup. + class Sema { + public: + virtual ~Sema(); + + /// \brief Process a matcher expression. + /// + /// All the arguments passed here have already been processed. + /// + /// \param MatcherName The matcher name found by the parser. + /// + /// \param NameRange The location of the name in the matcher source. + /// Useful for error reporting. + /// + /// \param BindID The ID to use to bind the matcher, or a null \c StringRef + /// if no ID is specified. + /// + /// \param Args The argument list for the matcher. + /// + /// \return The matcher objects constructed by the processor, or a null + /// matcher if an error occurred. In that case, \c Error will contain a + /// description of the error. + virtual VariantMatcher actOnMatcherExpression(StringRef MatcherName, + const SourceRange &NameRange, + StringRef BindID, + ArrayRef<ParserValue> Args, + Diagnostics *Error) = 0; + }; + + /// \brief Parse a matcher expression, creating matchers from the registry. + /// + /// This overload creates matchers calling directly into the registry. If the + /// caller needs more control over how the matchers are created, then it can + /// use the overload below that takes a Sema. + /// + /// \param MatcherCode The matcher expression to parse. + /// + /// \return The matcher object constructed, or an empty Optional if an error + /// occurred. + /// In that case, \c Error will contain a description of the error. + /// The caller takes ownership of the DynTypedMatcher object returned. + static llvm::Optional<DynTypedMatcher> + parseMatcherExpression(StringRef MatcherCode, Diagnostics *Error); + + /// \brief Parse a matcher expression. + /// + /// \param MatcherCode The matcher expression to parse. + /// + /// \param S The Sema instance that will help the parser + /// construct the matchers. + /// \return The matcher object constructed by the processor, or an empty + /// Optional if an error occurred. In that case, \c Error will contain a + /// description of the error. + /// The caller takes ownership of the DynTypedMatcher object returned. + static llvm::Optional<DynTypedMatcher> + parseMatcherExpression(StringRef MatcherCode, Sema *S, Diagnostics *Error); + + /// \brief Parse an expression, creating matchers from the registry. + /// + /// Parses any expression supported by this parser. In general, the + /// \c parseMatcherExpression function is a better approach to get a matcher + /// object. + static bool parseExpression(StringRef Code, VariantValue *Value, + Diagnostics *Error); + + /// \brief Parse an expression. + /// + /// Parses any expression supported by this parser. In general, the + /// \c parseMatcherExpression function is a better approach to get a matcher + /// object. + static bool parseExpression(StringRef Code, Sema *S, + VariantValue *Value, Diagnostics *Error); + +private: + class CodeTokenizer; + struct TokenInfo; + + Parser(CodeTokenizer *Tokenizer, Sema *S, + Diagnostics *Error); + + bool parseExpressionImpl(VariantValue *Value); + bool parseMatcherExpressionImpl(VariantValue *Value); + + CodeTokenizer *const Tokenizer; + Sema *const S; + Diagnostics *const Error; +}; + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H diff --git a/include/clang/ASTMatchers/Dynamic/Registry.h b/include/clang/ASTMatchers/Dynamic/Registry.h new file mode 100644 index 0000000..c113c14 --- /dev/null +++ b/include/clang/ASTMatchers/Dynamic/Registry.h @@ -0,0 +1,75 @@ +//===--- Registry.h - Matcher registry -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Registry of all known matchers. +/// +/// The registry provides a generic interface to construct any matcher by name. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H +#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H + +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +class Registry { +public: + /// \brief Construct a matcher from the registry by name. + /// + /// Consult the registry of known matchers and construct the appropriate + /// matcher by name. + /// + /// \param MatcherName The name of the matcher to instantiate. + /// + /// \param NameRange The location of the name in the matcher source. + /// Useful for error reporting. + /// + /// \param Args The argument list for the matcher. The number and types of the + /// values must be valid for the matcher requested. Otherwise, the function + /// will return an error. + /// + /// \return The matcher object constructed if no error was found. + /// A null matcher if the matcher is not found, or if the number of + /// arguments or argument types do not match the signature. + /// In that case \c Error will contain the description of the error. + static VariantMatcher constructMatcher(StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error); + + /// \brief Construct a matcher from the registry and bind it. + /// + /// Similar the \c constructMatcher() above, but it then tries to bind the + /// matcher to the specified \c BindID. + /// If the matcher is not bindable, it sets an error in \c Error and returns + /// a null matcher. + static VariantMatcher constructBoundMatcher(StringRef MatcherName, + const SourceRange &NameRange, + StringRef BindID, + ArrayRef<ParserValue> Args, + Diagnostics *Error); + +private: + Registry() LLVM_DELETED_FUNCTION; +}; + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h new file mode 100644 index 0000000..b9bc017 --- /dev/null +++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -0,0 +1,261 @@ +//===--- VariantValue.h - Polymorphic value type -*- C++ -*-===/ +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Polymorphic value type. +/// +/// Supports all the types required for dynamic Matcher construction. +/// Used by the registry to construct matchers in a generic way. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H +#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H + +#include <vector> + +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ASTMatchers/ASTMatchersInternal.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/type_traits.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +using ast_matchers::internal::DynTypedMatcher; + +/// \brief A variant matcher object. +/// +/// The purpose of this object is to abstract simple and polymorphic matchers +/// into a single object type. +/// Polymorphic matchers might be implemented as a list of all the possible +/// overloads of the matcher. \c VariantMatcher knows how to select the +/// appropriate overload when needed. +/// To get a real matcher object out of a \c VariantMatcher you can do: +/// - getSingleMatcher() which returns a matcher, only if it is not ambiguous +/// to decide which matcher to return. Eg. it contains only a single +/// matcher, or a polymorphic one with only one overload. +/// - hasTypedMatcher<T>()/getTypedMatcher<T>(): These calls will determine if +/// the underlying matcher(s) can unambiguously return a Matcher<T>. +class VariantMatcher { + /// \brief Methods that depend on T from hasTypedMatcher/getTypedMatcher. + class MatcherOps { + public: + virtual ~MatcherOps(); + virtual bool canConstructFrom(const DynTypedMatcher &Matcher) const = 0; + virtual void constructFrom(const DynTypedMatcher &Matcher) = 0; + virtual void constructVariadicOperator( + ast_matchers::internal::VariadicOperatorFunction Func, + ArrayRef<VariantMatcher> InnerMatchers) = 0; + }; + + /// \brief Payload interface to be specialized by each matcher type. + /// + /// It follows a similar interface as VariantMatcher itself. + class Payload : public RefCountedBaseVPTR { + public: + virtual ~Payload(); + virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const = 0; + virtual std::string getTypeAsString() const = 0; + virtual void makeTypedMatcher(MatcherOps &Ops) const = 0; + }; + +public: + /// \brief A null matcher. + VariantMatcher(); + + /// \brief Clones the provided matcher. + static VariantMatcher SingleMatcher(const DynTypedMatcher &Matcher); + + /// \brief Clones the provided matchers. + /// + /// They should be the result of a polymorphic matcher. + static VariantMatcher PolymorphicMatcher(ArrayRef<DynTypedMatcher> Matchers); + + /// \brief Creates a 'variadic' operator matcher. + /// + /// It will bind to the appropriate type on getTypedMatcher<T>(). + static VariantMatcher VariadicOperatorMatcher( + ast_matchers::internal::VariadicOperatorFunction Func, + ArrayRef<VariantMatcher> Args); + + /// \brief Makes the matcher the "null" matcher. + void reset(); + + /// \brief Whether the matcher is null. + bool isNull() const { return !Value; } + + /// \brief Return a single matcher, if there is no ambiguity. + /// + /// \returns the matcher, if there is only one matcher. An empty Optional, if + /// the underlying matcher is a polymorphic matcher with more than one + /// representation. + llvm::Optional<DynTypedMatcher> getSingleMatcher() const; + + /// \brief Determines if the contained matcher can be converted to + /// \c Matcher<T>. + /// + /// For the Single case, it returns true if it can be converted to + /// \c Matcher<T>. + /// For the Polymorphic case, it returns true if one, and only one, of the + /// overloads can be converted to \c Matcher<T>. If there are more than one + /// that can, the result would be ambiguous and false is returned. + template <class T> + bool hasTypedMatcher() const { + TypedMatcherOps<T> Ops; + if (Value) Value->makeTypedMatcher(Ops); + return Ops.hasMatcher(); + } + + /// \brief Return this matcher as a \c Matcher<T>. + /// + /// Handles the different types (Single, Polymorphic) accordingly. + /// Asserts that \c hasTypedMatcher<T>() is true. + template <class T> + ast_matchers::internal::Matcher<T> getTypedMatcher() const { + TypedMatcherOps<T> Ops; + Value->makeTypedMatcher(Ops); + assert(Ops.hasMatcher() && "hasTypedMatcher<T>() == false"); + return Ops.matcher(); + } + + /// \brief String representation of the type of the value. + /// + /// If the underlying matcher is a polymorphic one, the string will show all + /// the types. + std::string getTypeAsString() const; + +private: + explicit VariantMatcher(Payload *Value) : Value(Value) {} + + class SinglePayload; + class PolymorphicPayload; + class VariadicOpPayload; + + template <typename T> + class TypedMatcherOps : public MatcherOps { + public: + typedef ast_matchers::internal::Matcher<T> MatcherT; + + virtual bool canConstructFrom(const DynTypedMatcher &Matcher) const { + return Matcher.canConvertTo<T>(); + } + + virtual void constructFrom(const DynTypedMatcher& Matcher) { + Out.reset(new MatcherT(Matcher.convertTo<T>())); + } + + virtual void constructVariadicOperator( + ast_matchers::internal::VariadicOperatorFunction Func, + ArrayRef<VariantMatcher> InnerMatchers) { + const size_t NumArgs = InnerMatchers.size(); + MatcherT **InnerArgs = new MatcherT *[NumArgs](); + bool HasError = false; + for (size_t i = 0; i != NumArgs; ++i) { + // Abort if any of the inner matchers can't be converted to + // Matcher<T>. + if (!InnerMatchers[i].hasTypedMatcher<T>()) { + HasError = true; + break; + } + InnerArgs[i] = new MatcherT(InnerMatchers[i].getTypedMatcher<T>()); + } + if (!HasError) { + Out.reset(new MatcherT( + new ast_matchers::internal::VariadicOperatorMatcherInterface<T>( + Func, ArrayRef<const MatcherT *>(InnerArgs, NumArgs)))); + } + for (size_t i = 0; i != NumArgs; ++i) { + delete InnerArgs[i]; + } + delete[] InnerArgs; + } + + bool hasMatcher() const { return Out.get() != NULL; } + const MatcherT &matcher() const { return *Out; } + + private: + OwningPtr<MatcherT> Out; + }; + + IntrusiveRefCntPtr<const Payload> Value; +}; + +/// \brief Variant value class. +/// +/// Basically, a tagged union with value type semantics. +/// It is used by the registry as the return value and argument type for the +/// matcher factory methods. +/// It can be constructed from any of the supported types. It supports +/// copy/assignment. +/// +/// Supported types: +/// - \c unsigned +/// - \c std::string +/// - \c VariantMatcher (\c DynTypedMatcher / \c Matcher<T>) +class VariantValue { +public: + VariantValue() : Type(VT_Nothing) {} + + VariantValue(const VariantValue &Other); + ~VariantValue(); + VariantValue &operator=(const VariantValue &Other); + + /// \brief Specific constructors for each supported type. + VariantValue(unsigned Unsigned); + VariantValue(const std::string &String); + VariantValue(const VariantMatcher &Matchers); + + /// \brief Unsigned value functions. + bool isUnsigned() const; + unsigned getUnsigned() const; + void setUnsigned(unsigned Unsigned); + + /// \brief String value functions. + bool isString() const; + const std::string &getString() const; + void setString(const std::string &String); + + /// \brief Matcher value functions. + bool isMatcher() const; + const VariantMatcher &getMatcher() const; + void setMatcher(const VariantMatcher &Matcher); + + /// \brief String representation of the type of the value. + std::string getTypeAsString() const; + +private: + void reset(); + + /// \brief All supported value types. + enum ValueType { + VT_Nothing, + VT_Unsigned, + VT_String, + VT_Matcher + }; + + /// \brief All supported value types. + union AllValues { + unsigned Unsigned; + std::string *String; + VariantMatcher *Matcher; + }; + + ValueType Type; + AllValues Value; +}; + +} // end namespace dynamic +} // end namespace ast_matchers +} // end namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H |