[ASTMatchers] Add support for matching the type of a friend decl.

This allows matchers like:

  friendDecl(hasType(cxxRecordDecl(...)))
  friendDecl(hasType(asString(...)))

It seems that hasType is probably the most reasonable narrowing matcher to
overload, since it is already used to narrow to other declaration kinds.

Differential Revision: https://reviews.llvm.org/D48242

Reviewers: klimek, aaron.ballman

Subscribers: cfe-commits
llvm-svn: 334930
This commit is contained in:
David L. Jones 2018-06-18 09:23:08 +00:00
parent 8f7adcd7fb
commit 82e08bd776
3 changed files with 30 additions and 8 deletions

View File

@ -2860,13 +2860,17 @@ AST_MATCHER_P_OVERLOAD(CallExpr, callee, internal::Matcher<Decl>, InnerMatcher,
/// Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
/// and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
/// and U (matcher = typedefDecl(hasType(asString("int")))
/// and friend class X (matcher = friendDecl(hasType("X"))
/// \code
/// class X {};
/// void y(X &x) { x; X z; }
/// typedef int U;
/// class Y { friend class X; };
/// \endcode
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
hasType, AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, TypedefNameDecl, ValueDecl),
hasType,
AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, FriendDecl, TypedefNameDecl,
ValueDecl),
internal::Matcher<QualType>, InnerMatcher, 0) {
QualType QT = internal::getUnderlyingType(Node);
if (!QT.isNull())
@ -2885,18 +2889,21 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
///
/// Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
/// and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
/// and friend class X (matcher = friendDecl(hasType("X"))
/// \code
/// class X {};
/// void y(X &x) { x; X z; }
/// class Y { friend class X; };
/// \endcode
///
/// Usable as: Matcher<Expr>, Matcher<ValueDecl>
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(hasType,
AST_POLYMORPHIC_SUPPORTED_TYPES(Expr,
ValueDecl),
internal::Matcher<Decl>, InnerMatcher, 1) {
return qualType(hasDeclaration(InnerMatcher))
.matches(Node.getType(), Finder, Builder);
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
hasType, AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, FriendDecl, ValueDecl),
internal::Matcher<Decl>, InnerMatcher, 1) {
QualType QT = internal::getUnderlyingType(Node);
if (!QT.isNull())
return qualType(hasDeclaration(InnerMatcher)).matches(QT, Finder, Builder);
return false;
}
/// Matches if the type location of the declarator decl's type matches

View File

@ -38,6 +38,7 @@
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
@ -120,10 +121,14 @@ inline QualType getUnderlyingType(const Expr &Node) { return Node.getType(); }
inline QualType getUnderlyingType(const ValueDecl &Node) {
return Node.getType();
}
inline QualType getUnderlyingType(const TypedefNameDecl &Node) {
return Node.getUnderlyingType();
}
inline QualType getUnderlyingType(const FriendDecl &Node) {
if (const TypeSourceInfo *TSI = Node.getFriendType())
return TSI->getType();
return QualType();
}
/// Unifies obtaining the FunctionProtoType pointer from both
/// FunctionProtoType and FunctionDecl nodes..

View File

@ -160,6 +160,16 @@ TEST(ValueDecl, Matches) {
valueDecl(hasType(asString("void (void)")))));
}
TEST(FriendDecl, Matches) {
EXPECT_TRUE(matches("class Y { friend class X; };",
friendDecl(hasType(asString("class X")))));
EXPECT_TRUE(matches("class Y { friend class X; };",
friendDecl(hasType(recordDecl(hasName("X"))))));
EXPECT_TRUE(matches("class Y { friend void f(); };",
functionDecl(hasName("f"), hasParent(friendDecl()))));
}
TEST(Enum, DoesNotMatchClasses) {
EXPECT_TRUE(notMatches("class X {};", enumDecl(hasName("X"))));
}