[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
This commit is contained in:
Nathan James 2020-03-07 09:51:43 +00:00
parent 073dbaae39
commit fc3c80c386
6 changed files with 86 additions and 7 deletions

View File

@ -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 <op> 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 <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()))

View File

@ -2157,7 +2157,21 @@ Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
Example 2: matches s1 = s2
(matcher = cxxOperatorCallExpr(isAssignmentOperator()))
struct S { S&amp; operator=(const S&amp;); };
void x() { S s1, s2; s1 = s2; })
void x() { S s1, s2; s1 = s2; }
</pre></td></tr>
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>&gt;</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 &lt; s2
(matcher = cxxOperatorCallExpr(isComparisonOperator()))
struct S { bool operator&lt;(const S&amp; other); };
void x(S s1, S s2) { bool b1 = s1 &lt; s2; }
</pre></td></tr>
@ -2616,7 +2630,21 @@ Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
Example 2: matches s1 = s2
(matcher = cxxOperatorCallExpr(isAssignmentOperator()))
struct S { S&amp; operator=(const S&amp;); };
void x() { S s1, s2; s1 = s2; })
void x() { S s1, s2; s1 = s2; }
</pre></td></tr>
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;</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 &lt; s2
(matcher = cxxOperatorCallExpr(isComparisonOperator()))
struct S { bool operator&lt;(const S&amp; other); };
void x(S s1, S s2) { bool b1 = s1 &lt; s2; }
</pre></td></tr>

View File

@ -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;

View File

@ -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()))

View File

@ -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);

View File

@ -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};",