Skip to content

Commit

Permalink
[ASTMatchers][NFC] Update comments on assorted CXXMemberCallExpr ma…
Browse files Browse the repository at this point in the history
…tchers.

Specifically:

* fixes the comments on `hasObjectExpression`,
* clarifies comments on `thisPointerType` and `on`,
* adds comments to `onImplicitObjectArgument`.

It also updates associated reference docs (using the doc tool).

Reviewers: alexfh, steveire, aaron.ballman

Differential Revision: https://reviews.llvm.org/D56849

llvm-svn: 353532
  • Loading branch information
ymand committed Feb 8, 2019
1 parent 30b7d09 commit 8a43680
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 47 deletions.
111 changes: 79 additions & 32 deletions clang/docs/LibASTMatchersReference.html
Original file line number Diff line number Diff line change
Expand Up @@ -4810,16 +4810,20 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>


<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXDependentScopeMemberExpr.html">CXXDependentScopeMemberExpr</a>&gt;</td><td class="name" onclick="toggle('hasObjectExpression2')"><a name="hasObjectExpression2Anchor">hasObjectExpression</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasObjectExpression2"><pre>Matches a member expression where the object expression is
matched by a given matcher.
<tr><td colspan="4" class="doc" id="hasObjectExpression2"><pre>Matches a member expression where the object expression is matched by a
given matcher. Implicit object expressions are included; that is, it matches
use of implicit `this`.

Given
struct X { int m; };
void f(X x) { x.m; m; }
memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X")))))))
matches "x.m" and "m"
with hasObjectExpression(...)
matching "x" and the implicit object expression of "m" which has type X*.
struct X {
int m;
int f(X x) { x.m; return m; }
};
memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X")))))
matches `x.m`, but not `m`; however,
memberExpr(hasObjectExpression(hasType(pointsTo(
cxxRecordDecl(hasName("X"))))))
matches `m` (aka. `this-&gt;m`), but not `x.m`.
</pre></td></tr>


Expand Down Expand Up @@ -4857,16 +4861,39 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>


<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>&gt;</td><td class="name" onclick="toggle('onImplicitObjectArgument0')"><a name="onImplicitObjectArgument0Anchor">onImplicitObjectArgument</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="onImplicitObjectArgument0"><pre></pre></td></tr>
<tr><td colspan="4" class="doc" id="onImplicitObjectArgument0"><pre>Matches on the implicit object argument of a member call expression. Unlike
`on`, matches the argument directly without stripping away anything.

Given
class Y { public: void m(); };
Y g();
class X : public Y { void g(); };
void z(Y y, X x) { y.m(); x.m(); x.g(); (g()).m(); }
cxxMemberCallExpr(onImplicitObjectArgument(hasType(
cxxRecordDecl(hasName("Y")))))
matches `y.m()`, `x.m()` and (g()).m(), but not `x.g()`.
cxxMemberCallExpr(on(callExpr()))
does not match `(g()).m()`, because the parens are not ignored.

FIXME: Overload to allow directly matching types?
</pre></td></tr>


<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>&gt;</td><td class="name" onclick="toggle('on0')"><a name="on0Anchor">on</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="on0"><pre>Matches on the implicit object argument of a member call expression.
<tr><td colspan="4" class="doc" id="on0"><pre>Matches on the implicit object argument of a member call expression, after
stripping off any parentheses or implicit casts.

Example matches y.x()
(matcher = cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("Y"))))))
class Y { public: void x(); };
void z() { Y y; y.x(); }
Given
class Y { public: void m(); };
Y g();
class X : public Y {};
void z(Y y, X x) { y.m(); (g()).m(); x.m(); }
cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("Y")))))
matches `y.m()` and `(g()).m()`.
cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("X")))))
matches `x.m()`.
cxxMemberCallExpr(on(callExpr()))
matches `(g()).m()`.

FIXME: Overload to allow directly matching types?
</pre></td></tr>
Expand All @@ -4878,8 +4905,20 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>


