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 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.
@ -60,8 +59,11 @@ public:
/// 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.

View File

@ -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, ignoringParenImpCasts,
/// 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, refersToType,
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, refersToDeclaration,
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)

View File

@ -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);

View File

@ -1530,6 +1530,19 @@ TEST(Matcher, MatchesDeclarationReferenceTemplateArgument) {
"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) {