Index: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h +++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h @@ -2860,13 +2860,17 @@ /// 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, InnerMatcher, 0) { QualType QT = internal::getUnderlyingType(Node); if (!QT.isNull()) @@ -2885,18 +2889,21 @@ /// /// 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, Matcher -AST_POLYMORPHIC_MATCHER_P_OVERLOAD(hasType, - AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, - ValueDecl), - internal::Matcher, 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, 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 Index: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h =================================================================== --- cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h +++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -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 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.. Index: cfe/trunk/unittests/ASTMatchers/ASTMatchersNodeTest.cpp =================================================================== --- cfe/trunk/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ cfe/trunk/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -160,6 +160,16 @@ 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")))); }