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 cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits