Skip to content

Commit 127e351

Browse files
RiverDavetomtor
authored andcommitted
[clang-tidy] Improve integer comparison by matching valid expressions outside implicitCastExpr (llvm#134188)
Aims to fix llvm#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(); } ```
1 parent 7db9698 commit 127e351

File tree

3 files changed

+96
-7
lines changed

3 files changed

+96
-7
lines changed

clang-tools-extra/clang-tidy/modernize/UseIntegerSignComparisonCheck.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,28 @@ intCastExpression(bool IsSigned,
3939
// std::cmp_{} functions trigger a compile-time error if either LHS or RHS
4040
// is a non-integer type, char, enum or bool
4141
// (unsigned char/ signed char are Ok and can be used).
42-
auto IntTypeExpr = expr(hasType(hasCanonicalType(qualType(
42+
const auto HasIntegerType = hasType(hasCanonicalType(qualType(
4343
isInteger(), IsSigned ? isSignedInteger() : isUnsignedInteger(),
44-
unless(isActualChar()), unless(booleanType()), unless(enumType())))));
44+
unless(isActualChar()), unless(booleanType()), unless(enumType()))));
45+
46+
const auto IntTypeExpr = expr(HasIntegerType);
4547

4648
const auto ImplicitCastExpr =
4749
CastBindName.empty() ? implicitCastExpr(hasSourceExpression(IntTypeExpr))
4850
: implicitCastExpr(hasSourceExpression(IntTypeExpr))
4951
.bind(CastBindName);
5052

51-
const auto CStyleCastExpr = cStyleCastExpr(has(ImplicitCastExpr));
52-
const auto StaticCastExpr = cxxStaticCastExpr(has(ImplicitCastExpr));
53-
const auto FunctionalCastExpr = cxxFunctionalCastExpr(has(ImplicitCastExpr));
53+
const auto ExplicitCastExpr =
54+
anyOf(explicitCastExpr(has(ImplicitCastExpr)),
55+
ignoringImpCasts(explicitCastExpr(has(ImplicitCastExpr))));
56+
57+
// Match function calls or variable references not directly wrapped by an
58+
// implicit cast
59+
const auto CallIntExpr = CastBindName.empty()
60+
? callExpr(HasIntegerType)
61+
: callExpr(HasIntegerType).bind(CastBindName);
5462

55-
return expr(anyOf(ImplicitCastExpr, CStyleCastExpr, StaticCastExpr,
56-
FunctionalCastExpr));
63+
return expr(anyOf(ImplicitCastExpr, ExplicitCastExpr, CallIntExpr));
5764
}
5865

5966
static StringRef parseOpCode(BinaryOperator::Opcode Code) {

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,10 @@ Changes in existing checks
237237
<clang-tidy/checks/modernize/use-designated-initializers>` check by avoiding
238238
diagnosing designated initializers for ``std::array`` initializations.
239239

240+
- Improved :doc:`modernize-use-integer-sign-comparison
241+
<clang-tidy/checks/modernize/use-integer-sign-comparison>` check by matching
242+
valid integer expressions not directly wrapped around an implicit cast.
243+
240244
- Improved :doc:`modernize-use-ranges
241245
<clang-tidy/checks/modernize/use-ranges>` check by updating suppress
242246
warnings logic for ``nullptr`` in ``std::find``.

clang-tools-extra/test/clang-tidy/checkers/modernize/use-integer-sign-comparison.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,81 @@ int AllComparisons() {
121121

122122
return 0;
123123
}
124+
125+
namespace PR127471 {
126+
int getSignedValue();
127+
unsigned int getUnsignedValue();
128+
129+
void callExprTest() {
130+
131+
if (getSignedValue() < getUnsignedValue())
132+
return;
133+
// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison]
134+
// CHECK-FIXES: if (std::cmp_less(getSignedValue() , getUnsignedValue()))
135+
136+
int sVar = 0;
137+
if (getUnsignedValue() > sVar)
138+
return;
139+
// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison]
140+
// CHECK-FIXES: if (std::cmp_greater(getUnsignedValue() , sVar))
141+
142+
unsigned int uVar = 0;
143+
if (getSignedValue() > uVar)
144+
return;
145+
// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison]
146+
// CHECK-FIXES: if (std::cmp_greater(getSignedValue() , uVar))
147+
148+
}
149+
150+
// Add a class with member functions for testing member function calls
151+
class TestClass {
152+
public:
153+
int getSignedValue() { return -5; }
154+
unsigned int getUnsignedValue() { return 5; }
155+
};
156+
157+
void memberFunctionTests() {
158+
TestClass obj;
159+
160+
if (obj.getSignedValue() < obj.getUnsignedValue())
161+
return;
162+
// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison]
163+
// CHECK-FIXES: if (std::cmp_less(obj.getSignedValue() , obj.getUnsignedValue()))
164+
}
165+
166+
void castFunctionTests() {
167+
// C-style casts with function calls
168+
if ((int)getUnsignedValue() < (unsigned int)getSignedValue())
169+
return;
170+
// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison]
171+
// CHECK-FIXES: if (std::cmp_less(getUnsignedValue(),getSignedValue()))
172+
173+
174+
// Static casts with function calls
175+
if (static_cast<int>(getUnsignedValue()) < static_cast<unsigned int>(getSignedValue()))
176+
return;
177+
// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison]
178+
// CHECK-FIXES: if (std::cmp_less(getUnsignedValue(),getSignedValue()))
179+
}
180+
181+
// Define tests
182+
#define SIGNED_FUNC getSignedValue()
183+
#define UNSIGNED_FUNC getUnsignedValue()
184+
185+
void defineTests() {
186+
if (SIGNED_FUNC < UNSIGNED_FUNC)
187+
return;
188+
// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison]
189+
// CHECK-FIXES: if (std::cmp_less(SIGNED_FUNC , UNSIGNED_FUNC))
190+
}
191+
192+
// Template tests (should not warn)
193+
template <typename T1>
194+
void templateFunctionTest(T1 value) {
195+
if (value() < getUnsignedValue())
196+
return;
197+
198+
if (value() < (getSignedValue() || getUnsignedValue()))
199+
return;
200+
}
201+
} // namespace PR127471

0 commit comments

Comments
 (0)