Index: docs/LibASTMatchersReference.html =================================================================== --- docs/LibASTMatchersReference.html +++ docs/LibASTMatchersReference.html @@ -4891,6 +4891,18 @@ +
Matches a NamedDecl whose underlying declaration matches the given +matcher. + +Given + class X {}; + typedef X Y; +namedDecl(hasUnderlyingDecl(hasName("X"))) + matches both X and Y . +
Matches on the prefix of a NestedNameSpecifierLoc. @@ -4978,6 +4990,18 @@+ + Matcher<OverloadExpr> canReferToDecl Matcher<Decl> InnerMatcher + + Matches any Decl of an OverloadExpr that matches the given +matcher. + +Given + void foo(int); + template <typename T> void bar(T t) { foo(t); } +unresolvedLookupExpr(canReferToDecl(functionDecl())) + matches foo in foo(t); +Matcher<ParenType> innerType Matcher<Type> Matches ParenType nodes where the inner type is a specific type. Index: include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -2422,6 +2422,24 @@ void(internal::HasDeclarationSupportedTypes)>(InnerMatcher); } +/// \brief Matches a \c NamedDecl whose underlying declaration matches the given +/// matcher. +/// +/// Given +/// \code +/// class X {}; +/// typedef X Y; +/// \endcode +/// \c namedDecl(hasUnderlyingDecl(hasName("X"))) +/// matches both \c X and \c Y . +AST_MATCHER_P(NamedDecl, hasUnderlyingDecl, internal::Matcher, + InnerMatcher) { + const NamedDecl *UnderlyingDecl = Node.getUnderlyingDecl(); + + return (UnderlyingDecl != nullptr && + InnerMatcher.matches(*UnderlyingDecl, Finder, Builder)); +} + /// \brief Matches on the implicit object argument of a member call expression. /// /// Example matches y.x() @@ -2777,6 +2795,22 @@ return false; } +/// \brief Matches any \c Decl of an \c OverloadExpr that matches the given +/// matcher. +/// +/// Given +/// \code +/// void foo(int); +/// template void bar(T t) { foo(t); } +/// \endcode +/// unresolvedLookupExpr(canReferToDecl(functionDecl())) +/// matches \c foo in \c foo(t); +AST_MATCHER_P(OverloadExpr, canReferToDecl, internal::Matcher , + InnerMatcher) { + return matchesFirstInPointerRange(InnerMatcher, Node.decls_begin(), + Node.decls_end(), Finder, Builder); +} + /// \brief Matches the Decl of a DeclStmt which has a single declaration. /// /// Given Index: lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- lib/ASTMatchers/Dynamic/Registry.cpp +++ lib/ASTMatchers/Dynamic/Registry.cpp @@ -115,6 +115,7 @@ REGISTER_MATCHER(breakStmt); REGISTER_MATCHER(builtinType); REGISTER_MATCHER(callExpr); + REGISTER_MATCHER(canReferToDecl); REGISTER_MATCHER(caseStmt); REGISTER_MATCHER(castExpr); REGISTER_MATCHER(characterLiteral); @@ -265,6 +266,7 @@ REGISTER_MATCHER(hasTypeLoc); REGISTER_MATCHER(hasUnaryOperand); REGISTER_MATCHER(hasUnarySelector); + REGISTER_MATCHER(hasUnderlyingDecl); REGISTER_MATCHER(hasValueType); REGISTER_MATCHER(ifStmt); REGISTER_MATCHER(ignoringImplicit); Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp =================================================================== --- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -241,6 +241,17 @@ hasDeclaration(namedDecl(hasName("A")))))))); } +TEST(HasUnderlyingDecl, Matches) { + EXPECT_TRUE(matches("class A{};"), + cxxRecordDecl(hasName("A"), hasUnderlyingDecl(hasName("A")))); + EXPECT_TRUE(matches("class A{}; typedef A B;"), + typedefDecl(hasName("B"), hasUnderlyingDecl(hasName("A")))); + EXPECT_TRUE(matches("class A{}; typedef A B; typedef B C;"), + typedefDecl(hasName("C"), hasUnderlyingDecl(hasName("A")))); + EXPECT_TRUE(notMatches("class A{}; class B{}; typedef B C;"), + typedefDecl(hasName("C"), hasUnderlyingDecl(hasName("A")))); +} + TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) { TypeMatcher ClassX = hasDeclaration(recordDecl(hasName("X"))); EXPECT_TRUE( @@ -2051,5 +2062,24 @@ EXPECT_TRUE(notMatches(Code2, ForEachOverriddenInClass("A1"))); } +TEST(Matcher, CanReferToDecl) { + std::string Fragment = "void foo(int p1);" + "void foo(int *p2);" + "void bar(int p3);" + "template void baz(T t) { foo(t); }"; + + EXPECT_TRUE( + matches(Fragment, unresolvedLookupExpr(canReferToDecl(functionDecl( + hasParameter(0, parmVarDecl(hasName("p1")))))))); + EXPECT_TRUE( + matches(Fragment, unresolvedLookupExpr(canReferToDecl(functionDecl( + hasParameter(0, parmVarDecl(hasName("p2")))))))); + EXPECT_TRUE( + notMatches(Fragment, unresolvedLookupExpr(canReferToDecl(functionDecl( + hasParameter(0, parmVarDecl(hasName("p3")))))))); + EXPECT_TRUE(notMatches(Fragment, unresolvedLookupExpr(canReferToDecl( + functionDecl(hasName("bar")))))); +} + } // namespace ast_matchers } // namespace clang