<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>&gt;</td><td class="name" onclick="toggle('thisPointerType0')"><a name="thisPointerType0Anchor">thisPointerType</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="thisPointerType0"><pre>Matches if the expression's type either matches the specified
matcher, or is a pointer to a type that matches the InnerMatcher.
<tr><td colspan="4" class="doc" id="thisPointerType0"><pre>Matches if the type of the expression's implicit object argument either
matches the InnerMatcher, or is a pointer to a type that matches the
InnerMatcher.

Given
class Y { public: void m(); };
class X : public Y { void g(); };
void z() { Y y; y.m(); Y *p; p-&gt;m(); X x; x.m(); x.g(); }
cxxMemberCallExpr(thisPointerType(hasDeclaration(
cxxRecordDecl(hasName("Y")))))
matches `y.m()`, `p-&gt;m()` and `x.m()`.
cxxMemberCallExpr(thisPointerType(hasDeclaration(
cxxRecordDecl(hasName("X")))))
matches `x.g()`.
</pre></td></tr>


Expand Down Expand Up @@ -5984,16 +6023,20 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>


<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;</td><td class="name" onclick="toggle('hasObjectExpression0')"><a name="hasObjectExpression0Anchor">hasObjectExpression</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasObjectExpression0"><pre>Matches a member expression where the object expression is
matched by a given matcher.
<tr><td colspan="4" class="doc" id="hasObjectExpression0"><pre>Matches a member expression where the object expression is matched by a
given matcher. Implicit object expressions are included; that is, it matches
use of implicit `this`.

Given
struct X { int m; };
void f(X x) { x.m; m; }
memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X")))))))
matches "x.m" and "m"
with hasObjectExpression(...)
matching "x" and the implicit object expression of "m" which has type X*.
struct X {
int m;
int f(X x) { x.m; return m; }
};
memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X")))))
matches `x.m`, but not `m`; however,
memberExpr(hasObjectExpression(hasType(pointsTo(
cxxRecordDecl(hasName("X"))))))
matches `m` (aka. `this-&gt;m`), but not `x.m`.
</pre></td></tr>


Expand Down Expand Up @@ -6805,16 +6848,20 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>


<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1UnresolvedMemberExpr.html">UnresolvedMemberExpr</a>&gt;</td><td class="name" onclick="toggle('hasObjectExpression1')"><a name="hasObjectExpression1Anchor">hasObjectExpression</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasObjectExpression1"><pre>Matches a member expression where the object expression is
matched by a given matcher.
<tr><td colspan="4" class="doc" id="hasObjectExpression1"><pre>Matches a member expression where the object expression is matched by a
given matcher. Implicit object expressions are included; that is, it matches
use of implicit `this`.

Given
struct X { int m; };
void f(X x) { x.m; m; }
memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X")))))))
matches "x.m" and "m"
with hasObjectExpression(...)
matching "x" and the implicit object expression of "m" which has type X*.
struct X {
int m;
int f(X x) { x.m; return m; }
};
memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X")))))
matches `x.m`, but not `m`; however,
memberExpr(hasObjectExpression(hasType(pointsTo(
cxxRecordDecl(hasName("X"))))))
matches `m` (aka. `this-&gt;m`), but not `x.m`.
</pre></td></tr>


Expand Down
73 changes: 58 additions & 15 deletions clang/include/clang/ASTMatchers/ASTMatchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -2886,14 +2886,22 @@ AST_MATCHER_P(NamedDecl, hasUnderlyingDecl, internal::Matcher<NamedDecl>,
InnerMatcher.matches(*UnderlyingDecl, Finder, Builder);
}

