steveire created this revision.
steveire added a reviewer: aaron.ballman.
steveire requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
This is a simple utility which allows matching on binaryOperator and
cxxOperatorCallExpr. It can also be extended to support
cxxRewrittenBinaryOperator.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D94129
Files:
clang/docs/LibASTMatchersReference.html
clang/docs/tools/dump_ast_matchers.py
clang/include/clang/ASTMatchers/ASTMatchers.h
clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===================================================================
--- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -478,6 +478,10 @@
return;
}
+ if (GetParam().hasDelayedTemplateParsing()) {
+ return;
+ }
+
StringRef Code = R"cpp(
void F() {
if (true) {}
@@ -549,6 +553,15 @@
if (s1 != s2)
return;
}
+
+template<typename T>
+void templ()
+{
+ T s1;
+ T s2;
+ if (s1 != s2)
+ return;
+}
)cpp";
EXPECT_TRUE(matches(
@@ -625,6 +638,30 @@
.with(hasAnyOperatorName("==", "!="),
forFunction(functionDecl(hasName("opCall")))))));
+ EXPECT_TRUE(matches(
+ Code, traverse(TK_IgnoreUnlessSpelledInSource,
+ binaryOperation(
+ hasOperatorName("!="),
+ forFunction(functionDecl(hasName("binop"))),
+ hasLHS(declRefExpr(to(varDecl(hasName("s1"))))),
+ hasRHS(declRefExpr(to(varDecl(hasName("s2")))))))));
+
+ EXPECT_TRUE(matches(
+ Code, traverse(TK_IgnoreUnlessSpelledInSource,
+ binaryOperation(
+ hasOperatorName("!="),
+ forFunction(functionDecl(hasName("opCall"))),
+ hasLHS(declRefExpr(to(varDecl(hasName("s1"))))),
+ hasRHS(declRefExpr(to(varDecl(hasName("s2")))))))));
+
+ EXPECT_TRUE(matches(
+ Code, traverse(TK_IgnoreUnlessSpelledInSource,
+ binaryOperation(
+ hasOperatorName("!="),
+ forFunction(functionDecl(hasName("templ"))),
+ hasLHS(declRefExpr(to(varDecl(hasName("s1"))))),
+ hasRHS(declRefExpr(to(varDecl(hasName("s2")))))))));
+
Code = R"cpp(
struct HasOpBang
{
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -1973,6 +1973,8 @@
/// ostream &o; int b = 1, c = 1;
/// o << b << c;
/// \endcode
+/// See also the binaryOperation() matcher for more-general matching of binary
+/// uses of this AST node.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXOperatorCallExpr>
cxxOperatorCallExpr;
@@ -2395,6 +2397,7 @@
/// \code
/// !(a || b)
/// \endcode
+/// See also the binaryOperation() matcher for more-general matching.
extern const internal::VariadicDynCastAllOfMatcher<Stmt, BinaryOperator>
binaryOperator;
@@ -2733,6 +2736,56 @@
NodeMatcher...);
}
+/// Matches nodes which can be used with binary operators
+///
+/// The code
+/// \code
+/// var1 != var2;
+/// \endcode
+/// might be represented in the clang AST as a binaryOperator or a
+/// cxxOperatorCallExpr, depending on
+///
+/// * whether the types of var1 and var2 are fundamental (binaryOperator) or at
+/// least one is a class type (cxxOperatorCallExpr)
+/// * whether the code appears in a template declaration, if at least one of the
+/// vars is a dependent-type (binaryOperator)
+///
+/// This matcher elides details in places where the matchers for the nodes are
+/// compatible.
+///
+/// Given
+/// \code
+/// binaryOperation(
+/// hasOperatorName("!="),
+/// hasLHS(expr().bind("lhs")),
+/// hasRHS(expr().bind("rhs"))
+/// )
+/// \endcode
+/// matches each use of "!=" in:
+/// \code
+/// struct S{
+/// bool operator!=(const S&) const;
+/// };
+///
+/// void foo()
+/// {
+/// 1 != 2;
+/// S() != S();
+/// }
+///
+/// template<typename T>
+/// void templ()
+/// {
+/// 1 != 2;
+/// T() != S();
+/// }
+/// \endcode
+template <typename... InnerMatcherType>
+internal::BindableMatcher<Stmt>
+binaryOperation(InnerMatcherType &&... Matchers) {
+ return mapAnyOf(binaryOperator, cxxOperatorCallExpr).with(Matchers...);
+}
+
/// Matches unary expressions that have a specific type of argument.
///
/// Given
Index: clang/docs/tools/dump_ast_matchers.py
===================================================================
--- clang/docs/tools/dump_ast_matchers.py
+++ clang/docs/tools/dump_ast_matchers.py
@@ -126,6 +126,9 @@
args = "nodeMatcherFunction..."
docs_result_type = "<em>unspecified</em>"
+ if name == 'binaryOperation':
+ args = 'Matcher<*>, ..., Matcher<*>'
+
matcher_html = TD_TEMPLATE % {
'result': docs_result_type,
'name': name,
Index: clang/docs/LibASTMatchersReference.html
===================================================================
--- clang/docs/LibASTMatchersReference.html
+++ clang/docs/LibASTMatchersReference.html
@@ -1206,6 +1206,7 @@
Example matches a || b
!(a || b)
+See also the binaryOperation() matcher for more-general matching.
</pre></td></tr>
@@ -1505,6 +1506,8 @@
ostream &operator<< (ostream &out, int i) { };
ostream &o; int b = 1, c = 1;
o << b << c;
+See also the binaryOperation() matcher for more-general matching of binary
+uses of this AST node.
</pre></td></tr>
@@ -8100,6 +8103,48 @@
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('binaryOperation0')"><a name="binaryOperation0Anchor">binaryOperation</a></td><td>Matcher<*>, ..., Matcher<*></td></tr>
+<tr><td colspan="4" class="doc" id="binaryOperation0"><pre>Matches nodes which can be used with binary operators
+
+The code
+ var1 != var2;
+might be represented in the clang AST as a binaryOperator or a
+cxxOperatorCallExpr, depending on
+
+* whether the types of var1 and var2 are fundamental (binaryOperator) or at
+ least one is a class type (cxxOperatorCallExpr)
+* whether the code appears in a template declaration, if at least one of the
+ vars is a dependent-type (binaryOperator)
+
+This matcher elides details in places where the matchers for the nodes are
+compatible.
+
+Given
+ binaryOperation(
+ hasOperatorName("!="),
+ hasLHS(expr().bind("lhs")),
+ hasRHS(expr().bind("rhs"))
+ )
+matches each use of "!=" in:
+ struct S{
+ bool operator!=(const S&) const;
+ };
+
+ void foo()
+ {
+ 1 != 2;
+ S() != S();
+ }
+
+ template<typename T>
+ void templ()
+ {
+ 1 != 2;
+ T() != S();
+ }
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('forFunction0')"><a name="forFunction0Anchor">forFunction</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="forFunction0"><pre>Matches declaration of the function the statement belongs to
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits