Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a63309d

Browse files
authored
[clang-tidy] Improve redundant-casting check for binary operation (#191386)
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
1 parent 504a112 commit a63309d

5 files changed

Lines changed: 89 additions & 15 deletions

File tree

clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ static bool areTypesEqual(QualType TypeS, QualType TypeD,
5050
TypeD.getLocalUnqualifiedType());
5151
}
5252

53-
static bool areBinaryOperatorOperandsTypesEqualToOperatorResultType(
54-
const Expr *E, bool IgnoreTypeAliases) {
53+
static bool binaryOperatorOperandsTypesEqualToOperatorResultType(
54+
const Expr *E, bool IgnoreTypeAliases, bool IgnoreImplicitCasts) {
5555
if (!E)
5656
return true;
5757
const Expr *WithoutImplicitAndParen = E->IgnoreParenImpCasts();
@@ -64,12 +64,21 @@ static bool areBinaryOperatorOperandsTypesEqualToOperatorResultType(
6464

6565
const QualType NonReferenceType = Type.getNonReferenceType();
6666
const QualType LHSType = B->getLHS()->IgnoreImplicit()->getType();
67-
if (LHSType.isNull() || !areTypesEqual(LHSType.getNonReferenceType(),
68-
NonReferenceType, IgnoreTypeAliases))
69-
return false;
7067
const QualType RHSType = B->getRHS()->IgnoreImplicit()->getType();
71-
if (RHSType.isNull() || !areTypesEqual(RHSType.getNonReferenceType(),
72-
NonReferenceType, IgnoreTypeAliases))
68+
const bool LHSMatches =
69+
!LHSType.isNull() && areTypesEqual(LHSType.getNonReferenceType(),
70+
NonReferenceType, IgnoreTypeAliases);
71+
const bool RHSMatches =
72+
!RHSType.isNull() && areTypesEqual(RHSType.getNonReferenceType(),
73+
NonReferenceType, IgnoreTypeAliases);
74+
// Explicit Cast is needed if:
75+
// IgnoreImplicitCasts = false: neither of operands type matches cast type
76+
// IgnoreImplicitCasts = true: at least one operand type doesn't match cast
77+
// type
78+
const bool CastIsNeeded = IgnoreImplicitCasts
79+
? (!LHSMatches || !RHSMatches)
80+
: (!LHSMatches && !RHSMatches);
81+
if (CastIsNeeded)
7382
return false;
7483
}
7584
return true;
@@ -92,11 +101,13 @@ RedundantCastingCheck::RedundantCastingCheck(StringRef Name,
92101
ClangTidyContext *Context)
93102
: ClangTidyCheck(Name, Context),
94103
IgnoreMacros(Options.get("IgnoreMacros", true)),
95-
IgnoreTypeAliases(Options.get("IgnoreTypeAliases", false)) {}
104+
IgnoreTypeAliases(Options.get("IgnoreTypeAliases", false)),
105+
IgnoreImplicitCasts(Options.get("IgnoreImplicitCasts", false)) {}
96106

97107
void RedundantCastingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
98108
Options.store(Opts, "IgnoreMacros", IgnoreMacros);
99109
Options.store(Opts, "IgnoreTypeAliases", IgnoreTypeAliases);
110+
Options.store(Opts, "IgnoreImplicitCasts", IgnoreImplicitCasts);
100111
}
101112

102113
void RedundantCastingCheck::registerMatchers(MatchFinder *Finder) {
@@ -145,8 +156,8 @@ void RedundantCastingCheck::check(const MatchFinder::MatchResult &Result) {
145156
if (!areTypesEqual(TypeS, TypeD, IgnoreTypeAliases))
146157
return;
147158

148-
if (!areBinaryOperatorOperandsTypesEqualToOperatorResultType(
149-
SourceExpr, IgnoreTypeAliases))
159+
if (!binaryOperatorOperandsTypesEqualToOperatorResultType(
160+
SourceExpr, IgnoreTypeAliases, IgnoreImplicitCasts))
150161
return;
151162

152163
const auto *CastExpr = Result.Nodes.getNodeAs<ExplicitCastExpr>("cast");

clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class RedundantCastingCheck : public ClangTidyCheck {
3131
private:
3232
const bool IgnoreMacros;
3333
const bool IgnoreTypeAliases;
34+
const bool IgnoreImplicitCasts;
3435
};
3536

3637
} // namespace clang::tidy::readability

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,14 @@ Changes in existing checks
579579
- Fixed a false positive in array subscript expressions where the types are
580580
not yet resolved.
581581

582+
- Improved :doc:`readability-redundant-casting
583+
<clang-tidy/checks/readability/redundant-casting>` check by adding the
584+
`IgnoreImplicitCasts` option (default `false`) to flag casts as redundant
585+
when at least one operand of a binary operation matches the cast type due to
586+
implicit conversion. For example, ``static_cast<float>(1.0f + 1)`` is now
587+
identified as redundant since ``1`` is implicitly converted to ``float``.
588+
Setting this option to `true` restores the previous behavior.
589+
582590
- Improved :doc:`readability-redundant-member-init
583591
<clang-tidy/checks/readability/redundant-member-init>` check by adding an
584592
`IgnoreMacros` option to suppress warnings when the initializer involves

clang-tools-extra/docs/clang-tidy/checks/readability/redundant-casting.rst

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,24 @@ Options
2727

2828
.. option:: IgnoreMacros
2929

30-
If set to `true`, the check will not give warnings inside macros. Default
31-
is `true`.
30+
If set to `true`, the check will not give warnings inside macros. Default
31+
is `true`.
3232

3333
.. option:: IgnoreTypeAliases
3434

35-
When set to `false`, the check will consider type aliases, and when set to
36-
`true`, it will resolve all type aliases and operate on the underlying
37-
types. Default is `false`.
35+
When set to `false`, the check will consider type aliases, and when set to
36+
`true`, it will resolve all type aliases and operate on the underlying types.
37+
Default is `false`.
38+
39+
.. option:: IgnoreImplicitCasts
40+
41+
When set to `false`, the check will flag casts as redundant when atleast one
42+
operand in an expression is implicitly cast to match the result type of the
43+
explicit cast. When set to `true` the casts will not be flagged. Default is
44+
`false`.
45+
46+
For example, with `IgnoreImplicitCasts = false`:
47+
48+
.. code-block:: c++
49+
50+
static_cast<float>(2.0f + 1); // redundant (1 implicitly converts to float)

clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
// RUN: %check_clang_tidy -std=c++11,c++14,c++17 -check-suffix=,ALIASES %s readability-redundant-casting %t -- \
66
// RUN: -config='{CheckOptions: { readability-redundant-casting.IgnoreTypeAliases: true }}' \
77
// RUN: -- -fno-delayed-template-parsing
8+
// RUN: %check_clang_tidy -std=c++11,c++14,c++17 -check-suffix=IMPLICIT %s readability-redundant-casting %t -- \
9+
// RUN: -config='{CheckOptions: { readability-redundant-casting.IgnoreImplicitCasts: true }}' \
10+
// RUN: -- -fno-delayed-template-parsing
811
// RUN: %check_clang_tidy -std=c++20-or-later %s readability-redundant-casting %t -- \
912
// RUN: -- -fno-delayed-template-parsing -D CXX_20=1
1013
// RUN: %check_clang_tidy -std=c++20-or-later -check-suffix=,MACROS %s readability-redundant-casting %t -- \
@@ -13,6 +16,12 @@
1316
// RUN: %check_clang_tidy -std=c++20-or-later -check-suffix=,ALIASES %s readability-redundant-casting %t -- \
1417
// RUN: -config='{CheckOptions: { readability-redundant-casting.IgnoreTypeAliases: true }}' \
1518
// RUN: -- -fno-delayed-template-parsing -D CXX_20=1
19+
// RUN: %check_clang_tidy -std=c++20-or-later -check-suffix=IMPLICIT %s readability-redundant-casting %t -- \
20+
// RUN: -config='{CheckOptions: { readability-redundant-casting.IgnoreImplicitCasts: true }}' \
21+
// RUN: -- -fno-delayed-template-parsing -D CXX_20=1
22+
23+
#include <cstdint>
24+
#include <cstddef>
1625

1726
struct A {};
1827
struct B : A {};
@@ -168,6 +177,38 @@ void testFunctionalCastWithInitExpr(unsigned a) {
168177
unsigned c = unsigned{0};
169178
}
170179

180+
void testBinaryOperatorRedundantCasting() {
181+
const auto diff_types_operands1 { static_cast<float>(1.0f + 1) };
182+
// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant explicit casting to the same type 'float' as the sub-expression, remove this casting [readability-redundant-casting]
183+
// CHECK-FIXES: const auto diff_types_operands1 { (1.0f + 1) };
184+
// CHECK-FIXES-IMPLICIT: const auto diff_types_operands1 { static_cast<float>(1.0f + 1) };
185+
186+
const auto diff_types_operands2 { static_cast<float>(2 + 3.0f) };
187+
// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant explicit casting to the same type 'float' as the sub-expression, remove this casting [readability-redundant-casting]
188+
// CHECK-FIXES: const auto diff_types_operands2 { (2 + 3.0f) };
189+
// CHECK-FIXES-IMPLICIT: const auto diff_types_operands2 { static_cast<float>(2 + 3.0f) };
190+
191+
const auto diff_types_operands3 { static_cast<int>(1 + static_cast<uint8_t>(1)) };
192+
// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant explicit casting to the same type 'int' as the sub-expression, remove this casting [readability-redundant-casting]
193+
// CHECK-FIXES: const auto diff_types_operands3 { (1 + static_cast<uint8_t>(1)) };
194+
// CHECK-FIXES-IMPLICIT: const auto diff_types_operands3 { static_cast<int>(1 + static_cast<uint8_t>(1)) };
195+
196+
const auto diff_types_operands4 {
197+
static_cast<size_t>(static_cast<size_t>(3) + 2)
198+
};
199+
// CHECK-MESSAGES: :[[@LINE-2]]:5: warning: redundant explicit casting to the same type 'size_t' (aka 'unsigned long{{( long)?}}') as the sub-expression, remove this casting [readability-redundant-casting]
200+
// CHECK-FIXES: (static_cast<size_t>(3) + 2)
201+
// CHECK-FIXES-IMPLICIT: static_cast<size_t>(static_cast<size_t>(3) + 2)
202+
203+
const auto diff_types_operands5 { unsigned(7 + unsigned(4)) };
204+
// 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]
205+
// CHECK-FIXES: const auto diff_types_operands5 { (7 + unsigned(4)) };
206+
// CHECK-FIXES-IMPLICIT: const auto diff_types_operands5 { unsigned(7 + unsigned(4)) };
207+
208+
// casting isn't redundant here
209+
const auto diff_types_operands6 { (int)(-7 + unsigned(4)) };
210+
}
211+
171212
void testBinaryOperator(char c) {
172213
int a = int(c - 'C');
173214
}

0 commit comments

Comments
 (0)