blob: 22fce443a3e0ab576ea6586232d0e4d3a12b5e0f [file] [log] [blame]
Alexander Kornienkof1a65522017-08-08 14:53:52 +00001//===--- ImplicitBoolConversionCheck.cpp - clang-tidy----------------------===//
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +00006//
7//===----------------------------------------------------------------------===//
8
Alexander Kornienkof1a65522017-08-08 14:53:52 +00009#include "ImplicitBoolConversionCheck.h"
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000010#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "clang/Lex/Lexer.h"
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000013#include "clang/Tooling/FixIt.h"
Alexander Kornienko4e001b52017-04-29 12:06:45 +000014#include <queue>
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000015
16using namespace clang::ast_matchers;
17
18namespace clang {
19namespace tidy {
Etienne Bergeron456177b2016-05-02 18:00:29 +000020namespace readability {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000021
22namespace {
23
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000024AST_MATCHER(Stmt, isMacroExpansion) {
25 SourceManager &SM = Finder->getASTContext().getSourceManager();
Stephen Kelly43465bf2018-08-09 22:42:26 +000026 SourceLocation Loc = Node.getBeginLoc();
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000027 return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc);
28}
29
30bool isNULLMacroExpansion(const Stmt *Statement, ASTContext &Context) {
31 SourceManager &SM = Context.getSourceManager();
32 const LangOptions &LO = Context.getLangOpts();
Stephen Kelly43465bf2018-08-09 22:42:26 +000033 SourceLocation Loc = Statement->getBeginLoc();
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000034 return SM.isMacroBodyExpansion(Loc) &&
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000035 Lexer::getImmediateMacroName(Loc, SM, LO) == "NULL";
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000036}
37
38AST_MATCHER(Stmt, isNULLMacroExpansion) {
39 return isNULLMacroExpansion(&Node, Finder->getASTContext());
40}
41
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000042StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
43 QualType Type,
44 ASTContext &Context) {
45 switch (CastExprKind) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000046 case CK_IntegralToBoolean:
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000047 return Type->isUnsignedIntegerType() ? "0u" : "0";
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000048
49 case CK_FloatingToBoolean:
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000050 return Context.hasSameType(Type, Context.FloatTy) ? "0.0f" : "0.0";
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000051
52 case CK_PointerToBoolean:
53 case CK_MemberPointerToBoolean: // Fall-through on purpose.
54 return Context.getLangOpts().CPlusPlus11 ? "nullptr" : "0";
55
56 default:
Benjamin Kramer6d505c02015-10-25 22:03:00 +000057 llvm_unreachable("Unexpected cast kind");
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000058 }
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000059}
60
61bool isUnaryLogicalNotOperator(const Stmt *Statement) {
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000062 const auto *UnaryOperatorExpr = dyn_cast<UnaryOperator>(Statement);
63 return UnaryOperatorExpr && UnaryOperatorExpr->getOpcode() == UO_LNot;
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000064}
65
66bool areParensNeededForOverloadedOperator(OverloadedOperatorKind OperatorKind) {
67 switch (OperatorKind) {
68 case OO_New:
69 case OO_Delete: // Fall-through on purpose.
70 case OO_Array_New:
71 case OO_Array_Delete:
72 case OO_ArrowStar:
73 case OO_Arrow:
74 case OO_Call:
75 case OO_Subscript:
76 return false;
77
78 default:
79 return true;
80 }
81}
82
83bool areParensNeededForStatement(const Stmt *Statement) {
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000084 if (const auto *OperatorCall = dyn_cast<CXXOperatorCallExpr>(Statement)) {
85 return areParensNeededForOverloadedOperator(OperatorCall->getOperator());
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000086 }
87
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000088 return isa<BinaryOperator>(Statement) || isa<UnaryOperator>(Statement);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000089}
90
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000091void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
92 const ImplicitCastExpr *Cast, const Stmt *Parent,
93 ASTContext &Context) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000094 // In case of expressions like (! integer), we should remove the redundant not
95 // operator and use inverted comparison (integer == 0).
96 bool InvertComparison =
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000097 Parent != nullptr && isUnaryLogicalNotOperator(Parent);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000098 if (InvertComparison) {
Stephen Kelly43465bf2018-08-09 22:42:26 +000099 SourceLocation ParentStartLoc = Parent->getBeginLoc();
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000100 SourceLocation ParentEndLoc =
Stephen Kelly43465bf2018-08-09 22:42:26 +0000101 cast<UnaryOperator>(Parent)->getSubExpr()->getBeginLoc();
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000102 Diag << FixItHint::CreateRemoval(
103 CharSourceRange::getCharRange(ParentStartLoc, ParentEndLoc));
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000104
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000105 Parent = Context.getParents(*Parent)[0].get<Stmt>();
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000106 }
107
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000108 const Expr *SubExpr = Cast->getSubExpr();
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000109
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000110 bool NeedInnerParens = areParensNeededForStatement(SubExpr);
111 bool NeedOuterParens =
112 Parent != nullptr && areParensNeededForStatement(Parent);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000113
114 std::string StartLocInsertion;
115
116 if (NeedOuterParens) {
117 StartLocInsertion += "(";
118 }
119 if (NeedInnerParens) {
120 StartLocInsertion += "(";
121 }
122
123 if (!StartLocInsertion.empty()) {
Stephen Kelly43465bf2018-08-09 22:42:26 +0000124 Diag << FixItHint::CreateInsertion(Cast->getBeginLoc(), StartLocInsertion);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000125 }
126
127 std::string EndLocInsertion;
128
129 if (NeedInnerParens) {
130 EndLocInsertion += ")";
131 }
132
133 if (InvertComparison) {
134 EndLocInsertion += " == ";
135 } else {
136 EndLocInsertion += " != ";
137 }
138
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000139 EndLocInsertion += getZeroLiteralToCompareWithForType(
140 Cast->getCastKind(), SubExpr->getType(), Context);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000141
142 if (NeedOuterParens) {
143 EndLocInsertion += ")";
144 }
145
146 SourceLocation EndLoc = Lexer::getLocForEndOfToken(
Stephen Kellyc09197e2018-08-09 22:43:02 +0000147 Cast->getEndLoc(), 0, Context.getSourceManager(), Context.getLangOpts());
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000148 Diag << FixItHint::CreateInsertion(EndLoc, EndLocInsertion);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000149}
150
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000151StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression,
152 ASTContext &Context) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000153 if (isNULLMacroExpansion(Expression, Context)) {
154 return "false";
155 }
156
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000157 if (const auto *IntLit = dyn_cast<IntegerLiteral>(Expression)) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000158 return (IntLit->getValue() == 0) ? "false" : "true";
159 }
160
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000161 if (const auto *FloatLit = dyn_cast<FloatingLiteral>(Expression)) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000162 llvm::APFloat FloatLitAbsValue = FloatLit->getValue();
163 FloatLitAbsValue.clearSign();
164 return (FloatLitAbsValue.bitcastToAPInt() == 0) ? "false" : "true";
165 }
166
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000167 if (const auto *CharLit = dyn_cast<CharacterLiteral>(Expression)) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000168 return (CharLit->getValue() == 0) ? "false" : "true";
169 }
170
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000171 if (isa<StringLiteral>(Expression->IgnoreCasts())) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000172 return "true";
173 }
174
175 return StringRef();
176}
177
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000178void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
179 const ImplicitCastExpr *Cast,
180 ASTContext &Context, StringRef OtherType) {
181 const Expr *SubExpr = Cast->getSubExpr();
182 bool NeedParens = !isa<ParenExpr>(SubExpr);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000183
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000184 Diag << FixItHint::CreateInsertion(
Stephen Kelly43465bf2018-08-09 22:42:26 +0000185 Cast->getBeginLoc(),
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000186 (Twine("static_cast<") + OtherType + ">" + (NeedParens ? "(" : ""))
187 .str());
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000188
189 if (NeedParens) {
190 SourceLocation EndLoc = Lexer::getLocForEndOfToken(
Stephen Kellyc09197e2018-08-09 22:43:02 +0000191 Cast->getEndLoc(), 0, Context.getSourceManager(),
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000192 Context.getLangOpts());
193
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000194 Diag << FixItHint::CreateInsertion(EndLoc, ")");
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000195 }
196}
197
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000198StringRef getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
199 QualType DestType, ASTContext &Context) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000200 // Prior to C++11, false literal could be implicitly converted to pointer.
201 if (!Context.getLangOpts().CPlusPlus11 &&
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000202 (DestType->isPointerType() || DestType->isMemberPointerType()) &&
203 BoolLiteral->getValue() == false) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000204 return "0";
205 }
206
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000207 if (DestType->isFloatingType()) {
208 if (Context.hasSameType(DestType, Context.FloatTy)) {
209 return BoolLiteral->getValue() ? "1.0f" : "0.0f";
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000210 }
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000211 return BoolLiteral->getValue() ? "1.0" : "0.0";
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000212 }
213
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000214 if (DestType->isUnsignedIntegerType()) {
215 return BoolLiteral->getValue() ? "1u" : "0u";
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000216 }
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000217 return BoolLiteral->getValue() ? "1" : "0";
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000218}
219
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000220bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000221 ASTContext &Context) {
Alexander Kornienko4e001b52017-04-29 12:06:45 +0000222 std::queue<const Stmt *> Q;
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000223 Q.push(Cast);
Alexander Kornienko4e001b52017-04-29 12:06:45 +0000224 while (!Q.empty()) {
225 for (const auto &N : Context.getParents(*Q.front())) {
226 const Stmt *S = N.get<Stmt>();
227 if (!S)
228 return false;
Alexander Kornienkof89e0bb2017-05-08 15:22:09 +0000229 if (isa<IfStmt>(S) || isa<ConditionalOperator>(S) || isa<ForStmt>(S) ||
230 isa<WhileStmt>(S) || isa<BinaryConditionalOperator>(S))
Alexander Kornienko4e001b52017-04-29 12:06:45 +0000231 return true;
232 if (isa<ParenExpr>(S) || isa<ImplicitCastExpr>(S) ||
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000233 isUnaryLogicalNotOperator(S) ||
Alexander Kornienko4e001b52017-04-29 12:06:45 +0000234 (isa<BinaryOperator>(S) && cast<BinaryOperator>(S)->isLogicalOp())) {
235 Q.push(S);
236 } else {
237 return false;
238 }
239 }
240 Q.pop();
241 }
242 return false;
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000243}
244
245} // anonymous namespace
246
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000247ImplicitBoolConversionCheck::ImplicitBoolConversionCheck(
248 StringRef Name, ClangTidyContext *Context)
Haojian Wu80c1c9f2016-08-16 11:15:05 +0000249 : ClangTidyCheck(Name, Context),
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000250 AllowIntegerConditions(Options.get("AllowIntegerConditions", false)),
251 AllowPointerConditions(Options.get("AllowPointerConditions", false)) {}
Haojian Wu80c1c9f2016-08-16 11:15:05 +0000252
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000253void ImplicitBoolConversionCheck::storeOptions(
254 ClangTidyOptions::OptionMap &Opts) {
255 Options.store(Opts, "AllowIntegerConditions", AllowIntegerConditions);
256 Options.store(Opts, "AllowPointerConditions", AllowPointerConditions);
Haojian Wu80c1c9f2016-08-16 11:15:05 +0000257}
258
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000259void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) {
Alexander Kornienkoe1331402017-05-16 15:44:42 +0000260 auto exceptionCases =
Alexander Kornienko50de3ad2017-05-16 16:40:46 +0000261 expr(anyOf(allOf(isMacroExpansion(), unless(isNULLMacroExpansion())),
Alexander Kornienkoc5016c02018-10-02 11:38:41 +0000262 has(ignoringImplicit(memberExpr(hasDeclaration(fieldDecl(hasBitWidth(1)))))),
Alexander Kornienko50de3ad2017-05-16 16:40:46 +0000263 hasParent(explicitCastExpr())));
Alexander Kornienkoc6ba6fc2017-05-04 16:06:08 +0000264 auto implicitCastFromBool = implicitCastExpr(
Alexander Kornienkoc6ba6fc2017-05-04 16:06:08 +0000265 anyOf(hasCastKind(CK_IntegralCast), hasCastKind(CK_IntegralToFloating),
266 // Prior to C++11 cast from bool literal to pointer was allowed.
267 allOf(anyOf(hasCastKind(CK_NullToPointer),
268 hasCastKind(CK_NullToMemberPointer)),
269 hasSourceExpression(cxxBoolLiteral()))),
Alexander Kornienko50de3ad2017-05-16 16:40:46 +0000270 hasSourceExpression(expr(hasType(booleanType()))),
271 unless(exceptionCases));
Alexander Kornienkoc6ba6fc2017-05-04 16:06:08 +0000272 auto boolXor =
273 binaryOperator(hasOperatorName("^"), hasLHS(implicitCastFromBool),
274 hasRHS(implicitCastFromBool));
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000275 Finder->addMatcher(
276 implicitCastExpr(
Alexander Kornienko50de3ad2017-05-16 16:40:46 +0000277 anyOf(hasCastKind(CK_IntegralToBoolean),
278 hasCastKind(CK_FloatingToBoolean),
279 hasCastKind(CK_PointerToBoolean),
280 hasCastKind(CK_MemberPointerToBoolean)),
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000281 // Exclude case of using if or while statements with variable
282 // declaration, e.g.:
283 // if (int var = functionCall()) {}
284 unless(
285 hasParent(stmt(anyOf(ifStmt(), whileStmt()), has(declStmt())))),
Alexander Kornienko50de3ad2017-05-16 16:40:46 +0000286 // Exclude cases common to implicit cast to and from bool.
287 unless(exceptionCases), unless(has(boolXor)),
Kazuaki Ishizakidd5571d2020-04-05 15:28:11 +0900288 // Retrieve also parent statement, to check if we need additional
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000289 // parens in replacement.
Alexander Kornienkoe1331402017-05-16 15:44:42 +0000290 anyOf(hasParent(stmt().bind("parentStmt")), anything()),
291 unless(isInTemplateInstantiation()),
292 unless(hasAncestor(functionTemplateDecl())))
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000293 .bind("implicitCastToBool"),
294 this);
295
Nathan James97572fa2020-03-10 00:42:21 +0000296 auto boolComparison = binaryOperator(hasAnyOperatorName("==", "!="),
297 hasLHS(implicitCastFromBool),
298 hasRHS(implicitCastFromBool));
299 auto boolOpAssignment = binaryOperator(hasAnyOperatorName("|=", "&="),
300 hasLHS(expr(hasType(booleanType()))));
Malcolm Parsonsd8851b5d2018-11-27 16:23:39 +0000301 auto bitfieldAssignment = binaryOperator(
302 hasLHS(memberExpr(hasDeclaration(fieldDecl(hasBitWidth(1))))));
303 auto bitfieldConstruct = cxxConstructorDecl(hasDescendant(cxxCtorInitializer(
304 withInitializer(equalsBoundNode("implicitCastFromBool")),
305 forField(hasBitWidth(1)))));
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000306 Finder->addMatcher(
307 implicitCastExpr(
Alexander Kornienkob92cb072017-05-04 15:34:31 +0000308 implicitCastFromBool,
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000309 // Exclude comparisons of bools, as they are always cast to integers
310 // in such context:
311 // bool_expr_a == bool_expr_b
312 // bool_expr_a != bool_expr_b
Malcolm Parsonsd8851b5d2018-11-27 16:23:39 +0000313 unless(hasParent(binaryOperator(anyOf(
314 boolComparison, boolXor, boolOpAssignment, bitfieldAssignment)))),
315 implicitCastExpr().bind("implicitCastFromBool"),
316 unless(hasParent(bitfieldConstruct)),
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000317 // Check also for nested casts, for example: bool -> int -> float.
318 anyOf(hasParent(implicitCastExpr().bind("furtherImplicitCast")),
Alexander Kornienkoe1331402017-05-16 15:44:42 +0000319 anything()),
320 unless(isInTemplateInstantiation()),
Malcolm Parsonsd8851b5d2018-11-27 16:23:39 +0000321 unless(hasAncestor(functionTemplateDecl()))),
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000322 this);
323}
324
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000325void ImplicitBoolConversionCheck::check(
326 const MatchFinder::MatchResult &Result) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000327 if (const auto *CastToBool =
328 Result.Nodes.getNodeAs<ImplicitCastExpr>("implicitCastToBool")) {
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000329 const auto *Parent = Result.Nodes.getNodeAs<Stmt>("parentStmt");
330 return handleCastToBool(CastToBool, Parent, *Result.Context);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000331 }
332
333 if (const auto *CastFromBool =
334 Result.Nodes.getNodeAs<ImplicitCastExpr>("implicitCastFromBool")) {
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000335 const auto *NextImplicitCast =
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000336 Result.Nodes.getNodeAs<ImplicitCastExpr>("furtherImplicitCast");
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000337 return handleCastFromBool(CastFromBool, NextImplicitCast, *Result.Context);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000338 }
339}
340
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000341void ImplicitBoolConversionCheck::handleCastToBool(const ImplicitCastExpr *Cast,
342 const Stmt *Parent,
343 ASTContext &Context) {
344 if (AllowPointerConditions &&
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000345 (Cast->getCastKind() == CK_PointerToBoolean ||
346 Cast->getCastKind() == CK_MemberPointerToBoolean) &&
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000347 isCastAllowedInCondition(Cast, Context)) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000348 return;
349 }
350
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000351 if (AllowIntegerConditions && Cast->getCastKind() == CK_IntegralToBoolean &&
352 isCastAllowedInCondition(Cast, Context)) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000353 return;
354 }
355
Stephen Kelly43465bf2018-08-09 22:42:26 +0000356 auto Diag = diag(Cast->getBeginLoc(), "implicit conversion %0 -> bool")
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000357 << Cast->getSubExpr()->getType();
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000358
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000359 StringRef EquivalentLiteral =
360 getEquivalentBoolLiteralForExpr(Cast->getSubExpr(), Context);
361 if (!EquivalentLiteral.empty()) {
362 Diag << tooling::fixit::createReplacement(*Cast, EquivalentLiteral);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000363 } else {
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000364 fixGenericExprCastToBool(Diag, Cast, Parent, Context);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000365 }
366}
367
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000368void ImplicitBoolConversionCheck::handleCastFromBool(
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000369 const ImplicitCastExpr *Cast, const ImplicitCastExpr *NextImplicitCast,
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000370 ASTContext &Context) {
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000371 QualType DestType =
372 NextImplicitCast ? NextImplicitCast->getType() : Cast->getType();
Stephen Kelly43465bf2018-08-09 22:42:26 +0000373 auto Diag = diag(Cast->getBeginLoc(), "implicit conversion bool -> %0")
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000374 << DestType;
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000375
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000376 if (const auto *BoolLiteral =
377 dyn_cast<CXXBoolLiteralExpr>(Cast->getSubExpr())) {
378 Diag << tooling::fixit::createReplacement(
379 *Cast, getEquivalentForBoolLiteral(BoolLiteral, DestType, Context));
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000380 } else {
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000381 fixGenericExprCastFromBool(Diag, Cast, Context, DestType.getAsString());
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000382 }
383}
384
Etienne Bergeron456177b2016-05-02 18:00:29 +0000385} // namespace readability
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000386} // namespace tidy
387} // namespace clang