diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index fc55788801325..18f9e7d6c0ea0 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -3449,6 +3449,19 @@
Matches the dependent name of a DependentScopeDeclRefExpr.
+
+Matches the dependent name of a DependentScopeDeclRefExpr
+
+Given:
+
+ template <class T< class X : T { void f() { T::v; } };
+
+dependentScopeDeclRefExpr(hasDependentName("v")) matches `T::v`
+Matches template-dependent, but known, member names against an already-bound
node
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 5e75fc447636e..f2b27893b7a9d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1116,6 +1116,8 @@ AST Matchers
- Add ``dependentTemplateSpecializationType`` matcher to match a dependent template specialization type.
+- Add ``hasDependentName`` matcher to match the dependent name of a DependentScopeDeclRefExpr.
+
clang-format
------------
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index dd0fedb2cda2d..f10135d7a901f 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -3257,6 +3257,17 @@ AST_MATCHER_P(CXXDependentScopeMemberExpr, memberHasSameNameAsBoundNode,
});
}
+/// Matches the dependent name of a DependentScopeDeclRefExpr
+///
+/// Given:
+/// \code
+/// template class X : T { void f() { T::v; } };
+/// \endcode
+/// \c dependentScopeDeclRefExpr(hasDependentName("v")) matches `T::v`
+AST_MATCHER_P(DependentScopeDeclRefExpr, hasDependentName, std::string, N) {
+ return Node.getDeclName().getAsString() == N;
+}
+
/// Matches C++ classes that are directly or indirectly derived from a class
/// matching \c Base, or Objective-C classes that directly or indirectly
/// subclass a class matching \c Base.
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 97e6bbc093fe4..336d3a14f7955 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -314,6 +314,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasDeducedType);
REGISTER_MATCHER(hasDefaultArgument);
REGISTER_MATCHER(hasDefinition);
+ REGISTER_MATCHER(hasDependentName);
REGISTER_MATCHER(hasDescendant);
REGISTER_MATCHER(hasDestinationType);
REGISTER_MATCHER(hasDirectBase);
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index 056b7c7b571ef..f3d953454173c 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2235,6 +2235,24 @@ TEST_P(ASTMatchersTest, ArgumentCountIs_CXXConstructExpr) {
Constructor1Arg));
}
+TEST_P(ASTMatchersTest, HasDependentName_DependentScopeDeclRefExpr) {
+ if (!GetParam().isCXX() || GetParam().hasDelayedTemplateParsing()) {
+ // FIXME: Fix this test to work with delayed template parsing.
+ return;
+ }
+
+ EXPECT_TRUE(matches("template class X : T { void f() { T::v; } };",
+ dependentScopeDeclRefExpr(hasDependentName("v"))));
+
+ EXPECT_TRUE(matches("template struct S { static T Foo; };"
+ "template void x() { (void)S::Foo; }",
+ dependentScopeDeclRefExpr(hasDependentName("Foo"))));
+
+ EXPECT_TRUE(matches("template struct S { static T foo(); };"
+ "template void x() { S::foo(); }",
+ dependentScopeDeclRefExpr(hasDependentName("foo"))));
+}
+
TEST(ASTMatchersTest, NamesMember_CXXDependentScopeMemberExpr) {
// Member functions: