diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -5033,6 +5033,18 @@ +
Matches if both matchers match with opposite sides of the binary operator. + +Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1), + integerLiteral(equals(2))) + 1 + 2 // Match + 2 + 1 // Match + 1 + 1 // No match + 2 + 2 // No match +
Matches the right hand side of binary operator expressions. 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 @@ -4869,6 +4869,23 @@ return anyOf(hasLHS(InnerMatcher), hasRHS(InnerMatcher)); } +/// Matches if both matchers match with opposite sides of the binary operator. +/// +/// Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1), +/// integerLiteral(equals(2))) +/// \code +/// 1 + 2 // Match +/// 2 + 1 // Match +/// 1 + 1 // No match +/// 2 + 2 // No match +/// \endcode +inline internal::Matcher+hasOperands(const internal::Matcher &Matcher1, + const internal::Matcher &Matcher2) { + return anyOf(allOf(hasLHS(Matcher1), hasRHS(Matcher2)), + allOf(hasLHS(Matcher2), hasRHS(Matcher1))); +} + /// Matches if the operand of a unary operator matches. /// /// Example matches true (matcher = hasUnaryOperand( diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -294,6 +294,7 @@ REGISTER_MATCHER(hasName); REGISTER_MATCHER(hasNullSelector); REGISTER_MATCHER(hasObjectExpression); + REGISTER_MATCHER(hasOperands); REGISTER_MATCHER(hasOperatorName); REGISTER_MATCHER(hasOverloadedOperatorName); REGISTER_MATCHER(hasParameter); diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -1160,6 +1160,17 @@ EXPECT_TRUE(notMatches("void x() { true || true; }", HasOperand)); } +TEST(MatchBinaryOperator, HasOperands) { + StatementMatcher HasOperands = binaryOperator( + hasOperands(integerLiteral(equals(1)), integerLiteral(equals(2)))); + EXPECT_TRUE(matches("void x() { 1 + 2; }", HasOperands)); + EXPECT_TRUE(matches("void x() { 2 + 1; }", HasOperands)); + EXPECT_TRUE(notMatches("void x() { 1 + 1; }", HasOperands)); + EXPECT_TRUE(notMatches("void x() { 2 + 2; }", HasOperands)); + EXPECT_TRUE(notMatches("void x() { 0 + 0; }", HasOperands)); + EXPECT_TRUE(notMatches("void x() { 0 + 1; }", HasOperands)); +} + TEST(Matcher, BinaryOperatorTypes) { // Integration test that verifies the AST provides all binary operators in // a way we expect.