[PATCH] Add TemplateSpecializationType polymorphism for hasTemplateArgument and hasAnyTemplateArgument, and (out of necessity) a refersToExpr matcher.
Peter Collingbourne
peter at pcc.me.uk
Fri Feb 14 19:27:57 PST 2014
Hi klimek,
Also updates the TemplateArgument doxygen to reflect my understanding
of non-canonical TemplateArguments.
http://llvm-reviews.chandlerc.com/D2810
Files:
include/clang/AST/TemplateBase.h
include/clang/ASTMatchers/ASTMatchers.h
lib/ASTMatchers/Dynamic/Registry.cpp
unittests/ASTMatchers/ASTMatchersTest.cpp
Index: include/clang/AST/TemplateBase.h
===================================================================
--- include/clang/AST/TemplateBase.h
+++ include/clang/AST/TemplateBase.h
@@ -35,7 +35,7 @@
class ValueDecl;
/// \brief Represents a template argument within a class template
-/// specialization.
+/// specialization or a template specialization type.
class TemplateArgument {
public:
/// \brief The kind of template argument we're storing.
@@ -52,16 +52,18 @@
/// was provided for a non-type template parameter.
NullPtr,
/// The template argument is an integral value stored in an llvm::APSInt
- /// that was provided for an integral non-type template parameter.
+ /// that was provided for an integral non-type template parameter.
Integral,
- /// The template argument is a template name that was provided for a
+ /// The template argument is a template name that was provided for a
/// template template parameter.
Template,
- /// The template argument is a pack expansion of a template name that was
+ /// The template argument is a pack expansion of a template name that was
/// provided for a template template parameter.
TemplateExpansion,
- /// The template argument is a value- or type-dependent expression or a
- /// non-dependent __uuidof expression stored in an Expr*.
+ /// If owned by a template specialization type, the template argument is any
+ /// expression. Otherwise, the template argument is a value- or
+ /// type-dependent expression or a non-dependent __uuidof expression stored
+ /// in an Expr*.
Expression,
/// The template argument is actually a parameter pack. Arguments are stored
/// in the Args struct.
Index: include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -311,6 +311,18 @@
return Node.getAccess() == AS_private;
}
+// TODO: unify ClassTemplateSpecializationDecl and TemplateSpecializationType's
+// APIs for accessing the template argument list.
+inline llvm::ArrayRef<TemplateArgument>
+getTemplateSpecializationArgs(const ClassTemplateSpecializationDecl &D) {
+ return D.getTemplateArgs().asArray();
+}
+
+inline llvm::ArrayRef<TemplateArgument>
+getTemplateSpecializationArgs(const TemplateSpecializationType &T) {
+ return llvm::ArrayRef<TemplateArgument>(T.getArgs(), T.getNumArgs());
+}
+
/// \brief Matches classTemplateSpecializations that have at least one
/// TemplateArgument matching the given InnerMatcher.
///
@@ -323,9 +335,12 @@
/// classTemplateSpecializationDecl(hasAnyTemplateArgument(
/// refersToType(asString("int"))))
/// matches the specialization \c A<int>
-AST_MATCHER_P(ClassTemplateSpecializationDecl, hasAnyTemplateArgument,
- internal::Matcher<TemplateArgument>, InnerMatcher) {
- llvm::ArrayRef<TemplateArgument> List = Node.getTemplateArgs().asArray();
+AST_POLYMORPHIC_MATCHER_P(
+ hasAnyTemplateArgument,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_2(ClassTemplateSpecializationDecl,
+ TemplateSpecializationType),
+ internal::Matcher<TemplateArgument>, InnerMatcher) {
+ llvm::ArrayRef<TemplateArgument> List = getTemplateSpecializationArgs(Node);
return matchesFirstInRange(InnerMatcher, List.begin(), List.end(), Finder,
Builder);
}
@@ -419,12 +434,15 @@
/// classTemplateSpecializationDecl(hasTemplateArgument(
/// 1, refersToType(asString("int"))))
/// matches the specialization \c A<bool, int>
-AST_MATCHER_P2(ClassTemplateSpecializationDecl, hasTemplateArgument,
- unsigned, N, internal::Matcher<TemplateArgument>, InnerMatcher) {
- const TemplateArgumentList &List = Node.getTemplateArgs();
+AST_POLYMORPHIC_MATCHER_P2(
+ hasTemplateArgument,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_2(ClassTemplateSpecializationDecl,
+ TemplateSpecializationType),
+ unsigned, N, internal::Matcher<TemplateArgument>, InnerMatcher) {
+ llvm::ArrayRef<TemplateArgument> List = getTemplateSpecializationArgs(Node);
if (List.size() <= N)
return false;
- return InnerMatcher.matches(List.get(N), Finder, Builder);
+ return InnerMatcher.matches(List[N], Finder, Builder);
}
/// \brief Matches a TemplateArgument that refers to a certain type.
@@ -445,7 +463,8 @@
return InnerMatcher.matches(Node.getAsType(), Finder, Builder);
}
-/// \brief Matches a TemplateArgument that refers to a certain declaration.
+/// \brief Matches a canonical TemplateArgument that refers to a certain
+/// declaration.
///
/// Given
/// \code
@@ -464,6 +483,25 @@
return false;
}
+/// \brief Matches a sugar TemplateArgument that refers to a certain expression.
+///
+/// Given
+/// \code
+/// template<typename T> struct A {};
+/// struct B { B* next; };
+/// A<&B::next> a;
+/// \endcode
+/// templateSpecializationType(hasAnyTemplateArgument(
+/// refersToExpr(hasDescendant(declRefExpr(to(fieldDecl(hasName("next"))))))))
+/// matches the specialization \c A<&B::next> with \c fieldDecl(...) matching
+/// \c B::next
+AST_MATCHER_P(TemplateArgument, refersToExpr,
+ internal::Matcher<Expr>, InnerMatcher) {
+ if (Node.getKind() == TemplateArgument::Expression)
+ return InnerMatcher.matches(*Node.getAsExpr(), Finder, Builder);
+ return false;
+}
+
/// \brief Matches C++ constructor declarations.
///
/// Example matches Foo::Foo() and Foo::Foo(int)
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===================================================================
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -272,6 +272,7 @@
REGISTER_MATCHER(recordType);
REGISTER_MATCHER(referenceType);
REGISTER_MATCHER(refersToDeclaration);
+ REGISTER_MATCHER(refersToExpr);
REGISTER_MATCHER(refersToType);
REGISTER_MATCHER(reinterpretCastExpr);
REGISTER_MATCHER(returnStmt);
Index: unittests/ASTMatchers/ASTMatchersTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -1527,6 +1527,19 @@
"A<int> a;",
classTemplateSpecializationDecl(hasAnyTemplateArgument(
refersToDeclaration(decl())))));
+
+ EXPECT_TRUE(matches(
+ "struct B { int next; };"
+ "template<int(B::*next_ptr)> struct A {};"
+ "A<&B::next> a;",
+ templateSpecializationType(hasAnyTemplateArgument(refersToExpr(
+ hasDescendant(declRefExpr(to(fieldDecl(hasName("next"))))))))));
+
+ EXPECT_TRUE(notMatches(
+ "template <typename T> struct A {};"
+ "A<int> a;",
+ templateSpecializationType(hasAnyTemplateArgument(
+ refersToDeclaration(decl())))));
}
TEST(Matcher, MatchesSpecificArgument) {
@@ -1540,6 +1553,17 @@
"A<int, bool> a;",
classTemplateSpecializationDecl(hasTemplateArgument(
1, refersToType(asString("int"))))));
+
+ EXPECT_TRUE(matches(
+ "template<typename T, typename U> class A {};"
+ "A<bool, int> a;",
+ templateSpecializationType(hasTemplateArgument(
+ 1, refersToType(asString("int"))))));
+ EXPECT_TRUE(notMatches(
+ "template<typename T, typename U> class A {};"
+ "A<int, bool> a;",
+ templateSpecializationType(hasTemplateArgument(
+ 1, refersToType(asString("int"))))));
}
TEST(Matcher, MatchesAccessSpecDecls) {
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D2810.1.patch
Type: text/x-patch
Size: 7563 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140214/50b75f65/attachment.bin>
More information about the cfe-commits
mailing list