diff options
Diffstat (limited to 'clang/include')
| -rw-r--r-- | clang/include/clang/ASTMatchers/ASTMatchers.h | 108 | ||||
| -rw-r--r-- | clang/include/clang/ASTMatchers/ASTMatchersInternal.h | 72 | ||||
| -rw-r--r-- | clang/include/clang/ASTMatchers/ASTMatchersMacros.h | 67 | ||||
| -rw-r--r-- | clang/include/clang/ASTMatchers/Dynamic/Diagnostics.h | 3 | ||||
| -rw-r--r-- | clang/include/clang/ASTMatchers/Dynamic/Parser.h | 13 | ||||
| -rw-r--r-- | clang/include/clang/ASTMatchers/Dynamic/Registry.h | 28 | ||||
| -rw-r--r-- | clang/include/clang/ASTMatchers/Dynamic/VariantValue.h | 91 |
7 files changed, 256 insertions, 126 deletions
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 366707b0a44..d6c19b7dfa2 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -1451,10 +1451,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 @@ -1784,11 +1787,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(hasType, + AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl), + internal::Matcher<QualType>, InnerMatcher) { return InnerMatcher.matches(Node.getType(), Finder, Builder); } @@ -1810,8 +1811,8 @@ AST_POLYMORPHIC_MATCHER_P(hasType, internal::Matcher<QualType>, /// /// Usable as: Matcher<Expr>, Matcher<ValueDecl> inline internal::PolymorphicMatcherWithParam1< - internal::matcher_hasType0Matcher, - internal::Matcher<QualType> > + internal::matcher_hasType0Matcher, internal::Matcher<QualType>, + AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl)> hasType(const internal::Matcher<Decl> &InnerMatcher) { return hasType(qualType(hasDeclaration(InnerMatcher))); } @@ -2013,11 +2014,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; } @@ -2030,11 +2029,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)); @@ -2180,12 +2177,9 @@ AST_MATCHER(CXXConstructorDecl, isImplicit) { /// 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, 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); +AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, AST_POLYMORPHIC_SUPPORTED_TYPES_2( + CallExpr, CXXConstructExpr), + internal::Matcher<Expr>, InnerMatcher) { for (unsigned I = 0; I < Node.getNumArgs(); ++I) { BoundNodesTreeBuilder Result(*Builder); if (InnerMatcher.matches(*Node.getArg(I)->IgnoreParenImpCasts(), Finder, @@ -2280,15 +2274,10 @@ 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)); @@ -2325,18 +2314,15 @@ struct NotEqualsBoundNodePredicate { /// 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, std::string, ID) { +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. - TOOLING_COMPILE_ASSERT((llvm::is_base_of<Stmt, NodeType>::value || - llvm::is_base_of<Decl, NodeType>::value || - llvm::is_base_of<Type, NodeType>::value || - llvm::is_base_of<QualType, NodeType>::value), - equals_bound_node_requires_non_unique_node_class); internal::NotEqualsBoundNodePredicate Predicate; Predicate.ID = ID; Predicate.Node = ast_type_traits::DynTypedNode::create(Node); @@ -2403,13 +2389,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)); @@ -2470,11 +2452,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()); } @@ -2596,12 +2576,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(); } @@ -2834,11 +2810,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); @@ -2856,11 +2830,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); } diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h index 9e6d4bf3482..f29ea0e1dcc 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -761,6 +761,58 @@ private: const Matcher<T> InnerMatcher; }; +/// \brief A simple type-list implementation. +/// +/// It is implemented as a flat struct with a maximum number of arguments to +/// simplify compiler error messages. +/// However, it is used as a "linked list" of types. +/// +/// Note: If you need to extend for more types, add them as template arguments +/// and to the "typedef TypeList<...> tail" below. Nothing else is needed. +template <typename T1 = void, typename T2 = void, typename T3 = void, + typename T4 = void, typename T5 = void, typename T6 = void, + typename T7 = void, typename T8 = void> +struct TypeList { + /// \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 TypeList<T2, T3, T4, T5, T6, T7, T8> tail; + + /// \brief Helper meta-function to determine if some type \c T is present or + /// a parent type in the list. + template <typename T> struct ContainsSuperOf { + static const bool value = llvm::is_base_of<head, T>::value || + tail::template ContainsSuperOf<T>::value; + }; +}; + +/// \brief Specialization of ContainsSuperOf for the empty list. +template <> template <typename T> struct TypeList<>::ContainsSuperOf { + static const bool value = false; +}; + +/// \brief The empty type list. +typedef TypeList<> EmptyTypeList; + +/// \brief A "type list" that contains all types. +/// +/// Useful for matchers like \c anything and \c unless. +typedef TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, + 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 A PolymorphicMatcherWithParamN<MatcherT, P1, ..., PN> object can be /// created from N parameters p1, ..., pN (of type P1, ..., PN) and /// used as a Matcher<T> where a MatcherT<T, P1, ..., PN>(p1, ..., pN) @@ -773,24 +825,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(ReturnTypes::template ContainsSuperOf<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(ReturnTypes::template ContainsSuperOf<T>::value, + right_polymorphic_conversion); return Matcher<T>(new MatcherT<T, P1>(Param1)); } @@ -799,14 +860,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(ReturnTypes::template ContainsSuperOf<T>::value, + right_polymorphic_conversion); return Matcher<T>(new MatcherT<T, P1, P2>(Param1, Param2)); } diff --git a/clang/include/clang/ASTMatchers/ASTMatchersMacros.h b/clang/include/clang/ASTMatchers/ASTMatchersMacros.h index f5ca26bca73..91e254eb571 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersMacros.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersMacros.h @@ -155,16 +155,34 @@ 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_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, 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(DefineMatcher, ReturnTypesF) \ + AST_POLYMORPHIC_MATCHER_OVERLOAD(DefineMatcher, ReturnTypesF, 0) -#define AST_POLYMORPHIC_MATCHER_OVERLOAD(DefineMatcher, OverloadId) \ +#define AST_POLYMORPHIC_MATCHER_OVERLOAD(DefineMatcher, ReturnTypesF, \ + OverloadId) \ namespace internal { \ template <typename NodeType> \ class matcher_##DefineMatcher##OverloadId##Matcher \ @@ -175,9 +193,11 @@ }; \ } \ inline internal::PolymorphicMatcherWithParam0< \ - internal::matcher_##DefineMatcher##OverloadId##Matcher> DefineMatcher() {\ + internal::matcher_##DefineMatcher##OverloadId##Matcher, ReturnTypesF> \ + DefineMatcher() { \ return internal::PolymorphicMatcherWithParam0< \ - internal::matcher_##DefineMatcher##OverloadId##Matcher>(); \ + internal::matcher_##DefineMatcher##OverloadId##Matcher, \ + ReturnTypesF>(); \ } \ template <typename NodeType> \ bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \ @@ -193,11 +213,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 \ @@ -214,11 +236,11 @@ }; \ } \ 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); \ } \ template <typename NodeType, typename ParamT> \ bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \ @@ -233,13 +255,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 \ @@ -258,11 +281,11 @@ } \ 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); \ } \ template <typename NodeType, typename ParamT1, typename ParamT2> \ bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \ diff --git a/clang/include/clang/ASTMatchers/Dynamic/Diagnostics.h b/clang/include/clang/ASTMatchers/Dynamic/Diagnostics.h index 21e08ff2da8..973d54cead3 100644 --- a/clang/include/clang/ASTMatchers/Dynamic/Diagnostics.h +++ b/clang/include/clang/ASTMatchers/Dynamic/Diagnostics.h @@ -70,7 +70,8 @@ class Diagnostics { ET_ParserInvalidToken = 108, ET_ParserMalformedBindExpr = 109, ET_ParserTrailingCode = 110, - ET_ParserUnsignedError = 111 + ET_ParserUnsignedError = 111, + ET_ParserOverloadedType = 112 }; /// \brief Helper stream class. diff --git a/clang/include/clang/ASTMatchers/Dynamic/Parser.h b/clang/include/clang/ASTMatchers/Dynamic/Parser.h index 51dbc8a5a43..b3fd7d607fb 100644 --- a/clang/include/clang/ASTMatchers/Dynamic/Parser.h +++ b/clang/include/clang/ASTMatchers/Dynamic/Parser.h @@ -74,13 +74,14 @@ public: /// /// \param Args The argument list for the matcher. /// - /// \return The matcher object constructed by the processor, or NULL - /// if an error occurred. In that case, \c Error will contain a + /// \return The matcher objects constructed by the processor, or an empty + /// list 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. - virtual DynTypedMatcher *actOnMatcherExpression( - StringRef MatcherName, const SourceRange &NameRange, StringRef BindID, - ArrayRef<ParserValue> Args, Diagnostics *Error) = 0; + virtual MatcherList actOnMatcherExpression(StringRef MatcherName, + const SourceRange &NameRange, + StringRef BindID, + ArrayRef<ParserValue> Args, + Diagnostics *Error) = 0; }; /// \brief Parse a matcher expression, creating matchers from the registry. diff --git a/clang/include/clang/ASTMatchers/Dynamic/Registry.h b/clang/include/clang/ASTMatchers/Dynamic/Registry.h index dede8df776f..a75f29641ab 100644 --- a/clang/include/clang/ASTMatchers/Dynamic/Registry.h +++ b/clang/include/clang/ASTMatchers/Dynamic/Registry.h @@ -43,26 +43,26 @@ public: /// values must be valid for the matcher requested. Otherwise, the function /// will return an error. /// - /// \return The matcher if no error was found. NULL 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 DynTypedMatcher *constructMatcher(StringRef MatcherName, - const SourceRange &NameRange, - ArrayRef<ParserValue> Args, - Diagnostics *Error); + /// \return The matcher objects constructed if no error was found. + /// An empty list 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 MatcherList 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 - /// \c NULL. - static DynTypedMatcher *constructBoundMatcher(StringRef MatcherName, - const SourceRange &NameRange, - StringRef BindID, - ArrayRef<ParserValue> Args, - Diagnostics *Error); + /// an empty list. + static MatcherList constructBoundMatcher(StringRef MatcherName, + const SourceRange &NameRange, + StringRef BindID, + ArrayRef<ParserValue> Args, + Diagnostics *Error); private: Registry() LLVM_DELETED_FUNCTION; diff --git a/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h b/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h index c2e60e1ce9e..44f497248ae 100644 --- a/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h +++ b/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -17,6 +17,8 @@ #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/Twine.h" @@ -28,6 +30,73 @@ namespace dynamic { using ast_matchers::internal::DynTypedMatcher; +/// \brief A list of \c DynTypedMatcher objects. +/// +/// The purpose of this list is to wrap multiple different matchers and +/// provide the right one when calling \c hasTypedMatcher/getTypedMatcher. +class MatcherList { +public: + /// \brief An empty list. + MatcherList(); + /// \brief Clones the matcher objects. + MatcherList(const MatcherList &Other); + /// \brief Clones the provided matcher. + MatcherList(const DynTypedMatcher &Matcher); + ~MatcherList(); + + MatcherList &operator=(const MatcherList &Other); + + /// \brief Add a matcher to this list. The matcher is cloned. + void add(const DynTypedMatcher &Matcher); + + /// \brief Empties the list. + void reset(); + + /// \brief Whether the list is empty. + bool empty() const { return List.empty(); } + + ArrayRef<const DynTypedMatcher *> matchers() const { return List; } + + /// \brief Determines if any of the contained matchers can be converted + /// to \c Matcher<T>. + /// + /// Returns true if one, and only one, of the contained matchers can be + /// converted to \c Matcher<T>. If there are more than one that can, the + /// result would be ambigous and false is returned. + template <class T> + bool hasTypedMatcher() const { + size_t Matches = 0; + for (size_t I = 0, E = List.size(); I != E; ++I) { + Matches += ast_matchers::internal::Matcher<T>::canConstructFrom(*List[I]); + } + return Matches == 1; + } + + /// \brief Wrap the correct matcher as a \c Matcher<T>. + /// + /// Selects the appropriate matcher from the list and returns it as a + /// \c Matcher<T>. + /// Asserts that \c hasTypedMatcher<T>() is true. + template <class T> + ast_matchers::internal::Matcher<T> getTypedMatcher() const { + assert(hasTypedMatcher<T>()); + for (size_t I = 0, E = List.size(); I != E; ++I) { + if (ast_matchers::internal::Matcher<T>::canConstructFrom(*List[I])) + return ast_matchers::internal::Matcher<T>::constructFrom(*List[I]); + } + llvm_unreachable("!hasTypedMatcher<T>()"); + } + + /// \brief String representation of the type of the value. + /// + /// If there are more than one matcher on the list, the string will show all + /// the types. + std::string getTypeAsString() const; + +private: + std::vector<const DynTypedMatcher *> List; +}; + /// \brief Variant value class. /// /// Basically, a tagged union with value type semantics. @@ -39,7 +108,7 @@ using ast_matchers::internal::DynTypedMatcher; /// Supported types: /// - \c unsigned /// - \c std::string -/// - \c DynTypedMatcher, and any \c Matcher<T> +/// - \c MatcherList (\c DynTypedMatcher / \c Matcher<T>) class VariantValue { public: VariantValue() : Type(VT_Nothing) {} @@ -52,6 +121,7 @@ public: VariantValue(unsigned Unsigned); VariantValue(const std::string &String); VariantValue(const DynTypedMatcher &Matcher); + VariantValue(const MatcherList &Matchers); /// \brief Unsigned value functions. bool isUnsigned() const; @@ -64,22 +134,19 @@ public: void setString(const std::string &String); /// \brief Matcher value functions. - bool isMatcher() const; - const DynTypedMatcher &getMatcher() const; - void setMatcher(const DynTypedMatcher &Matcher); - /// \brief Set the value to be \c Matcher by taking ownership of the object. - void takeMatcher(DynTypedMatcher *Matcher); + bool isMatchers() const; + const MatcherList &getMatchers() const; + void setMatchers(const MatcherList &Matchers); - /// \brief Specialized Matcher<T> functions. + /// \brief Shortcut functions. template <class T> bool hasTypedMatcher() const { - return isMatcher() && - ast_matchers::internal::Matcher<T>::canConstructFrom(getMatcher()); + return isMatchers() && getMatchers().hasTypedMatcher<T>(); } template <class T> ast_matchers::internal::Matcher<T> getTypedMatcher() const { - return ast_matchers::internal::Matcher<T>::constructFrom(getMatcher()); + return getMatchers().getTypedMatcher<T>(); } /// \brief String representation of the type of the value. @@ -93,14 +160,14 @@ private: VT_Nothing, VT_Unsigned, VT_String, - VT_Matcher + VT_Matchers }; /// \brief All supported value types. union AllValues { unsigned Unsigned; std::string *String; - DynTypedMatcher *Matcher; + MatcherList *Matchers; }; ValueType Type; |

