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)),
const auto SymRight = matchSymbolicExpr("rhs");
// Match expressions like: x <op> 0xFF == 0xF00.
- Finder->addMatcher(binaryOperator(isComparisonOperator(),
+ Finder->addMatcher(binaryOperator(matchers::isComparisonOperator(),
hasEitherOperand(BinOpCstLeft),
hasEitherOperand(CstRight))
.bind("binop-const-compare-to-const"),
// Match expressions like: x <op> 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 <op> 10 == x <op> 12.
- Finder->addMatcher(binaryOperator(isComparisonOperator(),
+ Finder->addMatcher(binaryOperator(matchers::isComparisonOperator(),
hasLHS(BinOpCstLeft), hasRHS(BinOpCstRight),
// Already reported as redundant.
unless(operandsAreEquivalent()))
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; }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>></td><td class="name" onclick="toggle('isComparisonOperator0')"><a name="isComparisonOperator0Anchor">isComparisonOperator</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isComparisonOperator0"><pre>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; }
</pre></td></tr>
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; }
+</pre></td></tr>
+
+
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>></td><td class="name" onclick="toggle('isComparisonOperator1')"><a name="isComparisonOperator1Anchor">isComparisonOperator</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isComparisonOperator1"><pre>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; }
</pre></td></tr>
}
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;
/// (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,
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()))
REGISTER_MATCHER(isClass);
REGISTER_MATCHER(isClassMessage);
REGISTER_MATCHER(isClassMethod);
+ REGISTER_MATCHER(isComparisonOperator);
REGISTER_MATCHER(isConst);
REGISTER_MATCHER(isConstQualified);
REGISTER_MATCHER(isConstexpr);
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};",