forked from OSchip/llvm-project
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:
parent
b7a40081e9
commit
564597fd26
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue