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

llvm-svn: 201804
This commit is contained in:
Peter Collingbourne 2014-02-20 19:18:03 +00:00
parent b7a40081e9
commit 564597fd26
4 changed files with 79 additions and 15 deletions

View File

@ -34,8 +34,7 @@ struct PrintingPolicy;
class TypeSourceInfo; class TypeSourceInfo;
class ValueDecl; class ValueDecl;
/// \brief Represents a template argument within a class template /// \brief Represents a template argument.
/// specialization.
class TemplateArgument { class TemplateArgument {
public: public:
/// \brief The kind of template argument we're storing. /// \brief The kind of template argument we're storing.
@ -60,8 +59,11 @@ public:
/// 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. /// provided for a template template parameter.
TemplateExpansion, TemplateExpansion,
/// The template argument is a value- or type-dependent expression or a /// The template argument is an expression, and we've not resolved it to one
/// non-dependent __uuidof expression stored in an Expr*. /// 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, Expression,
/// The template argument is actually a parameter pack. Arguments are stored /// The template argument is actually a parameter pack. Arguments are stored
/// in the Args struct. /// in the Args struct.

View File

@ -311,6 +311,18 @@ AST_MATCHER(Decl, isPrivate) {
return Node.getAccess() == AS_private; 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 /// \brief Matches classTemplateSpecializations that have at least one
/// TemplateArgument matching the given InnerMatcher. /// TemplateArgument matching the given InnerMatcher.
/// ///
@ -323,9 +335,12 @@ AST_MATCHER(Decl, isPrivate) {
/// classTemplateSpecializationDecl(hasAnyTemplateArgument( /// classTemplateSpecializationDecl(hasAnyTemplateArgument(
/// refersToType(asString("int")))) /// refersToType(asString("int"))))
/// matches the specialization \c A<int> /// matches the specialization \c A<int>
AST_MATCHER_P(ClassTemplateSpecializationDecl, hasAnyTemplateArgument, AST_POLYMORPHIC_MATCHER_P(
hasAnyTemplateArgument,
AST_POLYMORPHIC_SUPPORTED_TYPES_2(ClassTemplateSpecializationDecl,
TemplateSpecializationType),
internal::Matcher<TemplateArgument>, InnerMatcher) { internal::Matcher<TemplateArgument>, InnerMatcher) {
llvm::ArrayRef<TemplateArgument> List = Node.getTemplateArgs().asArray(); llvm::ArrayRef<TemplateArgument> List = getTemplateSpecializationArgs(Node);
return matchesFirstInRange(InnerMatcher, List.begin(), List.end(), Finder, return matchesFirstInRange(InnerMatcher, List.begin(), List.end(), Finder,
Builder); Builder);
} }
@ -419,12 +434,15 @@ AST_MATCHER_P(Expr, ignoringParenImpCasts,
/// classTemplateSpecializationDecl(hasTemplateArgument( /// classTemplateSpecializationDecl(hasTemplateArgument(
/// 1, refersToType(asString("int")))) /// 1, refersToType(asString("int"))))
/// matches the specialization \c A<bool, int> /// matches the specialization \c A<bool, int>
AST_MATCHER_P2(ClassTemplateSpecializationDecl, hasTemplateArgument, AST_POLYMORPHIC_MATCHER_P2(
hasTemplateArgument,
AST_POLYMORPHIC_SUPPORTED_TYPES_2(ClassTemplateSpecializationDecl,
TemplateSpecializationType),
unsigned, N, internal::Matcher<TemplateArgument>, InnerMatcher) { unsigned, N, internal::Matcher<TemplateArgument>, InnerMatcher) {
const TemplateArgumentList &List = Node.getTemplateArgs(); llvm::ArrayRef<TemplateArgument> List = getTemplateSpecializationArgs(Node);
if (List.size() <= N) if (List.size() <= N)
return false; 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. /// \brief Matches a TemplateArgument that refers to a certain type.
@ -445,7 +463,8 @@ AST_MATCHER_P(TemplateArgument, refersToType,
return InnerMatcher.matches(Node.getAsType(), Finder, Builder); 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 /// Given
/// \code /// \code
@ -464,6 +483,24 @@ AST_MATCHER_P(TemplateArgument, refersToDeclaration,
return false; 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. /// \brief Matches C++ constructor declarations.
/// ///
/// Example matches Foo::Foo() and Foo::Foo(int) /// Example matches Foo::Foo() and Foo::Foo(int)

View File

@ -228,6 +228,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isConstQualified); REGISTER_MATCHER(isConstQualified);
REGISTER_MATCHER(isDefinition); REGISTER_MATCHER(isDefinition);
REGISTER_MATCHER(isExplicitTemplateSpecialization); REGISTER_MATCHER(isExplicitTemplateSpecialization);
REGISTER_MATCHER(isExpr);
REGISTER_MATCHER(isExternC); REGISTER_MATCHER(isExternC);
REGISTER_MATCHER(isImplicit); REGISTER_MATCHER(isImplicit);
REGISTER_MATCHER(isInteger); REGISTER_MATCHER(isInteger);

View File

@ -1530,6 +1530,19 @@ TEST(Matcher, MatchesDeclarationReferenceTemplateArgument) {
"A<int> a;", "A<int> a;",
classTemplateSpecializationDecl(hasAnyTemplateArgument( classTemplateSpecializationDecl(hasAnyTemplateArgument(
refersToDeclaration(decl()))))); 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) { TEST(Matcher, MatchesSpecificArgument) {
@ -1543,6 +1556,17 @@ TEST(Matcher, MatchesSpecificArgument) {
"A<int, bool> a;", "A<int, bool> a;",
classTemplateSpecializationDecl(hasTemplateArgument( classTemplateSpecializationDecl(hasTemplateArgument(
1, refersToType(asString("int")))))); 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) { TEST(Matcher, MatchesAccessSpecDecls) {