[clang-tidy] Improve integer comparison by matching valid expressions outside implicitCastExpr (#134188)
Aims to fix #127471 Covered the edge case where an int expression is not necessarily directly wrapped around an 'ImplicitCastExpr' which seemed to be a requirement in 'use-integer-sign-comparison.cpp' check to trigger. **For instance**: ```cpp #include <vector> bool f() { std::vector<int> v; unsigned int i = 0; return i >= v.size(); } ```
This commit is contained in:
@@ -39,21 +39,28 @@ intCastExpression(bool IsSigned,
|
||||
// std::cmp_{} functions trigger a compile-time error if either LHS or RHS
|
||||
// is a non-integer type, char, enum or bool
|
||||
// (unsigned char/ signed char are Ok and can be used).
|
||||
auto IntTypeExpr = expr(hasType(hasCanonicalType(qualType(
|
||||
const auto HasIntegerType = hasType(hasCanonicalType(qualType(
|
||||
isInteger(), IsSigned ? isSignedInteger() : isUnsignedInteger(),
|
||||
unless(isActualChar()), unless(booleanType()), unless(enumType())))));
|
||||
unless(isActualChar()), unless(booleanType()), unless(enumType()))));
|
||||
|
||||
const auto IntTypeExpr = expr(HasIntegerType);
|
||||
|
||||
const auto ImplicitCastExpr =
|
||||
CastBindName.empty() ? implicitCastExpr(hasSourceExpression(IntTypeExpr))
|
||||
: implicitCastExpr(hasSourceExpression(IntTypeExpr))
|
||||
.bind(CastBindName);
|
||||
|
||||
const auto CStyleCastExpr = cStyleCastExpr(has(ImplicitCastExpr));
|
||||
const auto StaticCastExpr = cxxStaticCastExpr(has(ImplicitCastExpr));
|
||||
const auto FunctionalCastExpr = cxxFunctionalCastExpr(has(ImplicitCastExpr));
|
||||
const auto ExplicitCastExpr =
|
||||
anyOf(explicitCastExpr(has(ImplicitCastExpr)),
|
||||
ignoringImpCasts(explicitCastExpr(has(ImplicitCastExpr))));
|
||||
|
||||
return expr(anyOf(ImplicitCastExpr, CStyleCastExpr, StaticCastExpr,
|
||||
FunctionalCastExpr));
|
||||
// Match function calls or variable references not directly wrapped by an
|
||||
// implicit cast
|
||||
const auto CallIntExpr = CastBindName.empty()
|
||||
? callExpr(HasIntegerType)
|
||||
: callExpr(HasIntegerType).bind(CastBindName);
|
||||
|
||||
return expr(anyOf(ImplicitCastExpr, ExplicitCastExpr, CallIntExpr));
|
||||
}
|
||||
|
||||
static StringRef parseOpCode(BinaryOperator::Opcode Code) {
|
||||
|
||||
@@ -237,6 +237,10 @@ Changes in existing checks
|
||||
<clang-tidy/checks/modernize/use-designated-initializers>` check by avoiding
|
||||
diagnosing designated initializers for ``std::array`` initializations.
|
||||
|
||||
- Improved :doc:`modernize-use-integer-sign-comparison
|
||||
<clang-tidy/checks/modernize/use-integer-sign-comparison>` check by matching
|
||||
valid integer expressions not directly wrapped around an implicit cast.
|
||||
|
||||
- Improved :doc:`modernize-use-ranges
|
||||
<clang-tidy/checks/modernize/use-ranges>` check by updating suppress
|
||||
warnings logic for ``nullptr`` in ``std::find``.
|
||||
|
||||
@@ -121,3 +121,81 @@ int AllComparisons() {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace PR127471 {
|
||||
int getSignedValue();
|
||||
unsigned int getUnsignedValue();
|
||||
|
||||
void callExprTest() {
|
||||
|
||||
if (getSignedValue() < getUnsignedValue())
|
||||
return;
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison]
|
||||
// CHECK-FIXES: if (std::cmp_less(getSignedValue() , getUnsignedValue()))
|
||||
|
||||
int sVar = 0;
|
||||
if (getUnsignedValue() > sVar)
|
||||
return;
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison]
|
||||
// CHECK-FIXES: if (std::cmp_greater(getUnsignedValue() , sVar))
|
||||
|
||||
unsigned int uVar = 0;
|
||||
if (getSignedValue() > uVar)
|
||||
return;
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison]
|
||||
// CHECK-FIXES: if (std::cmp_greater(getSignedValue() , uVar))
|
||||
|
||||
}
|
||||
|
||||
// Add a class with member functions for testing member function calls
|
||||
class TestClass {
|
||||
public:
|
||||
int getSignedValue() { return -5; }
|
||||
unsigned int getUnsignedValue() { return 5; }
|
||||
};
|
||||
|
||||
void memberFunctionTests() {
|
||||
TestClass obj;
|
||||
|
||||
if (obj.getSignedValue() < obj.getUnsignedValue())
|
||||
return;
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison]
|
||||
// CHECK-FIXES: if (std::cmp_less(obj.getSignedValue() , obj.getUnsignedValue()))
|
||||
}
|
||||
|
||||
void castFunctionTests() {
|
||||
// C-style casts with function calls
|
||||
if ((int)getUnsignedValue() < (unsigned int)getSignedValue())
|
||||
return;
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison]
|
||||
// CHECK-FIXES: if (std::cmp_less(getUnsignedValue(),getSignedValue()))
|
||||
|
||||
|
||||
// Static casts with function calls
|
||||
if (static_cast<int>(getUnsignedValue()) < static_cast<unsigned int>(getSignedValue()))
|
||||
return;
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison]
|
||||
// CHECK-FIXES: if (std::cmp_less(getUnsignedValue(),getSignedValue()))
|
||||
}
|
||||
|
||||
// Define tests
|
||||
#define SIGNED_FUNC getSignedValue()
|
||||
#define UNSIGNED_FUNC getUnsignedValue()
|
||||
|
||||
void defineTests() {
|
||||
if (SIGNED_FUNC < UNSIGNED_FUNC)
|
||||
return;
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison]
|
||||
// CHECK-FIXES: if (std::cmp_less(SIGNED_FUNC , UNSIGNED_FUNC))
|
||||
}
|
||||
|
||||
// Template tests (should not warn)
|
||||
template <typename T1>
|
||||
void templateFunctionTest(T1 value) {
|
||||
if (value() < getUnsignedValue())
|
||||
return;
|
||||
|
||||
if (value() < (getSignedValue() || getUnsignedValue()))
|
||||
return;
|
||||
}
|
||||
} // namespace PR127471
|
||||
|
||||
Reference in New Issue
Block a user