</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXDependentScopeMemberExpr.html">CXXDependentScopeMemberExpr</a>></td><td class="name" onclick="toggle('hasMemberName0')"><a name="hasMemberName0Anchor">hasMemberName</a></td><td>std::string N</td></tr>
+<tr><td colspan="4" class="doc" id="hasMemberName0"><pre>Matches template-dependent, but known, member names
+
+In template declarations, dependent members are not resolved and so can
+not be matched to particular named declarations.
+
+This matcher allows to match on the known name of members.
+
+Given
+ template <typename T>
+ struct S {
+ void mem();
+ };
+ template <typename T>
+ void x() {
+ S<T> s;
+ s.mem();
+ }
+cxxDependentScopeMemberExpr(hasMemberName("mem")) matches `s.mem()`
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXDependentScopeMemberExpr.html">CXXDependentScopeMemberExpr</a>></td><td class="name" onclick="toggle('isArrow2')"><a name="isArrow2Anchor">isArrow</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isArrow2"><pre>Matches member expressions that are called with '->' as opposed
to '.'.
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXDependentScopeMemberExpr.html">CXXDependentScopeMemberExpr</a>></td><td class="name" onclick="toggle('memberHasSameNameAsBoundNode0')"><a name="memberHasSameNameAsBoundNode0Anchor">memberHasSameNameAsBoundNode</a></td><td>std::string BindingID</td></tr>
+<tr><td colspan="4" class="doc" id="memberHasSameNameAsBoundNode0"><pre>Matches template-dependent, but known, member names against an already-bound
+node
+
+In template declarations, dependent members are not resolved and so can
+not be matched to particular named declarations.
+
+This matcher allows to match on the name of already-bound VarDecl, FieldDecl
+and CXXMethodDecl nodes.
+
+Given
+ template <typename T>
+ struct S {
+ void mem();
+ };
+ template <typename T>
+ void x() {
+ S<T> s;
+ s.mem();
+ }
+The matcher
+@code
+cxxDependentScopeMemberExpr(
+ hasObjectExpression(declRefExpr(hasType(templateSpecializationType(
+ hasDeclaration(classTemplateDecl(has(cxxRecordDecl(has(
+ cxxMethodDecl(hasName("mem")).bind("templMem")
+ )))))
+ )))),
+ memberHasSameNameAsBoundNode("templMem")
+ )
+@endcode
+first matches and binds the @c mem member of the @c S template, then
+compares its name to the usage in @c s.mem() in the @c x function template
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('isConst0')"><a name="isConst0Anchor">isConst</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isConst0"><pre>Matches if the given method declaration is const.
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXUnresolvedConstructExpr.html">CXXUnresolvedConstructExpr</a>></td><td class="name" onclick="toggle('argumentCountIs2')"><a name="argumentCountIs2Anchor">argumentCountIs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="argumentCountIs2"><pre>Checks that a call expression or a constructor call expression has
+a specific number of arguments (including absent default arguments).
+
+Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+ void f(int x, int y);
+ f(0, 0);
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('argumentCountIs0')"><a name="argumentCountIs0Anchor">argumentCountIs</a></td><td>unsigned N</td></tr>
<tr><td colspan="4" class="doc" id="argumentCountIs0"><pre>Checks that a call expression or a constructor call expression has
a specific number of arguments (including absent default arguments).
</pre></td></tr>
-<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('argumentCountIs2')"><a name="argumentCountIs2Anchor">argumentCountIs</a></td><td>unsigned N</td></tr>
-<tr><td colspan="4" class="doc" id="argumentCountIs2"><pre>Checks that a call expression or a constructor call expression has
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('argumentCountIs3')"><a name="argumentCountIs3Anchor">argumentCountIs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="argumentCountIs3"><pre>Checks that a call expression or a constructor call expression has
a specific number of arguments (including absent default arguments).
Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXUnresolvedConstructExpr.html">CXXUnresolvedConstructExpr</a>></td><td class="name" onclick="toggle('hasArgument2')"><a name="hasArgument2Anchor">hasArgument</a></td><td>unsigned N, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasArgument2"><pre>Matches the n'th argument of a call expression or a constructor
+call expression.
+
+Example matches y in x(y)
+ (matcher = callExpr(hasArgument(0, declRefExpr())))
+ void x(int) { int y; x(y); }
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('callee1')"><a name="callee1Anchor">callee</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="callee1"><pre>Matches if the call expression's callee's declaration matches the
given matcher.
</pre></td></tr>
-<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasArgument2')"><a name="hasArgument2Anchor">hasArgument</a></td><td>unsigned N, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasArgument2"><pre>Matches the n'th argument of a call expression or a constructor
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasArgument3')"><a name="hasArgument3Anchor">hasArgument</a></td><td>unsigned N, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasArgument3"><pre>Matches the n'th argument of a call expression or a constructor
call expression.
Example matches y in x(y)
StringRef, internal::hasAnyOverloadedOperatorNameFunc>
hasAnyOverloadedOperatorName;
+/// Matches template-dependent, but known, member names.
+///
+/// In template declarations, dependent members are not resolved and so can
+/// not be matched to particular named declarations.
+///
+/// This matcher allows to match on the known name of members.
+///
+/// Given
+/// \code
+/// template <typename T>
+/// struct S {
+/// void mem();
+/// };
+/// template <typename T>
+/// void x() {
+/// S<T> s;
+/// s.mem();
+/// }
+/// \endcode
+/// \c cxxDependentScopeMemberExpr(hasMemberName("mem")) matches `s.mem()`
+AST_MATCHER_P(CXXDependentScopeMemberExpr, hasMemberName, std::string, N) {
+ return Node.getMember().getAsString() == N;
+}
+
+/// Matches template-dependent, but known, member names against an already-bound
+/// node
+///
+/// In template declarations, dependent members are not resolved and so can
+/// not be matched to particular named declarations.
+///
+/// This matcher allows to match on the name of already-bound VarDecl, FieldDecl
+/// and CXXMethodDecl nodes.
+///
+/// Given
+/// \code
+/// template <typename T>
+/// struct S {
+/// void mem();
+/// };
+/// template <typename T>
+/// void x() {
+/// S<T> s;
+/// s.mem();
+/// }
+/// \endcode
+/// The matcher
+/// @code
+/// \c cxxDependentScopeMemberExpr(
+/// hasObjectExpression(declRefExpr(hasType(templateSpecializationType(
+/// hasDeclaration(classTemplateDecl(has(cxxRecordDecl(has(
+/// cxxMethodDecl(hasName("mem")).bind("templMem")
+/// )))))
+/// )))),
+/// memberHasSameNameAsBoundNode("templMem")
+/// )
+/// @endcode
+/// first matches and binds the @c mem member of the @c S template, then
+/// compares its name to the usage in @c s.mem() in the @c x function template
+AST_MATCHER_P(CXXDependentScopeMemberExpr, memberHasSameNameAsBoundNode,
+ std::string, BindingID) {
+ auto MemberName = Node.getMember().getAsString();
+
+ return Builder->removeBindings(
+ [this, MemberName](const BoundNodesMap &Nodes) {
+ const auto &BN = Nodes.getNode(this->BindingID);
+ if (const auto *ND = BN.get<NamedDecl>()) {
+ if (!isa<FieldDecl, CXXMethodDecl, VarDecl>(ND))
+ return true;
+ return ND->getName() != MemberName;
+ }
+ return true;
+ });
+}
+
/// 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.
REGISTER_MATCHER(hasLocalStorage);
REGISTER_MATCHER(hasLoopInit);
REGISTER_MATCHER(hasLoopVariable);
+ REGISTER_MATCHER(hasMemberName);
REGISTER_MATCHER(hasMethod);
REGISTER_MATCHER(hasName);
REGISTER_MATCHER(hasNullSelector);
REGISTER_MATCHER(materializeTemporaryExpr);
REGISTER_MATCHER(member);
REGISTER_MATCHER(memberExpr);
+ REGISTER_MATCHER(memberHasSameNameAsBoundNode);
REGISTER_MATCHER(memberPointerType);
REGISTER_MATCHER(namedDecl);
REGISTER_MATCHER(namesType);
Constructor1Arg));
}
+TEST(ASTMatchersTest, NamesMember_CXXDependentScopeMemberExpr) {
+
+ // Member functions:
+ {
+ auto Code = "template <typename T> struct S{ void mem(); }; template "
+ "<typename T> void x() { S<T> s; s.mem(); }";
+
+ EXPECT_TRUE(matches(
+ Code,
+ cxxDependentScopeMemberExpr(
+ hasObjectExpression(declRefExpr(hasType(templateSpecializationType(
+ hasDeclaration(classTemplateDecl(has(cxxRecordDecl(
+ has(cxxMethodDecl(hasName("mem")).bind("templMem")))))))))),
+ memberHasSameNameAsBoundNode("templMem"))));
+
+ EXPECT_TRUE(
+ matches(Code, cxxDependentScopeMemberExpr(hasMemberName("mem"))));
+ }
+
+ // Member variables:
+ {
+ auto Code = "template <typename T> struct S{ int mem; }; template "
+ "<typename T> void x() { S<T> s; s.mem; }";
+
+ EXPECT_TRUE(
+ matches(Code, cxxDependentScopeMemberExpr(hasMemberName("mem"))));
+
+ EXPECT_TRUE(matches(
+ Code,
+ cxxDependentScopeMemberExpr(
+ hasObjectExpression(declRefExpr(hasType(templateSpecializationType(
+ hasDeclaration(classTemplateDecl(has(cxxRecordDecl(
+ has(fieldDecl(hasName("mem")).bind("templMem")))))))))),
+ memberHasSameNameAsBoundNode("templMem"))));
+ }
+
+ // static member variables:
+ {
+ auto Code = "template <typename T> struct S{ static int mem; }; template "
+ "<typename T> void x() { S<T> s; s.mem; }";
+
+ EXPECT_TRUE(
+ matches(Code, cxxDependentScopeMemberExpr(hasMemberName("mem"))));
+
+ EXPECT_TRUE(matches(
+ Code,
+ cxxDependentScopeMemberExpr(
+ hasObjectExpression(declRefExpr(hasType(templateSpecializationType(
+ hasDeclaration(classTemplateDecl(has(cxxRecordDecl(
+ has(varDecl(hasName("mem")).bind("templMem")))))))))),
+ memberHasSameNameAsBoundNode("templMem"))));
+ }
+ {
+ auto Code = R"cpp(
+template <typename T>
+struct S {
+ bool operator==(int) const { return true; }
+};
+
+template <typename T>
+void func(T t) {
+ S<T> s;
+ s.operator==(1);
+}
+)cpp";
+
+ EXPECT_TRUE(matches(
+ Code, cxxDependentScopeMemberExpr(hasMemberName("operator=="))));
+ }
+
+ // other named decl:
+ {
+ auto Code = "template <typename T> struct S{ static int mem; }; struct "
+ "mem{}; template "
+ "<typename T> void x() { S<T> s; s.mem; }";
+
+ EXPECT_TRUE(matches(
+ Code,
+ translationUnitDecl(has(cxxRecordDecl(hasName("mem"))),
+ hasDescendant(cxxDependentScopeMemberExpr()))));
+
+ EXPECT_FALSE(matches(
+ Code,
+ translationUnitDecl(has(cxxRecordDecl(hasName("mem")).bind("templMem")),
+ hasDescendant(cxxDependentScopeMemberExpr(
+ memberHasSameNameAsBoundNode("templMem"))))));
+ }
+}
+
TEST(ASTMatchersTest, ArgumentCountIs_CXXUnresolvedConstructExpr) {
const auto *Code =
"template <typename T> struct S{}; template <typename T> void "