[clang-tools-extra] [clang-tidy] Improve redundant-casting check for binary operation (PR #191386)
Gaurav Dhingra via cfe-commits
cfe-commits at lists.llvm.org
Sat Apr 11 03:16:17 PDT 2026
https://github.com/gxyd updated https://github.com/llvm/llvm-project/pull/191386
>From 7d7cfaec6c4fa6897baa8e7f32a78dc33910fc6b Mon Sep 17 00:00:00 2001
From: Gaurav Dhingra <gauravdhingra.gxyd at gmail.com>
Date: Fri, 10 Apr 2026 16:14:58 +0530
Subject: [PATCH 1/3] [clang-tidy] Improve redundant-casting check for binary
operation
Mark explicit casting as readabily redundant for a
BinaryOperation with atleast one operand of the same
type as the cast type in `RedundantCastingCheck`
E.g.; `static<float>(1 + 2.0f)` // redundant cast
Fixes #182132
---
.../readability/RedundantCastingCheck.cpp | 17 ++++++++++-------
.../checkers/readability/redundant-casting.cpp | 16 ++++++++++++++++
2 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp
index eae0b3f6d0e7d..9dc4cef139125 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp
@@ -50,7 +50,7 @@ static bool areTypesEqual(QualType TypeS, QualType TypeD,
TypeD.getLocalUnqualifiedType());
}
-static bool areBinaryOperatorOperandsTypesEqualToOperatorResultType(
+static bool anyBinaryOperatorOperandsTypesEqualToOperatorResultType(
const Expr *E, bool IgnoreTypeAliases) {
if (!E)
return true;
@@ -64,12 +64,15 @@ static bool areBinaryOperatorOperandsTypesEqualToOperatorResultType(
const QualType NonReferenceType = Type.getNonReferenceType();
const QualType LHSType = B->getLHS()->IgnoreImplicit()->getType();
- if (LHSType.isNull() || !areTypesEqual(LHSType.getNonReferenceType(),
- NonReferenceType, IgnoreTypeAliases))
- return false;
const QualType RHSType = B->getRHS()->IgnoreImplicit()->getType();
- if (RHSType.isNull() || !areTypesEqual(RHSType.getNonReferenceType(),
- NonReferenceType, IgnoreTypeAliases))
+ const bool LHSMatches =
+ !LHSType.isNull() && areTypesEqual(LHSType.getNonReferenceType(),
+ NonReferenceType, IgnoreTypeAliases);
+ const bool RHSMatches =
+ !RHSType.isNull() && areTypesEqual(RHSType.getNonReferenceType(),
+ NonReferenceType, IgnoreTypeAliases);
+ if (!LHSMatches && !RHSMatches)
+ // neither of the operand matches => casting is needed for readability
return false;
}
return true;
@@ -145,7 +148,7 @@ void RedundantCastingCheck::check(const MatchFinder::MatchResult &Result) {
if (!areTypesEqual(TypeS, TypeD, IgnoreTypeAliases))
return;
- if (!areBinaryOperatorOperandsTypesEqualToOperatorResultType(
+ if (!anyBinaryOperatorOperandsTypesEqualToOperatorResultType(
SourceExpr, IgnoreTypeAliases))
return;
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
index 001057aeaa495..8a0f271d55e29 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
@@ -14,6 +14,8 @@
// RUN: -config='{CheckOptions: { readability-redundant-casting.IgnoreTypeAliases: true }}' \
// RUN: -- -fno-delayed-template-parsing -D CXX_20=1
+#include <cstdint>
+
struct A {};
struct B : A {};
A getA();
@@ -168,6 +170,20 @@ void testFunctionalCastWithInitExpr(unsigned a) {
unsigned c = unsigned{0};
}
+void testBinaryOperatorRedundantCasting() {
+ const auto diff_types_operands1 { static_cast<float>(1.0f + 1) };
+ // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant explicit casting to the same type 'float' as the sub-expression, remove this casting [readability-redundant-casting]
+ // CHECK-FIXES: const auto diff_types_operands1 { (1.0f + 1) };
+
+ const auto diff_types_operands2 { static_cast<float>(2 + 3.0f) };
+ // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant explicit casting to the same type 'float' as the sub-expression, remove this casting [readability-redundant-casting]
+ // CHECK-FIXES: const auto diff_types_operands2 { (2 + 3.0f) };
+
+ const auto diff_types_operands3 { static_cast<int>(1 + static_cast<uint8_t>(1)) };
+ // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant explicit casting to the same type 'int' as the sub-expression, remove this casting [readability-redundant-casting]
+ // CHECK-FIXES: const auto diff_types_operands3 { (1 + static_cast<uint8_t>(1)) };
+}
+
void testBinaryOperator(char c) {
int a = int(c - 'C');
}
>From a1a4ac783a29d71574e02c8f7bd7b0cbc8a5428a Mon Sep 17 00:00:00 2001
From: Gaurav Dhingra <gauravdhingra.gxyd at gmail.com>
Date: Sat, 11 Apr 2026 12:47:51 +0530
Subject: [PATCH 2/3] add ReleaseNotes entry for the fixed issue
---
clang-tools-extra/docs/ReleaseNotes.rst | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 02315415b975f..073ae48b9018c 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -454,6 +454,12 @@ Changes in existing checks
implicit conversions of logical operator results (``&&``, ``||``, ``!``)
to ``bool`` in C.
+- Improved :doc:`readability-redundant-casting
+ <clang-tidy/checks/readability/redundant-casting>` check by fixing a false
+ negative where casts were not flagged as redundant when at least one operand
+ of a binary operation had the same type as the cast result type. For example,
+ ``static_cast<float>(1.0f + 1)`` is now correctly identified as redundant.
+
- Improved :doc:`readability-non-const-parameter
<clang-tidy/checks/readability/non-const-parameter>` check by avoiding false
positives on parameters used in dependent expressions (e.g. inside generic
>From 69cb114d4eb1554eb8e423d35a9dc9469e932fc1 Mon Sep 17 00:00:00 2001
From: Gaurav Dhingra <gauravdhingra.gxyd at gmail.com>
Date: Sat, 11 Apr 2026 15:45:10 +0530
Subject: [PATCH 3/3] add more test cases
add test cases for: ``int`` & ``unsigned`` , ``size_t`` & ``int``
---
.../checkers/readability/redundant-casting.cpp | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
index 8a0f271d55e29..336d17c7d69ef 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
@@ -15,6 +15,7 @@
// RUN: -- -fno-delayed-template-parsing -D CXX_20=1
#include <cstdint>
+#include <cstddef>
struct A {};
struct B : A {};
@@ -182,6 +183,19 @@ void testBinaryOperatorRedundantCasting() {
const auto diff_types_operands3 { static_cast<int>(1 + static_cast<uint8_t>(1)) };
// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant explicit casting to the same type 'int' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-FIXES: const auto diff_types_operands3 { (1 + static_cast<uint8_t>(1)) };
+
+ const auto diff_types_operands4 {
+ static_cast<size_t>(static_cast<size_t>(3) + 2)
+ };
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: redundant explicit casting to the same type 'size_t' (aka 'unsigned long') as the sub-expression, remove this casting [readability-redundant-casting]
+ // CHECK-FIXES: (static_cast<size_t>(3) + 2)
+
+ const auto diff_types_operands5 { unsigned(7 + unsigned(4)) };
+ // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant explicit casting to the same type 'unsigned int' as the sub-expression, remove this casting [readability-redundant-casting]
+ // CHECK-FIXES: const auto diff_types_operands5 { (7 + unsigned(4)) };
+
+ // casting isn't redundant here
+ const auto diff_types_operands6 { (int)(-7 + unsigned(4)) };
}
void testBinaryOperator(char c) {
More information about the cfe-commits
mailing list