Skip to content

Commit 2693747

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 3e393d9 commit 2693747

File tree

4 files changed

+22
-4
lines changed

4 files changed

+22
-4
lines changed

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

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

564+
void NarrowingConversionsCheck::handleConditionalOperatorArgument(
565+
const ASTContext &Context, const Expr &Lhs, const Expr *Arg) {
566+
if (const auto *ICE = llvm::dyn_cast<ImplicitCastExpr>(Arg))
567+
if (!Arg->getIntegerConstantExpr(Context))
568+
Arg = ICE->getSubExpr();
569+
handleBinaryOperator(Context, Arg->getExprLoc(), Lhs, *Arg);
570+
}
571+
566572
void NarrowingConversionsCheck::handleImplicitCast(
567573
const ASTContext &Context, const ImplicitCastExpr &Cast) {
568574
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
@@ -142,6 +142,10 @@ New check aliases
142142
Changes in existing checks
143143
^^^^^^^^^^^^^^^^^^^^^^^^^^
144144

145+
- Improved :doc:`bugprone-narrowing-conversions
146+
<clang-tidy/checks/bugprone/narrowing-conversions>` check by fixing
147+
false positive from analysis of a conditional expression in C.
148+
145149
- Improved :doc:`bugprone-optional-value-conversion
146150
<clang-tidy/checks/bugprone/optional-value-conversion>` check to detect
147151
conversion in argument of ``std::make_optional``.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %check_clang_tidy %s bugprone-narrowing-conversions %t -- --
2+
3+
char test(int cond, char c) {
4+
char ret = cond > 0 ? ':' : c;
5+
return ret;
6+
}

0 commit comments

Comments
 (0)