/// Matches on the implicit object argument of a member call expression.
/// Matches on the implicit object argument of a member call expression, after
/// stripping off any parentheses or implicit casts.
///
/// Example matches y.x()
/// (matcher = cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("Y"))))))
/// Given
/// \code
/// class Y { public: void x(); };
/// void z() { Y y; y.x(); }
/// class Y { public: void m(); };
/// Y g();
/// class X : public Y {};
/// void z(Y y, X x) { y.m(); (g()).m(); x.m(); }
/// \endcode
/// cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("Y")))))
/// matches `y.m()` and `(g()).m()`.
/// cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("X")))))
/// matches `x.m()`.
/// cxxMemberCallExpr(on(callExpr()))
/// matches `(g()).m()`.
///
/// FIXME: Overload to allow directly matching types?
AST_MATCHER_P(CXXMemberCallExpr, on, internal::Matcher<Expr>,
Expand Down Expand Up @@ -3253,15 +3261,46 @@ AST_MATCHER_P_OVERLOAD(QualType, references, internal::Matcher<Decl>,
.matches(Node, Finder, Builder);
}

/// Matches on the implicit object argument of a member call expression. Unlike
/// `on`, matches the argument directly without stripping away anything.
///
/// Given
/// \code
/// class Y { public: void m(); };
/// Y g();
/// class X : public Y { void g(); };
/// void z(Y y, X x) { y.m(); x.m(); x.g(); (g()).m(); }
/// \endcode
/// cxxMemberCallExpr(onImplicitObjectArgument(hasType(
/// cxxRecordDecl(hasName("Y")))))
/// matches `y.m()`, `x.m()` and (g()).m(), but not `x.g()`.
/// cxxMemberCallExpr(on(callExpr()))
/// does not match `(g()).m()`, because the parens are not ignored.
///
/// FIXME: Overload to allow directly matching types?
AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument,
internal::Matcher<Expr>, InnerMatcher) {
const Expr *ExprNode = Node.getImplicitObjectArgument();
return (ExprNode != nullptr &&
InnerMatcher.matches(*ExprNode, Finder, Builder));
}

/// Matches if the expression's type either matches the specified
/// matcher, or is a pointer to a type that matches the InnerMatcher.
/// Matches if the type of the expression's implicit object argument either
/// matches the InnerMatcher, or is a pointer to a type that matches the
/// InnerMatcher.
///
/// Given
/// \code
/// class Y { public: void m(); };
/// class X : public Y { void g(); };
/// void z() { Y y; y.m(); Y *p; p->m(); X x; x.m(); x.g(); }
/// \endcode
/// cxxMemberCallExpr(thisPointerType(hasDeclaration(
/// cxxRecordDecl(hasName("Y")))))
/// matches `y.m()`, `p->m()` and `x.m()`.
/// cxxMemberCallExpr(thisPointerType(hasDeclaration(
/// cxxRecordDecl(hasName("X")))))
/// matches `x.g()`.
AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType,
internal::Matcher<QualType>, InnerMatcher, 0) {
return onImplicitObjectArgument(
Expand Down Expand Up @@ -4963,18 +5002,22 @@ AST_MATCHER_P(MemberExpr, member,
return InnerMatcher.matches(*Node.getMemberDecl(), Finder, Builder);
}

/// Matches a member expression where the object expression is
/// matched by a given matcher.
/// Matches a member expression where the object expression is matched by a
/// given matcher. Implicit object expressions are included; that is, it matches
/// use of implicit `this`.
///
/// Given
/// \code
/// struct X { int m; };
/// void f(X x) { x.m; m; }
/// struct X {
/// int m;
/// int f(X x) { x.m; return m; }
/// };
/// \endcode
/// memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X")))))))
/// matches "x.m" and "m"
/// with hasObjectExpression(...)
/// matching "x" and the implicit object expression of "m" which has type X*.
/// memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X")))))
/// matches `x.m`, but not `m`; however,
/// memberExpr(hasObjectExpression(hasType(pointsTo(
// cxxRecordDecl(hasName("X"))))))
/// matches `m` (aka. `this->m`), but not `x.m`.
AST_POLYMORPHIC_MATCHER_P(
hasObjectExpression,
AST_POLYMORPHIC_SUPPORTED_TYPES(MemberExpr, UnresolvedMemberExpr,
Expand Down

0 comments on commit 8a43680

Please sign in to comment.