diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -1206,6 +1206,7 @@ Example matches a || b !(a || b) +See also the binaryOperation() matcher for more-general matching. @@ -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. @@ -8100,6 +8103,48 @@ +Matcher<Stmt>binaryOperationMatcher<*>, ..., Matcher<*> +
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();
+  }
+
+ + Matcher<Stmt>forFunctionMatcher<FunctionDecl> InnerMatcher
Matches declaration of the function the statement belongs to
 
diff --git a/clang/docs/tools/dump_ast_matchers.py b/clang/docs/tools/dump_ast_matchers.py
--- a/clang/docs/tools/dump_ast_matchers.py
+++ b/clang/docs/tools/dump_ast_matchers.py
@@ -126,6 +126,9 @@
     args = "nodeMatcherFunction..."
     docs_result_type = "unspecified"
 
+  if name == 'binaryOperation':
+    args = 'Matcher<*>, ..., Matcher<*>'
+
   matcher_html = TD_TEMPLATE % {
     'result': docs_result_type,
     'name': name,
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/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
     cxxOperatorCallExpr;
 
@@ -2395,6 +2397,7 @@
 /// \code
 ///   !(a || b)
 /// \endcode
+/// See also the binaryOperation() matcher for more-general matching.
 extern const internal::VariadicDynCastAllOfMatcher
     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
+///   void templ()
+///   {
+///      1 != 2;
+///      T() != S();
+///   }
+/// \endcode
+template 
+internal::BindableMatcher
+binaryOperation(InnerMatcherType &&... Matchers) {
+  return mapAnyOf(binaryOperator, cxxOperatorCallExpr).with(Matchers...);
+}
+
 /// Matches unary expressions that have a specific type of argument.
 ///
 /// Given
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/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
+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
 {