From fc3c80c38643aff6c4744433ab485c7550ee77b9 Mon Sep 17 00:00:00 2001 From: Nathan James Date: Sat, 7 Mar 2020 09:51:43 +0000 Subject: [PATCH] [ASTMatchers] adds isComparisonOperator to BinaryOperator and CXXOperatorCallExpr Reviewers: aaron.ballman, gribozavr2 Reviewed By: aaron.ballman Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D75800 --- .../misc/RedundantExpressionCheck.cpp | 8 ++--- clang/docs/LibASTMatchersReference.html | 32 +++++++++++++++++-- clang/include/clang/AST/ExprCXX.h | 16 ++++++++++ clang/include/clang/ASTMatchers/ASTMatchers.h | 22 ++++++++++++- clang/lib/ASTMatchers/Dynamic/Registry.cpp | 1 + .../ASTMatchers/ASTMatchersNarrowingTest.cpp | 14 ++++++++ 6 files changed, 86 insertions(+), 7 deletions(-) diff --git a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp index 90fcf38f83b7..99214ccf2e79 100644 --- a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp @@ -567,7 +567,7 @@ matchRelationalIntegerConstantExpr(StringRef Id) { std::string OverloadId = (Id + "-overload").str(); const auto RelationalExpr = ignoringParenImpCasts(binaryOperator( - isComparisonOperator(), expr().bind(Id), + matchers::isComparisonOperator(), expr().bind(Id), anyOf(allOf(hasLHS(matchSymbolicExpr(Id)), hasRHS(matchIntegerConstantExpr(Id))), allOf(hasLHS(matchIntegerConstantExpr(Id)), @@ -943,7 +943,7 @@ void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) { const auto SymRight = matchSymbolicExpr("rhs"); // Match expressions like: x 0xFF == 0xF00. - Finder->addMatcher(binaryOperator(isComparisonOperator(), + Finder->addMatcher(binaryOperator(matchers::isComparisonOperator(), hasEitherOperand(BinOpCstLeft), hasEitherOperand(CstRight)) .bind("binop-const-compare-to-const"), @@ -951,14 +951,14 @@ void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) { // Match expressions like: x 0xFF == x. Finder->addMatcher( - binaryOperator(isComparisonOperator(), + binaryOperator(matchers::isComparisonOperator(), anyOf(allOf(hasLHS(BinOpCstLeft), hasRHS(SymRight)), allOf(hasLHS(SymRight), hasRHS(BinOpCstLeft)))) .bind("binop-const-compare-to-sym"), this); // Match expressions like: x 10 == x 12. - Finder->addMatcher(binaryOperator(isComparisonOperator(), + Finder->addMatcher(binaryOperator(matchers::isComparisonOperator(), hasLHS(BinOpCstLeft), hasRHS(BinOpCstRight), // Already reported as redundant. unless(operandsAreEquivalent())) diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index dca7aa5c2cf7..f0faed7f0f8f 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -2157,7 +2157,21 @@ Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator())) Example 2: matches s1 = s2 (matcher = cxxOperatorCallExpr(isAssignmentOperator())) struct S { S& operator=(const S&); }; - void x() { S s1, s2; s1 = s2; }) + void x() { S s1, s2; s1 = s2; } + + + +Matcher<BinaryOperator>isComparisonOperator +
Matches comparison operators.
+
+Example 1: matches a == b (matcher = binaryOperator(isComparisonOperator()))
+  if (a == b)
+    a += b;
+
+Example 2: matches s1 < s2
+           (matcher = cxxOperatorCallExpr(isComparisonOperator()))
+  struct S { bool operator<(const S& other); };
+  void x(S s1, S s2) { bool b1 = s1 < s2; }
 
@@ -2616,7 +2630,21 @@ Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator())) Example 2: matches s1 = s2 (matcher = cxxOperatorCallExpr(isAssignmentOperator())) struct S { S& operator=(const S&); }; - void x() { S s1, s2; s1 = s2; }) + void x() { S s1, s2; s1 = s2; } + + + +Matcher<CXXOperatorCallExpr>isComparisonOperator +
Matches comparison operators.
+
+Example 1: matches a == b (matcher = binaryOperator(isComparisonOperator()))
+  if (a == b)
+    a += b;
+
+Example 2: matches s1 < s2
+           (matcher = cxxOperatorCallExpr(isComparisonOperator()))
+  struct S { bool operator<(const S& other); };
+  void x(S s1, S s2) { bool b1 = s1 < s2; }
 
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index cea360d12e91..2bd68eec175a 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -118,6 +118,22 @@ public: } bool isAssignmentOp() const { return isAssignmentOp(getOperator()); } + static bool isComparisonOp(OverloadedOperatorKind Opc) { + switch (Opc) { + case OO_EqualEqual: + case OO_ExclaimEqual: + case OO_Greater: + case OO_GreaterEqual: + case OO_Less: + case OO_LessEqual: + case OO_Spaceship: + return true; + default: + return false; + } + } + bool isComparisonOp() const { return isComparisonOp(getOperator()); } + /// Is this written as an infix binary operator? bool isInfixBinaryOp() const; diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index da7e23052b28..31138e47750c 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -4783,7 +4783,7 @@ extern const internal::VariadicFunction< /// (matcher = cxxOperatorCallExpr(isAssignmentOperator())) /// \code /// struct S { S& operator=(const S&); }; -/// void x() { S s1, s2; s1 = s2; }) +/// void x() { S s1, s2; s1 = s2; } /// \endcode AST_POLYMORPHIC_MATCHER(isAssignmentOperator, AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, @@ -4791,6 +4791,26 @@ AST_POLYMORPHIC_MATCHER(isAssignmentOperator, return Node.isAssignmentOp(); } +/// Matches comparison operators. +/// +/// Example 1: matches a == b (matcher = binaryOperator(isComparisonOperator())) +/// \code +/// if (a == b) +/// a += b; +/// \endcode +/// +/// Example 2: matches s1 < s2 +/// (matcher = cxxOperatorCallExpr(isComparisonOperator())) +/// \code +/// struct S { bool operator<(const S& other); }; +/// void x(S s1, S s2) { bool b1 = s1 < s2; } +/// \endcode +AST_POLYMORPHIC_MATCHER(isComparisonOperator, + AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, + CXXOperatorCallExpr)) { + return Node.isComparisonOp(); +} + /// Matches the left hand side of binary operator expressions. /// /// Example matches a (matcher = binaryOperator(hasLHS())) diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 5452b408a817..fd2b6b253c53 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -358,6 +358,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(isClass); REGISTER_MATCHER(isClassMessage); REGISTER_MATCHER(isClassMethod); + REGISTER_MATCHER(isComparisonOperator); REGISTER_MATCHER(isConst); REGISTER_MATCHER(isConstQualified); REGISTER_MATCHER(isConstexpr); diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp index c3c770a7dffd..2816e216e8c4 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -2689,6 +2689,20 @@ TEST(IsAssignmentOperator, Basic) { notMatches("void x() { int a; if(a == 0) return; }", BinAsgmtOperator)); } +TEST(IsComparisonOperator, Basic) { + StatementMatcher BinCompOperator = binaryOperator(isComparisonOperator()); + StatementMatcher CXXCompOperator = + cxxOperatorCallExpr(isComparisonOperator()); + + EXPECT_TRUE(matches("void x() { int a; a == 1; }", BinCompOperator)); + EXPECT_TRUE(matches("void x() { int a; a > 2; }", BinCompOperator)); + EXPECT_TRUE(matches("struct S { bool operator==(const S&); };" + "void x() { S s1, s2; bool b1 = s1 == s2; }", + CXXCompOperator)); + EXPECT_TRUE( + notMatches("void x() { int a; if(a = 0) return; }", BinCompOperator)); +} + TEST(HasInit, Basic) { EXPECT_TRUE( matches("int x{0};",