Index: docs/LibASTMatchersReference.html =================================================================== --- docs/LibASTMatchersReference.html +++ docs/LibASTMatchersReference.html @@ -4958,6 +4958,19 @@ +
Matches a NamedDecl whose underlying declaration matches the given +matcher. + +Given + namespace N { template<class T> void f(T t); } + template <class T> void g() { using N::f; f(T()); } +unresolvedLookupExpr(canReferToDecl( + namedDecl(hasUnderlyingDecl(hasName("::N::f"))))) + matches the use of f in g() . +
Matches on the prefix of a NestedNameSpecifierLoc. @@ -5045,6 +5058,22 @@+ + Matcher<OverloadExpr> canReferToDecl Matcher<Decl> InnerMatcher + + Matches an OverloadExpr if any of the declarations in the set of +overloads matches the given matcher. + +Given + template <typename T> void foo(T); + template <typename T> void bar(T); + template <typename T> void baz(T t) { + foo(t); + bar(t); + } +unresolvedLookupExpr(canReferToDecl(functionTemplateDecl(hasName("foo")))) + matches foo in foo(t); but not bar in bar(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 @@ -2468,6 +2468,25 @@ void(internal::HasDeclarationSupportedTypes)>(InnerMatcher); } +/// \brief Matches a \c NamedDecl whose underlying declaration matches the given +/// matcher. +/// +/// Given +/// \code +/// namespace N { templatevoid f(T t); } +/// template void g() { using N::f; f(T()); } +/// \endcode +/// \c unresolvedLookupExpr(canReferToDecl( +/// namedDecl(hasUnderlyingDecl(hasName("::N::f"))))) +/// matches the use of \c f in \c g() . +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() @@ -2823,6 +2842,26 @@ return false; } +/// \brief Matches an \c OverloadExpr if any of the declarations in the set of +/// overloads matches the given matcher. +/// +/// Given +/// \code +/// template void foo(T); +/// template void bar(T); +/// template void baz(T t) { +/// foo(t); +/// bar(t); +/// } +/// \endcode +/// unresolvedLookupExpr(canReferToDecl(functionTemplateDecl(hasName("foo")))) +/// matches \c foo in \c foo(t); but not \c bar in \c bar(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,21 @@ hasDeclaration(namedDecl(hasName("A")))))))); } +TEST(HasUnderlyingDecl, Matches) { + EXPECT_TRUE(matches("namespace N { template void f(T t); }" + "template void g() { using N::f; f(T()); }", + unresolvedLookupExpr(canReferToDecl( + namedDecl(hasUnderlyingDecl(hasName("::N::f"))))))); + EXPECT_TRUE(matches( + "namespace N { template void f(T t); }" + "template void g() { N::f(T()); }", + unresolvedLookupExpr(canReferToDecl(namedDecl(hasName("::N::f")))))); + EXPECT_TRUE(notMatches( + "namespace N { template void f(T t); }" + "template void g() { using N::f; f(T()); }", + unresolvedLookupExpr(canReferToDecl(namedDecl(hasName("::N::f")))))); +} + TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) { TypeMatcher ClassX = hasDeclaration(recordDecl(hasName("X"))); EXPECT_TRUE( @@ -2072,5 +2087,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