Skip to content

Commit fd0e06d

Browse files
authored
[clang-tidy] Fix missing parentheses in readability-implicit-bool-conversion fixes (#74891)
Check now more properly add missing parentheses to code like this: 'bool bar = true ? 1 : 0 != 0;'. Closes #71867
1 parent 2c4a53a commit fd0e06d

File tree

7 files changed

+140
-109
lines changed

7 files changed

+140
-109
lines changed

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

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "ImplicitBoolConversionCheck.h"
10+
#include "../utils/FixItHintUtils.h"
1011
#include "clang/AST/ASTContext.h"
1112
#include "clang/ASTMatchers/ASTMatchFinder.h"
1213
#include "clang/Lex/Lexer.h"
@@ -61,31 +62,6 @@ bool isUnaryLogicalNotOperator(const Stmt *Statement) {
6162
return UnaryOperatorExpr && UnaryOperatorExpr->getOpcode() == UO_LNot;
6263
}
6364

64-
bool areParensNeededForOverloadedOperator(OverloadedOperatorKind OperatorKind) {
65-
switch (OperatorKind) {
66-
case OO_New:
67-
case OO_Delete: // Fall-through on purpose.
68-
case OO_Array_New:
69-
case OO_Array_Delete:
70-
case OO_ArrowStar:
71-
case OO_Arrow:
72-
case OO_Call:
73-
case OO_Subscript:
74-
return false;
75-
76-
default:
77-
return true;
78-
}
79-
}
80-
81-
bool areParensNeededForStatement(const Stmt *Statement) {
82-
if (const auto *OperatorCall = dyn_cast<CXXOperatorCallExpr>(Statement)) {
83-
return areParensNeededForOverloadedOperator(OperatorCall->getOperator());
84-
}
85-
86-
return isa<BinaryOperator>(Statement) || isa<UnaryOperator>(Statement);
87-
}
88-
8965
void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
9066
const ImplicitCastExpr *Cast, const Stmt *Parent,
9167
ASTContext &Context) {
@@ -105,9 +81,10 @@ void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
10581

10682
const Expr *SubExpr = Cast->getSubExpr();
10783

108-
bool NeedInnerParens = areParensNeededForStatement(SubExpr);
84+
bool NeedInnerParens =
85+
SubExpr != nullptr && utils::fixit::areParensNeededForStatement(*SubExpr);
10986
bool NeedOuterParens =
110-
Parent != nullptr && areParensNeededForStatement(Parent);
87+
Parent != nullptr && utils::fixit::areParensNeededForStatement(*Parent);
11188

11289
std::string StartLocInsertion;
11390

@@ -364,7 +341,7 @@ void ImplicitBoolConversionCheck::handleCastToBool(const ImplicitCastExpr *Cast,
364341
return;
365342
}
366343

367-
auto Diag = diag(Cast->getBeginLoc(), "implicit conversion %0 -> bool")
344+
auto Diag = diag(Cast->getBeginLoc(), "implicit conversion %0 -> 'bool'")
368345
<< Cast->getSubExpr()->getType();
369346

370347
StringRef EquivalentLiteral =
@@ -381,7 +358,7 @@ void ImplicitBoolConversionCheck::handleCastFromBool(
381358
ASTContext &Context) {
382359
QualType DestType =
383360
NextImplicitCast ? NextImplicitCast->getType() : Cast->getType();
384-
auto Diag = diag(Cast->getBeginLoc(), "implicit conversion bool -> %0")
361+
auto Diag = diag(Cast->getBeginLoc(), "implicit conversion 'bool' -> %0")
385362
<< DestType;
386363

387364
if (const auto *BoolLiteral =

clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,40 @@ std::optional<FixItHint> addQualifierToVarDecl(const VarDecl &Var,
224224
return std::nullopt;
225225
}
226226

227+
bool areParensNeededForStatement(const Stmt &Node) {
228+
if (isa<ParenExpr>(&Node))
229+
return false;
230+
231+
if (isa<clang::BinaryOperator>(&Node) || isa<UnaryOperator>(&Node))
232+
return true;
233+
234+
if (isa<clang::ConditionalOperator>(&Node) ||
235+
isa<BinaryConditionalOperator>(&Node))
236+
return true;
237+
238+
if (const auto *Op = dyn_cast<CXXOperatorCallExpr>(&Node)) {
239+
switch (Op->getOperator()) {
240+
case OO_PlusPlus:
241+
[[fallthrough]];
242+
case OO_MinusMinus:
243+
return Op->getNumArgs() != 2;
244+
case OO_Call:
245+
[[fallthrough]];
246+
case OO_Subscript:
247+
[[fallthrough]];
248+
case OO_Arrow:
249+
return false;
250+
default:
251+
return true;
252+
};
253+
}
254+
255+
if (isa<CStyleCastExpr>(&Node))
256+
return true;
257+
258+
return false;
259+
}
260+
227261
// Return true if expr needs to be put in parens when it is an argument of a
228262
// prefix unary operator, e.g. when it is a binary or ternary operator
229263
// syntactically.

clang-tools-extra/clang-tidy/utils/FixItHintUtils.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ addQualifierToVarDecl(const VarDecl &Var, const ASTContext &Context,
4747

4848
// \brief Format a pointer to an expression
4949
std::string formatDereference(const Expr &ExprNode, const ASTContext &Context);
50+
51+
// \brief Checks whatever a expression require extra () to be always used in
52+
// safe way in any other expression.
53+
bool areParensNeededForStatement(const Stmt &Node);
5054
} // namespace clang::tidy::utils::fixit
5155

5256
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_FIXITHINTUTILS_H

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -502,8 +502,8 @@ Changes in existing checks
502502
<clang-tidy/checks/readability/implicit-bool-conversion>` check to take
503503
do-while loops into account for the `AllowIntegerConditions` and
504504
`AllowPointerConditions` options. It also now provides more consistent
505-
suggestions when parentheses are added to the return value. It also ignores
506-
false-positives for comparison containing bool bitfield.
505+
suggestions when parentheses are added to the return value or expressions.
506+
It also ignores false-positives for comparison containing bool bitfield.
507507

508508
- Improved :doc:`readability-misleading-indentation
509509
<clang-tidy/checks/readability/misleading-indentation>` check to ignore

clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-allow-in-conditions.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ struct Struct {
1919
void regularImplicitConversionIntegerToBoolIsNotIgnored() {
2020
int integer = 0;
2121
functionTaking<bool>(integer);
22-
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool [readability-implicit-bool-conversion]
22+
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> 'bool' [readability-implicit-bool-conversion]
2323
// CHECK-FIXES: functionTaking<bool>(integer != 0);
2424
}
2525

@@ -54,12 +54,12 @@ void implicitConversionIntegerToBoolInConditionalsIsAllowed() {
5454
void regularImplicitConversionPointerToBoolIsNotIgnored() {
5555
int* pointer = nullptr;
5656
functionTaking<bool>(pointer);
57-
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int *' -> bool
57+
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int *' -> 'bool'
5858
// CHECK-FIXES: functionTaking<bool>(pointer != nullptr);
5959

6060
int Struct::* memberPointer = &Struct::member;
6161
functionTaking<bool>(memberPointer);
62-
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int Struct::*' -> bool
62+
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int Struct::*' -> 'bool'
6363
// CHECK-FIXES: functionTaking<bool>(memberPointer != nullptr);
6464
}
6565

clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-cxx98.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,31 @@ struct Struct {
1515
void useOldNullMacroInReplacements() {
1616
int* pointer = NULL;
1717
functionTaking<bool>(pointer);
18-
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int *' -> bool [readability-implicit-bool-conversion]
18+
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int *' -> 'bool' [readability-implicit-bool-conversion]
1919
// CHECK-FIXES: functionTaking<bool>(pointer != 0);
2020

2121
int Struct::* memberPointer = NULL;
2222
functionTaking<bool>(!memberPointer);
23-
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit conversion 'int Struct::*' -> bool
23+
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit conversion 'int Struct::*' -> 'bool'
2424
// CHECK-FIXES: functionTaking<bool>(memberPointer == 0);
2525
}
2626

2727
void fixFalseLiteralConvertingToNullPointer() {
2828
functionTaking<int*>(false);
29-
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion bool -> 'int *'
29+
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'bool' -> 'int *'
3030
// CHECK-FIXES: functionTaking<int*>(0);
3131

3232
int* pointer = NULL;
3333
if (pointer == false) {}
34-
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: implicit conversion bool -> 'int *'
34+
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: implicit conversion 'bool' -> 'int *'
3535
// CHECK-FIXES: if (pointer == 0) {}
3636

3737
functionTaking<int Struct::*>(false);
38-
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion bool -> 'int Struct::*'
38+
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion 'bool' -> 'int Struct::*'
3939
// CHECK-FIXES: functionTaking<int Struct::*>(0);
4040

4141
int Struct::* memberPointer = NULL;
4242
if (memberPointer != false) {}
43-
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion bool -> 'int Struct::*'
43+
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'bool' -> 'int Struct::*'
4444
// CHECK-FIXES: if (memberPointer != 0) {}
4545
}

0 commit comments

Comments
 (0)