https://github.com/RiverDave created 
https://github.com/llvm/llvm-project/pull/144240

Expands check based on: https://github.com/llvm/llvm-project/issues/127471

What changed:

1. I’m detecting `callExpr`  not directly wrapped by an implicit cast. where 
its `sourceExpression`  is of integer type.
2. The check originally counted with the fact that signed integer expressions 
would have an implicit cast expression for all **comparison cases**, but that 
doesn’t seem to be correct as shown below.

(For the following snippet. as referenced in #143927)

```cpp
struct A
{
  unsigned size() const;
};

struct B
{
  A a;

  bool foo(const A& a2) const { return (int)a2.size() == size(); //here  }
  int size() const { return (int)a.size(); }
};

```

(see AST):

<img width="881" alt="Screenshot 2025-06-14 at 7 24 20 PM" 
src="https://github.com/user-attachments/assets/d112b7c3-2217-4195-bfc4-cf4c5b46abd4";
 />


**Notice how the signed operand is not wrapped by a cast in any way.**

>From 4e78c29eb5f2d7d750c467b014a6827c8db9f19c Mon Sep 17 00:00:00 2001
From: David Rivera <davidriv...@gmail.com>
Date: Wed, 2 Apr 2025 21:02:00 -0400
Subject: [PATCH] [clang-tidy] Improve integer comparison by matching valid
 expressions outside implicitCastExpr for use-integer-sign-comparison

---
 .../UseIntegerSignComparisonCheck.cpp         | 38 +++++---
 clang-tools-extra/docs/ReleaseNotes.rst       |  4 +
 .../modernize/use-integer-sign-comparison.cpp | 97 +++++++++++++++++++
 3 files changed, 123 insertions(+), 16 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/modernize/UseIntegerSignComparisonCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseIntegerSignComparisonCheck.cpp
index eeba5cce80da5..8f0bcf26e8357 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseIntegerSignComparisonCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseIntegerSignComparisonCheck.cpp
@@ -39,21 +39,23 @@ 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);
+      implicitCastExpr(hasSourceExpression(IntTypeExpr)).bind(CastBindName);
+
+  const auto ExplicitCastExpr =
+      anyOf(explicitCastExpr(has(ImplicitCastExpr)),
+            ignoringImpCasts(explicitCastExpr(has(ImplicitCastExpr))));
 
-  const auto CStyleCastExpr = cStyleCastExpr(has(ImplicitCastExpr));
-  const auto StaticCastExpr = cxxStaticCastExpr(has(ImplicitCastExpr));
-  const auto FunctionalCastExpr = cxxFunctionalCastExpr(has(ImplicitCastExpr));
+  // Match function calls not directly wrapped by an implicit cast
+  const auto CallIntExpr = callExpr(HasIntegerType).bind(CastBindName);
 
-  return expr(anyOf(ImplicitCastExpr, CStyleCastExpr, StaticCastExpr,
-                    FunctionalCastExpr));
+  return expr(anyOf(ImplicitCastExpr, ExplicitCastExpr, CallIntExpr));
 }
 
 static StringRef parseOpCode(BinaryOperator::Opcode Code) {
@@ -91,7 +93,8 @@ void UseIntegerSignComparisonCheck::storeOptions(
 
 void UseIntegerSignComparisonCheck::registerMatchers(MatchFinder *Finder) {
   const auto SignedIntCastExpr = intCastExpression(true, "sIntCastExpression");
-  const auto UnSignedIntCastExpr = intCastExpression(false);
+  const auto UnSignedIntCastExpr =
+      intCastExpression(false, "uIntCastExpression");
 
   // Flag all operators "==", "<=", ">=", "<", ">", "!="
   // that are used between signed/unsigned
@@ -112,14 +115,17 @@ void UseIntegerSignComparisonCheck::registerPPCallbacks(
 void UseIntegerSignComparisonCheck::check(
     const MatchFinder::MatchResult &Result) {
   const auto *SignedCastExpression =
-      Result.Nodes.getNodeAs<ImplicitCastExpr>("sIntCastExpression");
-  assert(SignedCastExpression);
+      Result.Nodes.getNodeAs<CastExpr>("sIntCastExpression");
+  const auto *UnsignedCastExpression =
+      Result.Nodes.getNodeAs<CastExpr>("uIntCastExpression");
+  const auto *CastExpression =
+      SignedCastExpression ? SignedCastExpression : UnsignedCastExpression;
+  assert(CastExpression);
 
   // Ignore the match if we know that the signed int value is not negative.
   Expr::EvalResult EVResult;
-  if (!SignedCastExpression->isValueDependent() &&
-      SignedCastExpression->getSubExpr()->EvaluateAsInt(EVResult,
-                                                        *Result.Context)) {
+  if (!CastExpression->isValueDependent() &&
+      CastExpression->getSubExpr()->EvaluateAsInt(EVResult, *Result.Context)) {
     const llvm::APSInt SValue = EVResult.Val.getInt();
     if (SValue.isNonNegative())
       return;
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 19ccd1790e757..882ee0015df17 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -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``.
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-integer-sign-comparison.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-integer-sign-comparison.cpp
index e0a84ef5aed26..1af24c28e048d 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-integer-sign-comparison.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-integer-sign-comparison.cpp
@@ -121,3 +121,100 @@ 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;
+    }
+
+//GH127471
+  struct A
+  {
+    unsigned size() const;
+  };
+
+  struct B
+  {
+    A a;
+
+   bool foo(const A& a2) const {
+     return (int)a2.size() == size();
+     // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: comparison between 'signed' 
and 'unsigned' integers [modernize-use-integer-sign-comparison]
+     // CHECK-FIXES: return std::cmp_equal(a2.size(), size())
+   }
+
+   int size() const { return (int)a.size(); }
+  };
+} // namespace PR127471

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to