r184558 - Add support for polymorphic matchers. Use runtime type checking to determine the right polymorphic overload to use.
Samuel Benzaquen
sbenza at google.com
Fri Jun 21 08:51:31 PDT 2013
Author: sbenza
Date: Fri Jun 21 10:51:31 2013
New Revision: 184558
URL: http://llvm.org/viewvc/llvm-project?rev=184558&view=rev
Log:
Add support for polymorphic matchers. Use runtime type checking to determine the right polymorphic overload to use.
Modified:
cfe/trunk/docs/LibASTMatchersReference.html
cfe/trunk/docs/tools/dump_ast_matchers.py
cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h
cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h
cfe/trunk/include/clang/ASTMatchers/Dynamic/Parser.h
cfe/trunk/include/clang/ASTMatchers/Dynamic/Registry.h
cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h
cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp
cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h
cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp
cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp
cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp
cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp
cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
Modified: cfe/trunk/docs/LibASTMatchersReference.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LibASTMatchersReference.html?rev=184558&r1=184557&r2=184558&view=diff
==============================================================================
--- cfe/trunk/docs/LibASTMatchersReference.html (original)
+++ cfe/trunk/docs/LibASTMatchersReference.html Fri Jun 21 10:51:31 2013
@@ -1547,6 +1547,16 @@ Usable as: Matcher<<a href="http://cla
</pre></td></tr>
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('argumentCountIs1')"><a name="argumentCountIs1Anchor">argumentCountIs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="argumentCountIs1"><pre>Checks that a call expression or a constructor call expression has
+a specific number of arguments (including absent default arguments).
+
+Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+ void f(int x, int y);
+ f(0, 0);
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>></td><td class="name" onclick="toggle('isImplicit0')"><a name="isImplicit0Anchor">isImplicit</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isImplicit0"><pre>Matches a constructor declaration that has been implicitly added
by the compiler (eg. implicit defaultcopy constructors).
@@ -2483,6 +2493,34 @@ Usable as: Matcher<<a href="http://cla
</pre></td></tr>
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('hasAnyArgument1')"><a name="hasAnyArgument1Anchor">hasAnyArgument</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasAnyArgument1"><pre>Matches any argument of a call expression or a constructor call
+expression.
+
+Given
+ void x(int, int, int) { int y; x(1, y, 42); }
+callExpr(hasAnyArgument(declRefExpr()))
+ matches x(1, y, 42)
+with hasAnyArgument(...)
+ matching y
+
+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 ignoreImplicit()
+has been implemented.
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('hasArgument1')"><a name="hasArgument1Anchor">hasArgument</a></td><td>unsigned N, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasArgument1"><pre>Matches the n'th argument of a call expression or a constructor
+call expression.
+
+Example matches y in x(y)
+ (matcher = callExpr(hasArgument(0, declRefExpr())))
+ void x(int) { int y; x(y); }
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('hasDeclaration3')"><a name="hasDeclaration3Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasDeclaration3"><pre>Matches a node if the declaration associated with that node
matches the given matcher.
Modified: cfe/trunk/docs/tools/dump_ast_matchers.py
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/tools/dump_ast_matchers.py?rev=184558&r1=184557&r2=184558&view=diff
==============================================================================
--- cfe/trunk/docs/tools/dump_ast_matchers.py (original)
+++ cfe/trunk/docs/tools/dump_ast_matchers.py Fri Jun 21 10:51:31 2013
@@ -175,7 +175,31 @@ def act_on_decl(declaration, comment, al
comment)
return
- m = re.match(r"""^\s*AST_(POLYMORPHIC_)?MATCHER(_P)?(.?)(?:_OVERLOAD)?\(
+ m = re.match(r"""^\s*AST_POLYMORPHIC_MATCHER(_P)?(.?)(?:_OVERLOAD)?\(
+ \s*([^\s,]+)\s*,
+ \s*AST_POLYMORPHIC_SUPPORTED_TYPES_([^(]*)\(([^)]*)\)
+ (?:,\s*([^\s,]+)\s*
+ ,\s*([^\s,]+)\s*)?
+ (?:,\s*([^\s,]+)\s*
+ ,\s*([^\s,]+)\s*)?
+ (?:,\s*\d+\s*)?
+ \)\s*{\s*$""", declaration, flags=re.X)
+
+ if m:
+ p, n, name, n_results, results = m.groups()[0:5]
+ args = m.groups()[5:]
+ result_types = [r.strip() for r in results.split(',')]
+ if allowed_types and allowed_types != result_types:
+ raise Exception('Inconsistent documentation for: %s' % name)
+ if n not in ['', '2']:
+ raise Exception('Cannot parse "%s"' % declaration)
+ args = ', '.join('%s %s' % (args[i], args[i+1])
+ for i in range(0, len(args), 2) if args[i])
+ for result_type in result_types:
+ add_matcher(result_type, name, args, comment)
+ return
+
+ m = re.match(r"""^\s*AST_MATCHER(_P)?(.?)(?:_OVERLOAD)?\(
(?:\s*([^\s,]+)\s*,)?
\s*([^\s,]+)\s*
(?:,\s*([^\s,]+)\s*
@@ -185,8 +209,8 @@ def act_on_decl(declaration, comment, al
(?:,\s*\d+\s*)?
\)\s*{\s*$""", declaration, flags=re.X)
if m:
- p, n, result, name = m.groups()[1:5]
- args = m.groups()[5:]
+ p, n, result, name = m.groups()[0:4]
+ args = m.groups()[4:]
if not result:
if not allowed_types:
raise Exception('Did not find allowed result types for: %s' % name)
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=184558&r1=184557&r2=184558&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Fri Jun 21 10:51:31 2013
@@ -1451,10 +1451,13 @@ AST_MATCHER_P(NamedDecl, matchesName, st
///
/// 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> calle
/// 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, inter
///
/// 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(argumentCountI
/// 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, isImplic
/// 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, hasBas
/// 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, hasFa
/// \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, hasTarget
/// 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(isTemplateInstan
/// 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);
}
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=184558&r1=184557&r2=184558&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h Fri Jun 21 10:51:31 2013
@@ -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));
}
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h?rev=184558&r1=184557&r2=184558&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h Fri Jun 21 10:51:31 2013
@@ -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_OVERLOAD(DefineMatcher, ParamType1, Param1, \
- ParamType2, Param2, OverloadId) \
+#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, 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< \
Modified: cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h?rev=184558&r1=184557&r2=184558&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h Fri Jun 21 10:51:31 2013
@@ -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.
Modified: cfe/trunk/include/clang/ASTMatchers/Dynamic/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/Dynamic/Parser.h?rev=184558&r1=184557&r2=184558&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/Parser.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/Parser.h Fri Jun 21 10:51:31 2013
@@ -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.
Modified: cfe/trunk/include/clang/ASTMatchers/Dynamic/Registry.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/Dynamic/Registry.h?rev=184558&r1=184557&r2=184558&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/Registry.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/Registry.h Fri Jun 21 10:51:31 2013
@@ -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;
Modified: cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h?rev=184558&r1=184557&r2=184558&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h Fri Jun 21 10:51:31 2013
@@ -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::DynTypedMa
/// 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;
Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp?rev=184558&r1=184557&r2=184558&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp Fri Jun 21 10:51:31 2013
@@ -64,6 +64,8 @@ StringRef ErrorTypeToString(Diagnostics:
return "Expected end of code.";
case Diagnostics::ET_ParserUnsignedError:
return "Error parsing unsigned token: <$0>";
+ case Diagnostics::ET_ParserOverloadedType:
+ return "Input value has unresolved overloaded type: $0";
case Diagnostics::ET_None:
return "<N/A>";
Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h?rev=184558&r1=184557&r2=184558&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h Fri Jun 21 10:51:31 2013
@@ -49,6 +49,10 @@ template <> struct ArgTypeTraits<std::st
}
};
+template <>
+struct ArgTypeTraits<StringRef> : public ArgTypeTraits<std::string> {
+};
+
template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T> > {
static std::string asString() {
return (Twine("Matcher<") +
@@ -78,9 +82,9 @@ template <> struct ArgTypeTraits<unsigne
class MatcherCreateCallback {
public:
virtual ~MatcherCreateCallback() {}
- virtual DynTypedMatcher *run(const SourceRange &NameRange,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) const = 0;
+ virtual MatcherList run(const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) const = 0;
};
/// \brief Simple callback implementation. Marshaller and function are provided.
@@ -95,10 +99,10 @@ public:
/// FIXME: Use void(*)() as FuncType on this interface to remove the template
/// argument of this class. The marshaller can cast the function pointer back
/// to the original type.
- typedef DynTypedMatcher *(*MarshallerType)(FuncType, StringRef,
- const SourceRange &,
- ArrayRef<ParserValue>,
- Diagnostics *);
+ typedef MatcherList (*MarshallerType)(FuncType, StringRef,
+ const SourceRange &,
+ ArrayRef<ParserValue>,
+ Diagnostics *);
/// \param Marshaller Function to unpack the arguments and call \c Func
/// \param Func Matcher construct function. This is the function that
@@ -107,8 +111,8 @@ public:
StringRef MatcherName)
: Marshaller(Marshaller), Func(Func), MatcherName(MatcherName.str()) {}
- DynTypedMatcher *run(const SourceRange &NameRange,
- ArrayRef<ParserValue> Args, Diagnostics *Error) const {
+ MatcherList run(const SourceRange &NameRange, ArrayRef<ParserValue> Args,
+ Diagnostics *Error) const {
return Marshaller(Func, MatcherName, NameRange, Args, Error);
}
@@ -127,16 +131,16 @@ private:
/// object file.
class FreeFuncMatcherCreateCallback : public MatcherCreateCallback {
public:
- typedef DynTypedMatcher *(*RunFunc)(StringRef MatcherName,
- const SourceRange &NameRange,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error);
+ typedef MatcherList (*RunFunc)(StringRef MatcherName,
+ const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error);
FreeFuncMatcherCreateCallback(RunFunc Func, StringRef MatcherName)
: Func(Func), MatcherName(MatcherName.str()) {}
- DynTypedMatcher *run(const SourceRange &NameRange, ArrayRef<ParserValue> Args,
- Diagnostics *Error) const {
+ MatcherList run(const SourceRange &NameRange, ArrayRef<ParserValue> Args,
+ Diagnostics *Error) const {
return Func(MatcherName, NameRange, Args, Error);
}
@@ -150,7 +154,7 @@ private:
if (Args.size() != count) { \
Error->pushErrorFrame(NameRange, Error->ET_RegistryWrongArgCount) \
<< count << Args.size(); \
- return NULL; \
+ return MatcherList(); \
}
#define CHECK_ARG_TYPE(index, type) \
@@ -158,43 +162,78 @@ private:
Error->pushErrorFrame(Args[index].Range, Error->ET_RegistryWrongArgType) \
<< (index + 1) << ArgTypeTraits<type>::asString() \
<< Args[index].Value.getTypeAsString(); \
- return NULL; \
+ return MatcherList(); \
}
+/// \brief Helper methods to extract and merge all possible typed matchers
+/// out of the polymorphic object.
+template <class PolyMatcher>
+static void mergePolyMatchers(const PolyMatcher &Poly, MatcherList *Out,
+ ast_matchers::internal::EmptyTypeList) {}
+
+template <class PolyMatcher, class TypeList>
+static void mergePolyMatchers(const PolyMatcher &Poly, MatcherList *Out,
+ TypeList) {
+ Out->add(ast_matchers::internal::Matcher<typename TypeList::head>(Poly));
+ mergePolyMatchers(Poly, Out, typename TypeList::tail());
+}
+
+/// \brief Convert the return values of the functions into a MatcherList.
+///
+/// There are 2 cases right now: The return value is a Matcher<T> or is a
+/// polymorphic matcher. For the former, we just construct the MatcherList. For
+/// the latter, we instantiate all the possible Matcher<T> of the poly matcher.
+template <typename T>
+static MatcherList
+outvalueToMatcherList(const ast_matchers::internal::Matcher<T> &Matcher) {
+ return MatcherList(Matcher);
+}
+
+template <typename T>
+static MatcherList
+outvalueToMatcherList(const T& PolyMatcher, typename T::ReturnTypes* = NULL) {
+ MatcherList Matchers;
+ mergePolyMatchers(PolyMatcher, &Matchers, typename T::ReturnTypes());
+ return Matchers;
+}
+
/// \brief 0-arg marshaller function.
template <typename ReturnType>
-DynTypedMatcher *matcherMarshall0(ReturnType (*Func)(), StringRef MatcherName,
- const SourceRange &NameRange,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) {
+static MatcherList matcherMarshall0(ReturnType (*Func)(),
+ StringRef MatcherName,
+ const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
CHECK_ARG_COUNT(0);
- return Func().clone();
+ return outvalueToMatcherList(Func());
}
/// \brief 1-arg marshaller function.
template <typename ReturnType, typename ArgType1>
-DynTypedMatcher *matcherMarshall1(ReturnType (*Func)(ArgType1),
- StringRef MatcherName,
- const SourceRange &NameRange,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) {
+static MatcherList matcherMarshall1(ReturnType (*Func)(ArgType1),
+ StringRef MatcherName,
+ const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
CHECK_ARG_COUNT(1);
CHECK_ARG_TYPE(0, ArgType1);
- return Func(ArgTypeTraits<ArgType1>::get(Args[0].Value)).clone();
+ return outvalueToMatcherList(
+ Func(ArgTypeTraits<ArgType1>::get(Args[0].Value)));
}
/// \brief 2-arg marshaller function.
template <typename ReturnType, typename ArgType1, typename ArgType2>
-DynTypedMatcher *matcherMarshall2(ReturnType (*Func)(ArgType1, ArgType2),
- StringRef MatcherName,
- const SourceRange &NameRange,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) {
+static MatcherList matcherMarshall2(ReturnType (*Func)(ArgType1, ArgType2),
+ StringRef MatcherName,
+ const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
CHECK_ARG_COUNT(2);
CHECK_ARG_TYPE(0, ArgType1);
CHECK_ARG_TYPE(1, ArgType2);
- return Func(ArgTypeTraits<ArgType1>::get(Args[0].Value),
- ArgTypeTraits<ArgType2>::get(Args[1].Value)).clone();
+ return outvalueToMatcherList(
+ Func(ArgTypeTraits<ArgType1>::get(Args[0].Value),
+ ArgTypeTraits<ArgType2>::get(Args[1].Value)));
}
#undef CHECK_ARG_COUNT
@@ -202,10 +241,10 @@ DynTypedMatcher *matcherMarshall2(Return
/// \brief Variadic marshaller function.
template <typename BaseType, typename DerivedType>
-DynTypedMatcher *VariadicMatcherCreateCallback(StringRef MatcherName,
- const SourceRange &NameRange,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) {
+MatcherList VariadicMatcherCreateCallback(StringRef MatcherName,
+ const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
typedef ast_matchers::internal::Matcher<DerivedType> DerivedMatcherType;
DerivedMatcherType **InnerArgs = new DerivedMatcherType *[Args.size()]();
@@ -223,10 +262,10 @@ DynTypedMatcher *VariadicMatcherCreateCa
InnerArgs[i] = new DerivedMatcherType(DerivedTraits::get(Value));
}
- DynTypedMatcher *Out = NULL;
+ MatcherList Out;
if (!HasError) {
Out = ast_matchers::internal::makeDynCastAllOfComposite<BaseType>(
- ArrayRef<const DerivedMatcherType *>(InnerArgs, Args.size())).clone();
+ ArrayRef<const DerivedMatcherType *>(InnerArgs, Args.size()));
}
for (size_t i = 0, e = Args.size(); i != e; ++i) {
@@ -264,7 +303,7 @@ MatcherCreateCallback *makeMatcherAutoMa
ReturnType (*)(ArgType1, ArgType2)>(matcherMarshall2, Func, MatcherName);
}
-/// \brief Variadic overload.
+/// \brief Variadic overloads.
template <typename MatcherType>
MatcherCreateCallback *makeMatcherAutoMarshall(
ast_matchers::internal::VariadicAllOfMatcher<MatcherType> Func,
Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp?rev=184558&r1=184557&r2=184558&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Parser.cpp Fri Jun 21 10:51:31 2013
@@ -315,15 +315,15 @@ bool Parser::parseMatcherExpressionImpl(
// Merge the start and end infos.
SourceRange MatcherRange = NameToken.Range;
MatcherRange.End = EndToken.Range.End;
- DynTypedMatcher *Result = S->actOnMatcherExpression(
+ MatcherList Result = S->actOnMatcherExpression(
NameToken.Text, MatcherRange, BindID, Args, Error);
- if (Result == NULL) {
+ if (Result.empty()) {
Error->pushErrorFrame(NameToken.Range, Error->ET_ParserMatcherFailure)
<< NameToken.Text;
return false;
}
- Value->takeMatcher(Result);
+ *Value = Result;
return true;
}
@@ -367,11 +367,11 @@ Parser::Parser(CodeTokenizer *Tokenizer,
class RegistrySema : public Parser::Sema {
public:
virtual ~RegistrySema() {}
- DynTypedMatcher *actOnMatcherExpression(StringRef MatcherName,
- const SourceRange &NameRange,
- StringRef BindID,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) {
+ MatcherList actOnMatcherExpression(StringRef MatcherName,
+ const SourceRange &NameRange,
+ StringRef BindID,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
if (BindID.empty()) {
return Registry::constructMatcher(MatcherName, NameRange, Args, Error);
} else {
@@ -411,11 +411,16 @@ DynTypedMatcher *Parser::parseMatcherExp
VariantValue Value;
if (!parseExpression(Code, S, &Value, Error))
return NULL;
- if (!Value.isMatcher()) {
+ if (!Value.isMatchers()) {
Error->pushErrorFrame(SourceRange(), Error->ET_ParserNotAMatcher);
return NULL;
}
- return Value.getMatcher().clone();
+ if (Value.getMatchers().matchers().size() != 1) {
+ Error->pushErrorFrame(SourceRange(), Error->ET_ParserOverloadedType)
+ << Value.getTypeAsString();
+ return NULL;
+ }
+ return Value.getMatchers().matchers()[0]->clone();
}
} // namespace dynamic
Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=184558&r1=184557&r2=184558&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Fri Jun 21 10:51:31 2013
@@ -68,7 +68,6 @@ RegistryMaps::RegistryMaps() {
// forField
// withInitializer
// isWritten
- // isImplicit
//
// Type traversal:
// hasElementType
@@ -87,19 +86,6 @@ RegistryMaps::RegistryMaps() {
// references
// thisPointerType
//
- // Polymorphic matchers:
- // anything
- // hasAnyArgument
- // isTemplateInstantiation
- // isExplicitTemplateSpecialization
- // isDefinition
- // hasOperatorName
- // hasOverloadedOperatorName
- // hasCondition
- // hasBody
- // argumentCountIs
- // hasArgument
- //
// Polymorphic + argument overload:
// unless
// eachOf
@@ -123,6 +109,8 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(accessSpecDecl);
REGISTER_MATCHER(alignOfExpr);
+ REGISTER_MATCHER(anything);
+ REGISTER_MATCHER(argumentCountIs);
REGISTER_MATCHER(arraySubscriptExpr);
REGISTER_MATCHER(arrayType);
REGISTER_MATCHER(asString);
@@ -175,12 +163,16 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(functionType);
REGISTER_MATCHER(functionalCastExpr);
REGISTER_MATCHER(gotoStmt);
+ REGISTER_MATCHER(hasAnyArgument);
REGISTER_MATCHER(hasAnyParameter);
REGISTER_MATCHER(hasAnySubstatement);
REGISTER_MATCHER(hasAnyUsingShadowDecl);
+ REGISTER_MATCHER(hasArgument);
REGISTER_MATCHER(hasArgumentOfType);
REGISTER_MATCHER(hasBase);
+ REGISTER_MATCHER(hasBody);
REGISTER_MATCHER(hasCanonicalType);
+ REGISTER_MATCHER(hasCondition);
REGISTER_MATCHER(hasConditionVariableStatement);
REGISTER_MATCHER(hasDeclContext);
REGISTER_MATCHER(hasDestinationType);
@@ -196,6 +188,8 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasMethod);
REGISTER_MATCHER(hasName);
REGISTER_MATCHER(hasObjectExpression);
+ REGISTER_MATCHER(hasOperatorName);
+ REGISTER_MATCHER(hasOverloadedOperatorName);
REGISTER_MATCHER(hasParameter);
REGISTER_MATCHER(hasQualifier);
REGISTER_MATCHER(hasRHS);
@@ -216,6 +210,8 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(integerLiteral);
REGISTER_MATCHER(isArrow);
REGISTER_MATCHER(isConstQualified);
+ REGISTER_MATCHER(isDefinition);
+ REGISTER_MATCHER(isExplicitTemplateSpecialization);
REGISTER_MATCHER(isExternC);
REGISTER_MATCHER(isImplicit);
REGISTER_MATCHER(isInteger);
@@ -223,6 +219,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isPrivate);
REGISTER_MATCHER(isProtected);
REGISTER_MATCHER(isPublic);
+ REGISTER_MATCHER(isTemplateInstantiation);
REGISTER_MATCHER(isVirtual);
REGISTER_MATCHER(lValueReferenceType);
REGISTER_MATCHER(labelStmt);
@@ -300,36 +297,39 @@ static llvm::ManagedStatic<RegistryMaps>
} // anonymous namespace
// static
-DynTypedMatcher *Registry::constructMatcher(StringRef MatcherName,
- const SourceRange &NameRange,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) {
+MatcherList Registry::constructMatcher(StringRef MatcherName,
+ const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
ConstructorMap::const_iterator it =
RegistryData->constructors().find(MatcherName);
if (it == RegistryData->constructors().end()) {
Error->pushErrorFrame(NameRange, Error->ET_RegistryNotFound)
<< MatcherName;
- return NULL;
+ return MatcherList();
}
return it->second->run(NameRange, Args, Error);
}
// static
-DynTypedMatcher *Registry::constructBoundMatcher(StringRef MatcherName,
- const SourceRange &NameRange,
- StringRef BindID,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) {
- OwningPtr<DynTypedMatcher> Out(
- constructMatcher(MatcherName, NameRange, Args, Error));
- if (!Out) return NULL;
- DynTypedMatcher *Bound = Out->tryBind(BindID);
- if (!Bound) {
- Error->pushErrorFrame(NameRange, Error->ET_RegistryNotBindable);
- return NULL;
+MatcherList Registry::constructBoundMatcher(StringRef MatcherName,
+ const SourceRange &NameRange,
+ StringRef BindID,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
+ MatcherList Out = constructMatcher(MatcherName, NameRange, Args, Error);
+ if (Out.empty()) return Out;
+
+ ArrayRef<const DynTypedMatcher*> Matchers = Out.matchers();
+ if (Matchers.size() == 1) {
+ OwningPtr<DynTypedMatcher> Bound(Matchers[0]->tryBind(BindID));
+ if (Bound) {
+ return *Bound;
+ }
}
- return Bound;
+ Error->pushErrorFrame(NameRange, Error->ET_RegistryNotBindable);
+ return MatcherList();
}
} // namespace dynamic
Modified: cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp?rev=184558&r1=184557&r2=184558&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp Fri Jun 21 10:51:31 2013
@@ -20,6 +20,48 @@ namespace clang {
namespace ast_matchers {
namespace dynamic {
+MatcherList::MatcherList() : List() {}
+
+MatcherList::MatcherList(const DynTypedMatcher &Matcher)
+ : List(1, Matcher.clone()) {}
+
+MatcherList::MatcherList(const MatcherList& Other) {
+ *this = Other;
+}
+
+MatcherList::~MatcherList() {
+ reset();
+}
+
+MatcherList &MatcherList::operator=(const MatcherList &Other) {
+ if (this == &Other) return *this;
+ reset();
+ for (size_t i = 0, e = Other.List.size(); i != e; ++i) {
+ List.push_back(Other.List[i]->clone());
+ }
+ return *this;
+}
+
+void MatcherList::add(const DynTypedMatcher &Matcher) {
+ List.push_back(Matcher.clone());
+}
+
+void MatcherList::reset() {
+ for (size_t i = 0, e = List.size(); i != e; ++i) {
+ delete List[i];
+ }
+ List.resize(0);
+}
+
+std::string MatcherList::getTypeAsString() const {
+ std::string Inner;
+ for (size_t I = 0, E = List.size(); I != E; ++I) {
+ if (I != 0) Inner += "|";
+ Inner += List[I]->getSupportedKind().asStringRef();
+ }
+ return (Twine("Matcher<") + Inner + ">").str();
+}
+
VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) {
*this = Other;
}
@@ -33,7 +75,11 @@ VariantValue::VariantValue(const std::st
}
VariantValue::VariantValue(const DynTypedMatcher &Matcher) : Type(VT_Nothing) {
- setMatcher(Matcher);
+ setMatchers(MatcherList(Matcher));
+}
+
+VariantValue::VariantValue(const MatcherList &Matchers) : Type(VT_Nothing) {
+ setMatchers(Matchers);
}
VariantValue::~VariantValue() { reset(); }
@@ -48,8 +94,8 @@ VariantValue &VariantValue::operator=(co
case VT_String:
setString(Other.getString());
break;
- case VT_Matcher:
- setMatcher(Other.getMatcher());
+ case VT_Matchers:
+ setMatchers(Other.getMatchers());
break;
case VT_Nothing:
Type = VT_Nothing;
@@ -63,8 +109,8 @@ void VariantValue::reset() {
case VT_String:
delete Value.String;
break;
- case VT_Matcher:
- delete Value.Matcher;
+ case VT_Matchers:
+ delete Value.Matchers;
break;
// Cases that do nothing.
case VT_Unsigned:
@@ -104,33 +150,25 @@ void VariantValue::setString(const std::
Value.String = new std::string(NewValue);
}
-bool VariantValue::isMatcher() const {
- return Type == VT_Matcher;
+bool VariantValue::isMatchers() const {
+ return Type == VT_Matchers;
}
-const DynTypedMatcher &VariantValue::getMatcher() const {
- assert(isMatcher());
- return *Value.Matcher;
-}
-
-void VariantValue::setMatcher(const DynTypedMatcher &NewValue) {
- reset();
- Type = VT_Matcher;
- Value.Matcher = NewValue.clone();
+const MatcherList &VariantValue::getMatchers() const {
+ assert(isMatchers());
+ return *Value.Matchers;
}
-void VariantValue::takeMatcher(DynTypedMatcher *NewValue) {
+void VariantValue::setMatchers(const MatcherList &NewValue) {
reset();
- Type = VT_Matcher;
- Value.Matcher = NewValue;
+ Type = VT_Matchers;
+ Value.Matchers = new MatcherList(NewValue);
}
std::string VariantValue::getTypeAsString() const {
switch (Type) {
case VT_String: return "String";
- case VT_Matcher:
- return (Twine("Matcher<") + getMatcher().getSupportedKind().asStringRef() +
- ">").str();
+ case VT_Matchers: return getMatchers().getTypeAsString();
case VT_Unsigned: return "Unsigned";
case VT_Nothing: return "Nothing";
}
Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp?rev=184558&r1=184557&r2=184558&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp Fri Jun 21 10:51:31 2013
@@ -2250,10 +2250,9 @@ TEST(AstMatcherPMacro, Works) {
}
AST_POLYMORPHIC_MATCHER_P(
- polymorphicHas, internal::Matcher<Decl>, AMatcher) {
- TOOLING_COMPILE_ASSERT((llvm::is_same<NodeType, Decl>::value) ||
- (llvm::is_same<NodeType, Stmt>::value),
- assert_node_type_is_accessible);
+ polymorphicHas,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_2(Decl, Stmt),
+ internal::Matcher<Decl>, AMatcher) {
return Finder->matchesChildOf(
Node, AMatcher, Builder,
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp?rev=184558&r1=184557&r2=184558&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp Fri Jun 21 10:51:31 2013
@@ -52,6 +52,7 @@ public:
virtual ast_type_traits::ASTNodeKind getSupportedKind() const {
return ast_type_traits::ASTNodeKind();
}
+
private:
uint64_t ID;
std::string BoundID;
@@ -75,15 +76,16 @@ public:
Errors.push_back(Error.ToStringFull());
}
- DynTypedMatcher *actOnMatcherExpression(StringRef MatcherName,
- const SourceRange &NameRange,
- StringRef BindID,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) {
+ MatcherList actOnMatcherExpression(StringRef MatcherName,
+ const SourceRange &NameRange,
+ StringRef BindID,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
MatcherInfo ToStore = { MatcherName, NameRange, Args, BindID };
Matchers.push_back(ToStore);
DummyDynTypedMatcher Matcher(ExpectedMatchers[MatcherName]);
- return Matcher.tryBind(BindID);
+ OwningPtr<DynTypedMatcher> Out(Matcher.tryBind(BindID));
+ return *Out;
}
struct MatcherInfo {
@@ -146,9 +148,9 @@ TEST(ParserTest, ParseMatcher) {
}
EXPECT_EQ(1ULL, Sema.Values.size());
- EXPECT_EQ(ExpectedFoo, Sema.Values[0].getMatcher().getID());
- EXPECT_EQ("Yo!", static_cast<const DummyDynTypedMatcher &>(
- Sema.Values[0].getMatcher()).boundID());
+ EXPECT_EQ(ExpectedFoo, Sema.Values[0].getMatchers().matchers()[0]->getID());
+ EXPECT_EQ("Yo!", static_cast<const DummyDynTypedMatcher *>(
+ Sema.Values[0].getMatchers().matchers()[0])->boundID());
EXPECT_EQ(3ULL, Sema.Matchers.size());
const MockSema::MatcherInfo Bar = Sema.Matchers[0];
@@ -167,8 +169,10 @@ TEST(ParserTest, ParseMatcher) {
EXPECT_EQ("Foo", Foo.MatcherName);
EXPECT_TRUE(matchesRange(Foo.NameRange, 1, 2, 2, 12));
EXPECT_EQ(2ULL, Foo.Args.size());
- EXPECT_EQ(ExpectedBar, Foo.Args[0].Value.getMatcher().getID());
- EXPECT_EQ(ExpectedBaz, Foo.Args[1].Value.getMatcher().getID());
+ EXPECT_EQ(ExpectedBar,
+ Foo.Args[0].Value.getMatchers().matchers()[0]->getID());
+ EXPECT_EQ(ExpectedBaz,
+ Foo.Args[1].Value.getMatchers().matchers()[0]->getID());
EXPECT_EQ("Yo!", Foo.BoundID);
}
@@ -176,11 +180,14 @@ using ast_matchers::internal::Matcher;
TEST(ParserTest, FullParserTest) {
OwningPtr<DynTypedMatcher> VarDecl(Parser::parseMatcherExpression(
- "varDecl(hasInitializer(binaryOperator(hasLHS(integerLiteral()))))",
+ "varDecl(hasInitializer(binaryOperator(hasLHS(integerLiteral()),"
+ " hasOperatorName(\"+\"))))",
NULL));
Matcher<Decl> M = Matcher<Decl>::constructFrom(*VarDecl);
EXPECT_TRUE(matches("int x = 1 + false;", M));
EXPECT_FALSE(matches("int x = true + 1;", M));
+ EXPECT_FALSE(matches("int x = 1 - false;", M));
+ EXPECT_FALSE(matches("int x = true - 1;", M));
OwningPtr<DynTypedMatcher> HasParameter(Parser::parseMatcherExpression(
"functionDecl(hasParameter(1, hasName(\"x\")))", NULL));
@@ -242,6 +249,9 @@ TEST(ParserTest, Errors) {
EXPECT_EQ("1:1: Error building matcher isArrow.\n"
"1:1: Matcher does not support binding.",
ParseWithError("isArrow().bind(\"foo\")"));
+ EXPECT_EQ("Input value has unresolved overloaded type: "
+ "Matcher<DoStmt|ForStmt|WhileStmt>",
+ ParseMatcherWithError("hasBody(stmt())"));
}
} // end anonymous namespace
Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp?rev=184558&r1=184557&r2=184558&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp Fri Jun 21 10:51:31 2013
@@ -38,25 +38,23 @@ public:
template <class T>
Matcher<T> constructMatcher(StringRef MatcherName, Diagnostics *Error) {
- OwningPtr<DynTypedMatcher> Out(
- Registry::constructMatcher(MatcherName, SourceRange(), Args(), Error));
- return Matcher<T>::constructFrom(*Out);
+ return Registry::constructMatcher(MatcherName, SourceRange(), Args(), Error)
+ .getTypedMatcher<T>();
}
template <class T>
Matcher<T> constructMatcher(StringRef MatcherName, const VariantValue &Arg1,
Diagnostics *Error) {
- OwningPtr<DynTypedMatcher> Out(Registry::constructMatcher(
- MatcherName, SourceRange(), Args(Arg1), Error));
- return Matcher<T>::constructFrom(*Out);
+ return Registry::constructMatcher(MatcherName, SourceRange(), Args(Arg1),
+ Error).getTypedMatcher<T>();
}
template <class T>
Matcher<T> constructMatcher(StringRef MatcherName, const VariantValue &Arg1,
const VariantValue &Arg2, Diagnostics *Error) {
- OwningPtr<DynTypedMatcher> Out(Registry::constructMatcher(
- MatcherName, SourceRange(), Args(Arg1, Arg2), Error));
- return Matcher<T>::constructFrom(*Out);
+ return Registry::constructMatcher(MatcherName, SourceRange(),
+ Args(Arg1, Arg2), Error)
+ .getTypedMatcher<T>();
}
};
@@ -115,34 +113,57 @@ TEST_F(RegistryTest, ConstructWithMatche
EXPECT_FALSE(matches("void f(int x, int a);", HasParameter));
}
+TEST_F(RegistryTest, PolymorphicMatchers) {
+ const MatcherList IsDefinition =
+ Registry::constructMatcher("isDefinition", SourceRange(), Args(), NULL);
+ Matcher<Decl> Var = constructMatcher<Decl>("varDecl", IsDefinition, NULL);
+ Matcher<Decl> Class =
+ constructMatcher<Decl>("recordDecl", IsDefinition, NULL);
+ Matcher<Decl> Func =
+ constructMatcher<Decl>("functionDecl", IsDefinition, NULL);
+ EXPECT_TRUE(matches("int a;", Var));
+ EXPECT_FALSE(matches("extern int a;", Var));
+ EXPECT_TRUE(matches("class A {};", Class));
+ EXPECT_FALSE(matches("class A;", Class));
+ EXPECT_TRUE(matches("void f(){};", Func));
+ EXPECT_FALSE(matches("void f();", Func));
+
+ Matcher<Decl> Anything = constructMatcher<Decl>("anything", NULL);
+ Matcher<Decl> RecordDecl =
+ constructMatcher<Decl>("recordDecl", Anything, NULL);
+
+ EXPECT_TRUE(matches("int a;", Anything));
+ EXPECT_TRUE(matches("class A {};", Anything));
+ EXPECT_TRUE(matches("void f(){};", Anything));
+ EXPECT_FALSE(matches("int a;", RecordDecl));
+ EXPECT_TRUE(matches("class A {};", RecordDecl));
+ EXPECT_FALSE(matches("void f(){};", RecordDecl));
+}
+
TEST_F(RegistryTest, Errors) {
// Incorrect argument count.
OwningPtr<Diagnostics> Error(new Diagnostics());
- EXPECT_TRUE(NULL ==
- Registry::constructMatcher("hasInitializer", SourceRange(),
- Args(), Error.get()));
+ EXPECT_TRUE(Registry::constructMatcher("hasInitializer", SourceRange(),
+ Args(), Error.get()).empty());
EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
Error->ToString());
Error.reset(new Diagnostics());
- EXPECT_TRUE(NULL ==
- Registry::constructMatcher("isArrow", SourceRange(),
- Args(std::string()), Error.get()));
+ EXPECT_TRUE(Registry::constructMatcher(
+ "isArrow", SourceRange(), Args(std::string()), Error.get()).empty());
EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
Error->ToString());
// Bad argument type
Error.reset(new Diagnostics());
- EXPECT_TRUE(NULL ==
- Registry::constructMatcher("ofClass", SourceRange(),
- Args(std::string()), Error.get()));
+ EXPECT_TRUE(Registry::constructMatcher(
+ "ofClass", SourceRange(), Args(std::string()), Error.get()).empty());
EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
"(Actual = String)",
Error->ToString());
Error.reset(new Diagnostics());
- EXPECT_TRUE(NULL ==
- Registry::constructMatcher(
- "recordDecl", SourceRange(),
- Args(recordDecl(), parameterCountIs(3)), Error.get()));
+ EXPECT_TRUE(Registry::constructMatcher(
+ "recordDecl", SourceRange(), Args(recordDecl(), parameterCountIs(3)),
+ Error.get()).empty());
EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
"(Actual = Matcher<FunctionDecl>)",
Error->ToString());
Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp?rev=184558&r1=184557&r2=184558&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp Fri Jun 21 10:51:31 2013
@@ -27,9 +27,9 @@ TEST(VariantValueTest, Unsigned) {
EXPECT_EQ(kUnsigned, Value.getUnsigned());
EXPECT_FALSE(Value.isString());
- EXPECT_FALSE(Value.isMatcher());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
+ EXPECT_FALSE(Value.isMatchers());
+ EXPECT_FALSE(Value.hasTypedMatcher<Decl>());
+ EXPECT_FALSE(Value.hasTypedMatcher<UnaryOperator>());
}
TEST(VariantValueTest, String) {
@@ -41,9 +41,7 @@ TEST(VariantValueTest, String) {
EXPECT_EQ("String", Value.getTypeAsString());
EXPECT_FALSE(Value.isUnsigned());
- EXPECT_FALSE(Value.isMatcher());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
+ EXPECT_FALSE(Value.isMatchers());
}
TEST(VariantValueTest, DynTypedMatcher) {
@@ -52,25 +50,25 @@ TEST(VariantValueTest, DynTypedMatcher)
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
- EXPECT_TRUE(Value.isMatcher());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
- EXPECT_TRUE(Value.hasTypedMatcher<clang::UnaryOperator>());
+ EXPECT_TRUE(Value.isMatchers());
+ EXPECT_FALSE(Value.hasTypedMatcher<Decl>());
+ EXPECT_TRUE(Value.hasTypedMatcher<UnaryOperator>());
EXPECT_EQ("Matcher<Stmt>", Value.getTypeAsString());
// Can only convert to compatible matchers.
Value = recordDecl();
- EXPECT_TRUE(Value.isMatcher());
- EXPECT_TRUE(Value.hasTypedMatcher<clang::Decl>());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
+ EXPECT_TRUE(Value.isMatchers());
+ EXPECT_TRUE(Value.hasTypedMatcher<Decl>());
+ EXPECT_FALSE(Value.hasTypedMatcher<UnaryOperator>());
EXPECT_EQ("Matcher<Decl>", Value.getTypeAsString());
Value = ignoringImpCasts(expr());
- EXPECT_TRUE(Value.isMatcher());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::Stmt>());
- EXPECT_TRUE(Value.hasTypedMatcher<clang::Expr>());
- EXPECT_TRUE(Value.hasTypedMatcher<clang::IntegerLiteral>());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::GotoStmt>());
+ EXPECT_TRUE(Value.isMatchers());
+ EXPECT_FALSE(Value.hasTypedMatcher<Decl>());
+ EXPECT_FALSE(Value.hasTypedMatcher<Stmt>());
+ EXPECT_TRUE(Value.hasTypedMatcher<Expr>());
+ EXPECT_TRUE(Value.hasTypedMatcher<IntegerLiteral>());
+ EXPECT_FALSE(Value.hasTypedMatcher<GotoStmt>());
EXPECT_EQ("Matcher<Expr>", Value.getTypeAsString());
}
@@ -79,31 +77,31 @@ TEST(VariantValueTest, Assignment) {
EXPECT_TRUE(Value.isString());
EXPECT_EQ("A", Value.getString());
EXPECT_FALSE(Value.isUnsigned());
- EXPECT_FALSE(Value.isMatcher());
+ EXPECT_FALSE(Value.isMatchers());
EXPECT_EQ("String", Value.getTypeAsString());
Value = recordDecl();
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
- EXPECT_TRUE(Value.isMatcher());
- EXPECT_TRUE(Value.hasTypedMatcher<clang::Decl>());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
+ EXPECT_TRUE(Value.isMatchers());
+ EXPECT_TRUE(Value.hasTypedMatcher<Decl>());
+ EXPECT_FALSE(Value.hasTypedMatcher<UnaryOperator>());
EXPECT_EQ("Matcher<Decl>", Value.getTypeAsString());
Value = 17;
EXPECT_TRUE(Value.isUnsigned());
EXPECT_EQ(17U, Value.getUnsigned());
- EXPECT_FALSE(Value.isMatcher());
+ EXPECT_FALSE(Value.isMatchers());
EXPECT_FALSE(Value.isString());
Value = VariantValue();
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
- EXPECT_FALSE(Value.isMatcher());
+ EXPECT_FALSE(Value.isMatchers());
EXPECT_EQ("Nothing", Value.getTypeAsString());
}
-TEST(GenericValueTest, Matcher) {
+TEST(VariantValueTest, Matcher) {
EXPECT_TRUE(matches("class X {};", VariantValue(recordDecl(hasName("X")))
.getTypedMatcher<Decl>()));
EXPECT_TRUE(
@@ -117,13 +115,15 @@ TEST(GenericValueTest, Matcher) {
// do this test when building with MSVC because its debug C runtime prints the
// assertion failure message as a wide string, which gtest doesn't understand.
EXPECT_DEATH(VariantValue(varDecl()).getTypedMatcher<Stmt>(),
- "canConstructFrom");
+ "hasTypedMatcher");
#endif
EXPECT_FALSE(
matches("int x;", VariantValue(functionDecl()).getTypedMatcher<Decl>()));
- EXPECT_FALSE(matches("int foo() { return 1 + 1; }",
- VariantValue(declRefExpr()).getTypedMatcher<Stmt>()));
+ EXPECT_FALSE(
+ matches("int foo() { return 1 + 1; }",
+
+ VariantValue(declRefExpr()).getTypedMatcher<Stmt>()));
}
} // end anonymous namespace
More information about the cfe-commits
mailing list