Skip to content

Commit b4814ba

Browse files
committed
[clang-tidy] false positive narrowing conversion
Let's consider the following code from the issue #139467: void test(int cond, char c) { char ret = cond > 0 ? ':' : c; } Initializer of 'ret' looks the following: -ImplicitCastExpr 'char' <IntegralCast> `-ConditionalOperator 'int' |-BinaryOperator 'int' '>' | |-ImplicitCastExpr 'int' <LValueToRValue> | | `-DeclRefExpr 'int' lvalue ParmVar 'cond' 'int' | `-IntegerLiteral 'int' 0 |-CharacterLiteral 'int' 58 `-ImplicitCastExpr 'int' <IntegralCast> `-ImplicitCastExpr 'char' <LValueToRValue> `-DeclRefExpr 'char' lvalue ParmVar 'c' 'char' So it could be seen that 'RHS' of the conditional operator is DeclRefExpr 'c' which is casted to 'int' and then the whole conditional expression is casted to 'char'. But this last conversion is not narrowing, because 'RHS' was 'char' _initially_. We should just remove the cast from 'char' to 'int' before the narrowing conversion check.
1 parent 8983b22 commit b4814ba

File tree

5 files changed

+62
-4
lines changed

5 files changed

+62
-4
lines changed

clang-tools-extra/clang-tidy/bugprone/NarrowingConversionsCheck.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -553,15 +553,23 @@ bool NarrowingConversionsCheck::handleConditionalOperator(
553553
// We have an expression like so: `output = cond ? lhs : rhs`
554554
// From the point of view of narrowing conversion we treat it as two
555555
// expressions `output = lhs` and `output = rhs`.
556-
handleBinaryOperator(Context, CO->getLHS()->getExprLoc(), Lhs,
557-
*CO->getLHS());
558-
handleBinaryOperator(Context, CO->getRHS()->getExprLoc(), Lhs,
559-
*CO->getRHS());
556+
handleConditionalOperatorArgument(Context, Lhs, CO->getLHS());
557+
handleConditionalOperatorArgument(Context, Lhs, CO->getRHS());
560558
return true;
561559
}
562560
return false;
563561
}
564562

563+
void NarrowingConversionsCheck::handleConditionalOperatorArgument(
564+
const ASTContext &Context, const Expr &Lhs, const Expr *Arg) {
565+
if (const auto *ICE = llvm::dyn_cast<ImplicitCastExpr>(Arg)) {
566+
if (!Arg->getIntegerConstantExpr(Context)) {
567+
Arg = ICE->getSubExpr();
568+
}
569+
}
570+
handleBinaryOperator(Context, Arg->getExprLoc(), Lhs, *Arg);
571+
}
572+
565573
void NarrowingConversionsCheck::handleImplicitCast(
566574
const ASTContext &Context, const ImplicitCastExpr &Cast) {
567575
if (Cast.getExprLoc().isMacroID())

clang-tools-extra/clang-tidy/bugprone/NarrowingConversionsCheck.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ class NarrowingConversionsCheck : public ClangTidyCheck {
8585
bool handleConditionalOperator(const ASTContext &Context, const Expr &Lhs,
8686
const Expr &Rhs);
8787

88+
void handleConditionalOperatorArgument(const ASTContext &Context, const Expr &Lhs,
89+
const Expr *Arg);
8890
void handleImplicitCast(const ASTContext &Context,
8991
const ImplicitCastExpr &Cast);
9092

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@ New check aliases
182182
Changes in existing checks
183183
^^^^^^^^^^^^^^^^^^^^^^^^^^
184184

185+
- Improved :doc:`bugprone-narrowing-conversions
186+
<clang-tidy/checks/bugprone/narrowing-conversions>` check by fixing
187+
false positive from analysis of a conditional expression in C.
188+
185189
- Improved :doc:`bugprone-crtp-constructor-accessibility
186190
<clang-tidy/checks/bugprone/crtp-constructor-accessibility>` check by fixing
187191
false positives on deleted constructors that cannot be used to construct
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %check_clang_tidy %s bugprone-narrowing-conversions %t -- --
2+
3+
char test_char(int cond, char c) {
4+
char ret = cond > 0 ? ':' : c;
5+
return ret;
6+
}
7+
8+
short test_short(int cond, short s) {
9+
short ret = cond > 0 ? ':' : s;
10+
return ret;
11+
}
12+
13+
int test_int(int cond, int i) {
14+
int ret = cond > 0 ? ':' : i;
15+
return ret;
16+
}
17+
18+
void test(int cond, int i) {
19+
char x = cond > 0 ? ':' : i;
20+
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: narrowing conversion from 'int' to signed type 'char' is implementation-defined [bugprone-narrowing-conversions]
21+
}
22+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %check_clang_tidy %s bugprone-narrowing-conversions %t -- --
2+
3+
char test_char(int cond, char c) {
4+
char ret = cond > 0 ? ':' : c;
5+
return ret;
6+
}
7+
8+
short test_short(int cond, short s) {
9+
short ret = cond > 0 ? ':' : s;
10+
return ret;
11+
}
12+
13+
int test_int(int cond, int i) {
14+
int ret = cond > 0 ? ':' : i;
15+
return ret;
16+
}
17+
18+
void test(int cond, int i) {
19+
char x = cond > 0 ? ':' : i;
20+
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: narrowing conversion from 'int' to signed type 'char' is implementation-defined [bugprone-narrowing-conversions]
21+
}
22+

0 commit comments

Comments
 (0)