blob: e88c14360db365b1ca6943137f6e5e7c27b1ef50 [file] [log] [blame]
Alexander Kornienkof1a65522017-08-08 14:53:52 +00001//===--- ImplicitBoolConversionCheck.cpp - clang-tidy----------------------===//
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Alexander Kornienkof1a65522017-08-08 14:53:52 +000010#include "ImplicitBoolConversionCheck.h"
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000011#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13#include "clang/Lex/Lexer.h"
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000014#include "clang/Tooling/FixIt.h"
Alexander Kornienko4e001b52017-04-29 12:06:45 +000015#include <queue>
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000016
17using namespace clang::ast_matchers;
18
19namespace clang {
20namespace tidy {
Etienne Bergeron456177b2016-05-02 18:00:29 +000021namespace readability {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000022
23namespace {
24
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000025AST_MATCHER(Stmt, isMacroExpansion) {
26 SourceManager &SM = Finder->getASTContext().getSourceManager();
Stephen Kelly43465bf2018-08-09 22:42:26 +000027 SourceLocation Loc = Node.getBeginLoc();
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000028 return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc);
29}
30
31bool isNULLMacroExpansion(const Stmt *Statement, ASTContext &Context) {
32 SourceManager &SM = Context.getSourceManager();
33 const LangOptions &LO = Context.getLangOpts();
Stephen Kelly43465bf2018-08-09 22:42:26 +000034 SourceLocation Loc = Statement->getBeginLoc();
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000035 return SM.isMacroBodyExpansion(Loc) &&
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000036 Lexer::getImmediateMacroName(Loc, SM, LO) == "NULL";
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000037}
38
39AST_MATCHER(Stmt, isNULLMacroExpansion) {
40 return isNULLMacroExpansion(&Node, Finder->getASTContext());
41}
42
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000043StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
44 QualType Type,
45 ASTContext &Context) {
46 switch (CastExprKind) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000047 case CK_IntegralToBoolean:
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000048 return Type->isUnsignedIntegerType() ? "0u" : "0";
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000049
50 case CK_FloatingToBoolean:
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000051 return Context.hasSameType(Type, Context.FloatTy) ? "0.0f" : "0.0";
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000052
53 case CK_PointerToBoolean:
54 case CK_MemberPointerToBoolean: // Fall-through on purpose.
55 return Context.getLangOpts().CPlusPlus11 ? "nullptr" : "0";
56
57 default:
Benjamin Kramer6d505c02015-10-25 22:03:00 +000058 llvm_unreachable("Unexpected cast kind");
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000059 }
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000060}
61
62bool isUnaryLogicalNotOperator(const Stmt *Statement) {
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000063 const auto *UnaryOperatorExpr = dyn_cast<UnaryOperator>(Statement);
64 return UnaryOperatorExpr && UnaryOperatorExpr->getOpcode() == UO_LNot;
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000065}
66
67bool areParensNeededForOverloadedOperator(OverloadedOperatorKind OperatorKind) {
68 switch (OperatorKind) {
69 case OO_New:
70 case OO_Delete: // Fall-through on purpose.
71 case OO_Array_New:
72 case OO_Array_Delete:
73 case OO_ArrowStar:
74 case OO_Arrow:
75 case OO_Call:
76 case OO_Subscript:
77 return false;
78
79 default:
80 return true;
81 }
82}
83
84bool areParensNeededForStatement(const Stmt *Statement) {
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000085 if (const auto *OperatorCall = dyn_cast<CXXOperatorCallExpr>(Statement)) {
86 return areParensNeededForOverloadedOperator(OperatorCall->getOperator());
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000087 }
88
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000089 return isa<BinaryOperator>(Statement) || isa<UnaryOperator>(Statement);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000090}
91
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000092void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
93 const ImplicitCastExpr *Cast, const Stmt *Parent,
94 ASTContext &Context) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000095 // In case of expressions like (! integer), we should remove the redundant not
96 // operator and use inverted comparison (integer == 0).
97 bool InvertComparison =
Alexander Kornienkocbe8d162017-05-04 15:34:23 +000098 Parent != nullptr && isUnaryLogicalNotOperator(Parent);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +000099 if (InvertComparison) {
Stephen Kelly43465bf2018-08-09 22:42:26 +0000100 SourceLocation ParentStartLoc = Parent->getBeginLoc();
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000101 SourceLocation ParentEndLoc =
Stephen Kelly43465bf2018-08-09 22:42:26 +0000102 cast<UnaryOperator>(Parent)->getSubExpr()->getBeginLoc();
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000103 Diag << FixItHint::CreateRemoval(
104 CharSourceRange::getCharRange(ParentStartLoc, ParentEndLoc));
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000105
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000106 Parent = Context.getParents(*Parent)[0].get<Stmt>();
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000107 }
108
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000109 const Expr *SubExpr = Cast->getSubExpr();
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000110
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000111 bool NeedInnerParens = areParensNeededForStatement(SubExpr);
112 bool NeedOuterParens =
113 Parent != nullptr && areParensNeededForStatement(Parent);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000114
115 std::string StartLocInsertion;
116
117 if (NeedOuterParens) {
118 StartLocInsertion += "(";
119 }
120 if (NeedInnerParens) {
121 StartLocInsertion += "(";
122 }
123
124 if (!StartLocInsertion.empty()) {
Stephen Kelly43465bf2018-08-09 22:42:26 +0000125 Diag << FixItHint::CreateInsertion(Cast->getBeginLoc(), StartLocInsertion);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000126 }
127
128 std::string EndLocInsertion;
129
130 if (NeedInnerParens) {
131 EndLocInsertion += ")";
132 }
133
134 if (InvertComparison) {
135 EndLocInsertion += " == ";
136 } else {
137 EndLocInsertion += " != ";
138 }
139
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000140 EndLocInsertion += getZeroLiteralToCompareWithForType(
141 Cast->getCastKind(), SubExpr->getType(), Context);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000142
143 if (NeedOuterParens) {
144 EndLocInsertion += ")";
145 }
146
147 SourceLocation EndLoc = Lexer::getLocForEndOfToken(
Stephen Kellyc09197e2018-08-09 22:43:02 +0000148 Cast->getEndLoc(), 0, Context.getSourceManager(), Context.getLangOpts());
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000149 Diag << FixItHint::CreateInsertion(EndLoc, EndLocInsertion);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000150}
151
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000152StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression,
153 ASTContext &Context) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000154 if (isNULLMacroExpansion(Expression, Context)) {
155 return "false";
156 }
157
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000158 if (const auto *IntLit = dyn_cast<IntegerLiteral>(Expression)) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000159 return (IntLit->getValue() == 0) ? "false" : "true";
160 }
161
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000162 if (const auto *FloatLit = dyn_cast<FloatingLiteral>(Expression)) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000163 llvm::APFloat FloatLitAbsValue = FloatLit->getValue();
164 FloatLitAbsValue.clearSign();
165 return (FloatLitAbsValue.bitcastToAPInt() == 0) ? "false" : "true";
166 }
167
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000168 if (const auto *CharLit = dyn_cast<CharacterLiteral>(Expression)) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000169 return (CharLit->getValue() == 0) ? "false" : "true";
170 }
171
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000172 if (isa<StringLiteral>(Expression->IgnoreCasts())) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000173 return "true";
174 }
175
176 return StringRef();
177}
178
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000179void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
180 const ImplicitCastExpr *Cast,
181 ASTContext &Context, StringRef OtherType) {
182 const Expr *SubExpr = Cast->getSubExpr();
183 bool NeedParens = !isa<ParenExpr>(SubExpr);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000184
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000185 Diag << FixItHint::CreateInsertion(
Stephen Kelly43465bf2018-08-09 22:42:26 +0000186 Cast->getBeginLoc(),
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000187 (Twine("static_cast<") + OtherType + ">" + (NeedParens ? "(" : ""))
188 .str());
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000189
190 if (NeedParens) {
191 SourceLocation EndLoc = Lexer::getLocForEndOfToken(
Stephen Kellyc09197e2018-08-09 22:43:02 +0000192 Cast->getEndLoc(), 0, Context.getSourceManager(),
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000193 Context.getLangOpts());
194
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000195 Diag << FixItHint::CreateInsertion(EndLoc, ")");
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000196 }
197}
198
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000199StringRef getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
200 QualType DestType, ASTContext &Context) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000201 // Prior to C++11, false literal could be implicitly converted to pointer.
202 if (!Context.getLangOpts().CPlusPlus11 &&
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000203 (DestType->isPointerType() || DestType->isMemberPointerType()) &&
204 BoolLiteral->getValue() == false) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000205 return "0";
206 }
207
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000208 if (DestType->isFloatingType()) {
209 if (Context.hasSameType(DestType, Context.FloatTy)) {
210 return BoolLiteral->getValue() ? "1.0f" : "0.0f";
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000211 }
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000212 return BoolLiteral->getValue() ? "1.0" : "0.0";
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000213 }
214
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000215 if (DestType->isUnsignedIntegerType()) {
216 return BoolLiteral->getValue() ? "1u" : "0u";
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000217 }
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000218 return BoolLiteral->getValue() ? "1" : "0";
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000219}
220
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000221bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000222 ASTContext &Context) {
Alexander Kornienko4e001b52017-04-29 12:06:45 +0000223 std::queue<const Stmt *> Q;
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000224 Q.push(Cast);
Alexander Kornienko4e001b52017-04-29 12:06:45 +0000225 while (!Q.empty()) {
226 for (const auto &N : Context.getParents(*Q.front())) {
227 const Stmt *S = N.get<Stmt>();
228 if (!S)
229 return false;
Alexander Kornienkof89e0bb2017-05-08 15:22:09 +0000230 if (isa<IfStmt>(S) || isa<ConditionalOperator>(S) || isa<ForStmt>(S) ||
231 isa<WhileStmt>(S) || isa<BinaryConditionalOperator>(S))
Alexander Kornienko4e001b52017-04-29 12:06:45 +0000232 return true;
233 if (isa<ParenExpr>(S) || isa<ImplicitCastExpr>(S) ||
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000234 isUnaryLogicalNotOperator(S) ||
Alexander Kornienko4e001b52017-04-29 12:06:45 +0000235 (isa<BinaryOperator>(S) && cast<BinaryOperator>(S)->isLogicalOp())) {
236 Q.push(S);
237 } else {
238 return false;
239 }
240 }
241 Q.pop();
242 }
243 return false;
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000244}
245
246} // anonymous namespace
247
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000248ImplicitBoolConversionCheck::ImplicitBoolConversionCheck(
249 StringRef Name, ClangTidyContext *Context)
Haojian Wu80c1c9f2016-08-16 11:15:05 +0000250 : ClangTidyCheck(Name, Context),
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000251 AllowIntegerConditions(Options.get("AllowIntegerConditions", false)),
252 AllowPointerConditions(Options.get("AllowPointerConditions", false)) {}
Haojian Wu80c1c9f2016-08-16 11:15:05 +0000253
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000254void ImplicitBoolConversionCheck::storeOptions(
255 ClangTidyOptions::OptionMap &Opts) {
256 Options.store(Opts, "AllowIntegerConditions", AllowIntegerConditions);
257 Options.store(Opts, "AllowPointerConditions", AllowPointerConditions);
Haojian Wu80c1c9f2016-08-16 11:15:05 +0000258}
259
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000260void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000261 // This check doesn't make much sense if we run it on language without
262 // built-in bool support.
263 if (!getLangOpts().Bool) {
264 return;
265 }
266
Alexander Kornienkoe1331402017-05-16 15:44:42 +0000267 auto exceptionCases =
Alexander Kornienko50de3ad2017-05-16 16:40:46 +0000268 expr(anyOf(allOf(isMacroExpansion(), unless(isNULLMacroExpansion())),
269 hasParent(explicitCastExpr())));
Alexander Kornienkoc6ba6fc2017-05-04 16:06:08 +0000270 auto implicitCastFromBool = implicitCastExpr(
Alexander Kornienkoc6ba6fc2017-05-04 16:06:08 +0000271 anyOf(hasCastKind(CK_IntegralCast), hasCastKind(CK_IntegralToFloating),
272 // Prior to C++11 cast from bool literal to pointer was allowed.
273 allOf(anyOf(hasCastKind(CK_NullToPointer),
274 hasCastKind(CK_NullToMemberPointer)),
275 hasSourceExpression(cxxBoolLiteral()))),
Alexander Kornienko50de3ad2017-05-16 16:40:46 +0000276 hasSourceExpression(expr(hasType(booleanType()))),
277 unless(exceptionCases));
Alexander Kornienkoc6ba6fc2017-05-04 16:06:08 +0000278 auto boolXor =
279 binaryOperator(hasOperatorName("^"), hasLHS(implicitCastFromBool),
280 hasRHS(implicitCastFromBool));
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000281 Finder->addMatcher(
282 implicitCastExpr(
Alexander Kornienko50de3ad2017-05-16 16:40:46 +0000283 anyOf(hasCastKind(CK_IntegralToBoolean),
284 hasCastKind(CK_FloatingToBoolean),
285 hasCastKind(CK_PointerToBoolean),
286 hasCastKind(CK_MemberPointerToBoolean)),
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000287 // Exclude case of using if or while statements with variable
288 // declaration, e.g.:
289 // if (int var = functionCall()) {}
290 unless(
291 hasParent(stmt(anyOf(ifStmt(), whileStmt()), has(declStmt())))),
Alexander Kornienko50de3ad2017-05-16 16:40:46 +0000292 // Exclude cases common to implicit cast to and from bool.
293 unless(exceptionCases), unless(has(boolXor)),
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000294 // Retrive also parent statement, to check if we need additional
295 // parens in replacement.
Alexander Kornienkoe1331402017-05-16 15:44:42 +0000296 anyOf(hasParent(stmt().bind("parentStmt")), anything()),
297 unless(isInTemplateInstantiation()),
298 unless(hasAncestor(functionTemplateDecl())))
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000299 .bind("implicitCastToBool"),
300 this);
301
Alexander Kornienkob92cb072017-05-04 15:34:31 +0000302 auto boolComparison = binaryOperator(
303 anyOf(hasOperatorName("=="), hasOperatorName("!=")),
304 hasLHS(implicitCastFromBool), hasRHS(implicitCastFromBool));
Alexander Kornienkoc6ba6fc2017-05-04 16:06:08 +0000305 auto boolOpAssignment =
306 binaryOperator(anyOf(hasOperatorName("|="), hasOperatorName("&=")),
307 hasLHS(expr(hasType(booleanType()))));
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000308 Finder->addMatcher(
309 implicitCastExpr(
Alexander Kornienkob92cb072017-05-04 15:34:31 +0000310 implicitCastFromBool,
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000311 // Exclude comparisons of bools, as they are always cast to integers
312 // in such context:
313 // bool_expr_a == bool_expr_b
314 // bool_expr_a != bool_expr_b
Alexander Kornienkoc6ba6fc2017-05-04 16:06:08 +0000315 unless(hasParent(binaryOperator(
316 anyOf(boolComparison, boolXor, boolOpAssignment)))),
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()),
321 unless(hasAncestor(functionTemplateDecl())))
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000322 .bind("implicitCastFromBool"),
323 this);
324}
325
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000326void ImplicitBoolConversionCheck::check(
327 const MatchFinder::MatchResult &Result) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000328 if (const auto *CastToBool =
329 Result.Nodes.getNodeAs<ImplicitCastExpr>("implicitCastToBool")) {
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000330 const auto *Parent = Result.Nodes.getNodeAs<Stmt>("parentStmt");
331 return handleCastToBool(CastToBool, Parent, *Result.Context);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000332 }
333
334 if (const auto *CastFromBool =
335 Result.Nodes.getNodeAs<ImplicitCastExpr>("implicitCastFromBool")) {
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000336 const auto *NextImplicitCast =
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000337 Result.Nodes.getNodeAs<ImplicitCastExpr>("furtherImplicitCast");
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000338 return handleCastFromBool(CastFromBool, NextImplicitCast, *Result.Context);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000339 }
340}
341
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000342void ImplicitBoolConversionCheck::handleCastToBool(const ImplicitCastExpr *Cast,
343 const Stmt *Parent,
344 ASTContext &Context) {
345 if (AllowPointerConditions &&
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000346 (Cast->getCastKind() == CK_PointerToBoolean ||
347 Cast->getCastKind() == CK_MemberPointerToBoolean) &&
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000348 isCastAllowedInCondition(Cast, Context)) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000349 return;
350 }
351
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000352 if (AllowIntegerConditions && Cast->getCastKind() == CK_IntegralToBoolean &&
353 isCastAllowedInCondition(Cast, Context)) {
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000354 return;
355 }
356
Stephen Kelly43465bf2018-08-09 22:42:26 +0000357 auto Diag = diag(Cast->getBeginLoc(), "implicit conversion %0 -> bool")
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000358 << Cast->getSubExpr()->getType();
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000359
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000360 StringRef EquivalentLiteral =
361 getEquivalentBoolLiteralForExpr(Cast->getSubExpr(), Context);
362 if (!EquivalentLiteral.empty()) {
363 Diag << tooling::fixit::createReplacement(*Cast, EquivalentLiteral);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000364 } else {
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000365 fixGenericExprCastToBool(Diag, Cast, Parent, Context);
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000366 }
367}
368
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000369void ImplicitBoolConversionCheck::handleCastFromBool(
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000370 const ImplicitCastExpr *Cast, const ImplicitCastExpr *NextImplicitCast,
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000371 ASTContext &Context) {
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000372 QualType DestType =
373 NextImplicitCast ? NextImplicitCast->getType() : Cast->getType();
Stephen Kelly43465bf2018-08-09 22:42:26 +0000374 auto Diag = diag(Cast->getBeginLoc(), "implicit conversion bool -> %0")
Alexander Kornienkof1a65522017-08-08 14:53:52 +0000375 << DestType;
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000376
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000377 if (const auto *BoolLiteral =
378 dyn_cast<CXXBoolLiteralExpr>(Cast->getSubExpr())) {
379 Diag << tooling::fixit::createReplacement(
380 *Cast, getEquivalentForBoolLiteral(BoolLiteral, DestType, Context));
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000381 } else {
Alexander Kornienkocbe8d162017-05-04 15:34:23 +0000382 fixGenericExprCastFromBool(Diag, Cast, Context, DestType.getAsString());
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000383 }
384}
385
Etienne Bergeron456177b2016-05-02 18:00:29 +0000386} // namespace readability
Piotr Dziwinski7f1b5092015-10-25 15:31:25 +0000387} // namespace tidy
388} // namespace clang