r201804 - Add TemplateSpecializationType polymorphism for hasTemplateArgument and
Peter Collingbourne
peter at pcc.me.uk
Thu Feb 20 11:18:03 PST 2014
Author: pcc
Date: Thu Feb 20 13:18:03 2014
New Revision: 201804
URL: http://llvm.org/viewvc/llvm-project?rev=201804&view=rev
Log:
Add TemplateSpecializationType polymorphism for hasTemplateArgument and
hasAnyTemplateArgument, and (out of necessity) an isExpr matcher.
Also updates the TemplateArgument doxygen to reflect reality for
non-canonical template arguments.
Differential Revision: http://llvm-reviews.chandlerc.com/D2810
Modified:
cfe/trunk/include/clang/AST/TemplateBase.h
cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp
Modified: cfe/trunk/include/clang/AST/TemplateBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TemplateBase.h?rev=201804&r1=201803&r2=201804&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/TemplateBase.h (original)
+++ cfe/trunk/include/clang/AST/TemplateBase.h Thu Feb 20 13:18:03 2014
@@ -34,8 +34,7 @@ struct PrintingPolicy;
class TypeSourceInfo;
class ValueDecl;
-/// \brief Represents a template argument within a class template
-/// specialization.
+/// \brief Represents a template argument.
class TemplateArgument {
public:
/// \brief The kind of template argument we're storing.
@@ -52,16 +51,19 @@ public:
/// 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*.
+ /// The template argument is an expression, and we've not resolved it to one
+ /// of the other forms yet, either because it's dependent or because we're
+ /// representing a non-canonical template argument (for instance, in a
+ /// TemplateSpecializationType). Also used to represent a non-dependent
+ /// __uuidof expression (a Microsoft extension).
Expression,
/// The template argument is actually a parameter pack. Arguments are stored
/// in the Args struct.
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=201804&r1=201803&r2=201804&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Thu Feb 20 13:18:03 2014
@@ -311,6 +311,18 @@ AST_MATCHER(Decl, isPrivate) {
return Node.getAccess() == AS_private;
}
+// FIXME: 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 @@ AST_MATCHER(Decl, isPrivate) {
/// 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 @@ AST_MATCHER_P(Expr, ignoringParenImpCast
/// 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 @@ AST_MATCHER_P(TemplateArgument, refersTo
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,24 @@ AST_MATCHER_P(TemplateArgument, refersTo
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(
+/// isExpr(hasDescendant(declRefExpr(to(fieldDecl(hasName("next"))))))))
+/// matches the specialization \c A<&B::next> with \c fieldDecl(...) matching
+/// \c B::next
+AST_MATCHER_P(TemplateArgument, isExpr, 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)
Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=201804&r1=201803&r2=201804&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Thu Feb 20 13:18:03 2014
@@ -228,6 +228,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isConstQualified);
REGISTER_MATCHER(isDefinition);
REGISTER_MATCHER(isExplicitTemplateSpecialization);
+ REGISTER_MATCHER(isExpr);
REGISTER_MATCHER(isExternC);
REGISTER_MATCHER(isImplicit);
REGISTER_MATCHER(isInteger);
Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp?rev=201804&r1=201803&r2=201804&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp Thu Feb 20 13:18:03 2014
@@ -1530,6 +1530,19 @@ TEST(Matcher, MatchesDeclarationReferenc
"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(isExpr(
+ hasDescendant(declRefExpr(to(fieldDecl(hasName("next"))))))))));
+
+ EXPECT_TRUE(notMatches(
+ "template <typename T> struct A {};"
+ "A<int> a;",
+ templateSpecializationType(hasAnyTemplateArgument(
+ refersToDeclaration(decl())))));
}
TEST(Matcher, MatchesSpecificArgument) {
@@ -1543,6 +1556,17 @@ TEST(Matcher, MatchesSpecificArgument) {
"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) {
More information about the cfe-commits
mailing list