annotate clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp @ 236:c4bab56944e8 llvm-original

LLVM 16
author kono
date Wed, 09 Nov 2022 17:45:10 +0900
parents 79ff65ed7e25
children 1f2b6ac9f198
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===--- ImplicitBoolConversionCheck.cpp - clang-tidy----------------------===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8
anatofuz
parents:
diff changeset
9 #include "ImplicitBoolConversionCheck.h"
anatofuz
parents:
diff changeset
10 #include "clang/AST/ASTContext.h"
anatofuz
parents:
diff changeset
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
anatofuz
parents:
diff changeset
12 #include "clang/Lex/Lexer.h"
anatofuz
parents:
diff changeset
13 #include "clang/Tooling/FixIt.h"
anatofuz
parents:
diff changeset
14 #include <queue>
anatofuz
parents:
diff changeset
15
anatofuz
parents:
diff changeset
16 using namespace clang::ast_matchers;
anatofuz
parents:
diff changeset
17
anatofuz
parents:
diff changeset
18 namespace clang {
anatofuz
parents:
diff changeset
19 namespace tidy {
anatofuz
parents:
diff changeset
20 namespace readability {
anatofuz
parents:
diff changeset
21
anatofuz
parents:
diff changeset
22 namespace {
anatofuz
parents:
diff changeset
23
anatofuz
parents:
diff changeset
24 AST_MATCHER(Stmt, isMacroExpansion) {
anatofuz
parents:
diff changeset
25 SourceManager &SM = Finder->getASTContext().getSourceManager();
anatofuz
parents:
diff changeset
26 SourceLocation Loc = Node.getBeginLoc();
anatofuz
parents:
diff changeset
27 return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc);
anatofuz
parents:
diff changeset
28 }
anatofuz
parents:
diff changeset
29
anatofuz
parents:
diff changeset
30 bool isNULLMacroExpansion(const Stmt *Statement, ASTContext &Context) {
anatofuz
parents:
diff changeset
31 SourceManager &SM = Context.getSourceManager();
anatofuz
parents:
diff changeset
32 const LangOptions &LO = Context.getLangOpts();
anatofuz
parents:
diff changeset
33 SourceLocation Loc = Statement->getBeginLoc();
anatofuz
parents:
diff changeset
34 return SM.isMacroBodyExpansion(Loc) &&
anatofuz
parents:
diff changeset
35 Lexer::getImmediateMacroName(Loc, SM, LO) == "NULL";
anatofuz
parents:
diff changeset
36 }
anatofuz
parents:
diff changeset
37
anatofuz
parents:
diff changeset
38 AST_MATCHER(Stmt, isNULLMacroExpansion) {
anatofuz
parents:
diff changeset
39 return isNULLMacroExpansion(&Node, Finder->getASTContext());
anatofuz
parents:
diff changeset
40 }
anatofuz
parents:
diff changeset
41
anatofuz
parents:
diff changeset
42 StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
anatofuz
parents:
diff changeset
43 QualType Type,
anatofuz
parents:
diff changeset
44 ASTContext &Context) {
anatofuz
parents:
diff changeset
45 switch (CastExprKind) {
anatofuz
parents:
diff changeset
46 case CK_IntegralToBoolean:
anatofuz
parents:
diff changeset
47 return Type->isUnsignedIntegerType() ? "0u" : "0";
anatofuz
parents:
diff changeset
48
anatofuz
parents:
diff changeset
49 case CK_FloatingToBoolean:
anatofuz
parents:
diff changeset
50 return Context.hasSameType(Type, Context.FloatTy) ? "0.0f" : "0.0";
anatofuz
parents:
diff changeset
51
anatofuz
parents:
diff changeset
52 case CK_PointerToBoolean:
anatofuz
parents:
diff changeset
53 case CK_MemberPointerToBoolean: // Fall-through on purpose.
anatofuz
parents:
diff changeset
54 return Context.getLangOpts().CPlusPlus11 ? "nullptr" : "0";
anatofuz
parents:
diff changeset
55
anatofuz
parents:
diff changeset
56 default:
anatofuz
parents:
diff changeset
57 llvm_unreachable("Unexpected cast kind");
anatofuz
parents:
diff changeset
58 }
anatofuz
parents:
diff changeset
59 }
anatofuz
parents:
diff changeset
60
anatofuz
parents:
diff changeset
61 bool isUnaryLogicalNotOperator(const Stmt *Statement) {
anatofuz
parents:
diff changeset
62 const auto *UnaryOperatorExpr = dyn_cast<UnaryOperator>(Statement);
anatofuz
parents:
diff changeset
63 return UnaryOperatorExpr && UnaryOperatorExpr->getOpcode() == UO_LNot;
anatofuz
parents:
diff changeset
64 }
anatofuz
parents:
diff changeset
65
anatofuz
parents:
diff changeset
66 bool areParensNeededForOverloadedOperator(OverloadedOperatorKind OperatorKind) {
anatofuz
parents:
diff changeset
67 switch (OperatorKind) {
anatofuz
parents:
diff changeset
68 case OO_New:
anatofuz
parents:
diff changeset
69 case OO_Delete: // Fall-through on purpose.
anatofuz
parents:
diff changeset
70 case OO_Array_New:
anatofuz
parents:
diff changeset
71 case OO_Array_Delete:
anatofuz
parents:
diff changeset
72 case OO_ArrowStar:
anatofuz
parents:
diff changeset
73 case OO_Arrow:
anatofuz
parents:
diff changeset
74 case OO_Call:
anatofuz
parents:
diff changeset
75 case OO_Subscript:
anatofuz
parents:
diff changeset
76 return false;
anatofuz
parents:
diff changeset
77
anatofuz
parents:
diff changeset
78 default:
anatofuz
parents:
diff changeset
79 return true;
anatofuz
parents:
diff changeset
80 }
anatofuz
parents:
diff changeset
81 }
anatofuz
parents:
diff changeset
82
anatofuz
parents:
diff changeset
83 bool areParensNeededForStatement(const Stmt *Statement) {
anatofuz
parents:
diff changeset
84 if (const auto *OperatorCall = dyn_cast<CXXOperatorCallExpr>(Statement)) {
anatofuz
parents:
diff changeset
85 return areParensNeededForOverloadedOperator(OperatorCall->getOperator());
anatofuz
parents:
diff changeset
86 }
anatofuz
parents:
diff changeset
87
anatofuz
parents:
diff changeset
88 return isa<BinaryOperator>(Statement) || isa<UnaryOperator>(Statement);
anatofuz
parents:
diff changeset
89 }
anatofuz
parents:
diff changeset
90
anatofuz
parents:
diff changeset
91 void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
anatofuz
parents:
diff changeset
92 const ImplicitCastExpr *Cast, const Stmt *Parent,
anatofuz
parents:
diff changeset
93 ASTContext &Context) {
anatofuz
parents:
diff changeset
94 // In case of expressions like (! integer), we should remove the redundant not
anatofuz
parents:
diff changeset
95 // operator and use inverted comparison (integer == 0).
anatofuz
parents:
diff changeset
96 bool InvertComparison =
anatofuz
parents:
diff changeset
97 Parent != nullptr && isUnaryLogicalNotOperator(Parent);
anatofuz
parents:
diff changeset
98 if (InvertComparison) {
anatofuz
parents:
diff changeset
99 SourceLocation ParentStartLoc = Parent->getBeginLoc();
anatofuz
parents:
diff changeset
100 SourceLocation ParentEndLoc =
anatofuz
parents:
diff changeset
101 cast<UnaryOperator>(Parent)->getSubExpr()->getBeginLoc();
anatofuz
parents:
diff changeset
102 Diag << FixItHint::CreateRemoval(
anatofuz
parents:
diff changeset
103 CharSourceRange::getCharRange(ParentStartLoc, ParentEndLoc));
anatofuz
parents:
diff changeset
104
anatofuz
parents:
diff changeset
105 Parent = Context.getParents(*Parent)[0].get<Stmt>();
anatofuz
parents:
diff changeset
106 }
anatofuz
parents:
diff changeset
107
anatofuz
parents:
diff changeset
108 const Expr *SubExpr = Cast->getSubExpr();
anatofuz
parents:
diff changeset
109
anatofuz
parents:
diff changeset
110 bool NeedInnerParens = areParensNeededForStatement(SubExpr);
anatofuz
parents:
diff changeset
111 bool NeedOuterParens =
anatofuz
parents:
diff changeset
112 Parent != nullptr && areParensNeededForStatement(Parent);
anatofuz
parents:
diff changeset
113
anatofuz
parents:
diff changeset
114 std::string StartLocInsertion;
anatofuz
parents:
diff changeset
115
anatofuz
parents:
diff changeset
116 if (NeedOuterParens) {
anatofuz
parents:
diff changeset
117 StartLocInsertion += "(";
anatofuz
parents:
diff changeset
118 }
anatofuz
parents:
diff changeset
119 if (NeedInnerParens) {
anatofuz
parents:
diff changeset
120 StartLocInsertion += "(";
anatofuz
parents:
diff changeset
121 }
anatofuz
parents:
diff changeset
122
anatofuz
parents:
diff changeset
123 if (!StartLocInsertion.empty()) {
anatofuz
parents:
diff changeset
124 Diag << FixItHint::CreateInsertion(Cast->getBeginLoc(), StartLocInsertion);
anatofuz
parents:
diff changeset
125 }
anatofuz
parents:
diff changeset
126
anatofuz
parents:
diff changeset
127 std::string EndLocInsertion;
anatofuz
parents:
diff changeset
128
anatofuz
parents:
diff changeset
129 if (NeedInnerParens) {
anatofuz
parents:
diff changeset
130 EndLocInsertion += ")";
anatofuz
parents:
diff changeset
131 }
anatofuz
parents:
diff changeset
132
anatofuz
parents:
diff changeset
133 if (InvertComparison) {
anatofuz
parents:
diff changeset
134 EndLocInsertion += " == ";
anatofuz
parents:
diff changeset
135 } else {
anatofuz
parents:
diff changeset
136 EndLocInsertion += " != ";
anatofuz
parents:
diff changeset
137 }
anatofuz
parents:
diff changeset
138
anatofuz
parents:
diff changeset
139 EndLocInsertion += getZeroLiteralToCompareWithForType(
anatofuz
parents:
diff changeset
140 Cast->getCastKind(), SubExpr->getType(), Context);
anatofuz
parents:
diff changeset
141
anatofuz
parents:
diff changeset
142 if (NeedOuterParens) {
anatofuz
parents:
diff changeset
143 EndLocInsertion += ")";
anatofuz
parents:
diff changeset
144 }
anatofuz
parents:
diff changeset
145
anatofuz
parents:
diff changeset
146 SourceLocation EndLoc = Lexer::getLocForEndOfToken(
anatofuz
parents:
diff changeset
147 Cast->getEndLoc(), 0, Context.getSourceManager(), Context.getLangOpts());
anatofuz
parents:
diff changeset
148 Diag << FixItHint::CreateInsertion(EndLoc, EndLocInsertion);
anatofuz
parents:
diff changeset
149 }
anatofuz
parents:
diff changeset
150
anatofuz
parents:
diff changeset
151 StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression,
anatofuz
parents:
diff changeset
152 ASTContext &Context) {
anatofuz
parents:
diff changeset
153 if (isNULLMacroExpansion(Expression, Context)) {
anatofuz
parents:
diff changeset
154 return "false";
anatofuz
parents:
diff changeset
155 }
anatofuz
parents:
diff changeset
156
anatofuz
parents:
diff changeset
157 if (const auto *IntLit = dyn_cast<IntegerLiteral>(Expression)) {
anatofuz
parents:
diff changeset
158 return (IntLit->getValue() == 0) ? "false" : "true";
anatofuz
parents:
diff changeset
159 }
anatofuz
parents:
diff changeset
160
anatofuz
parents:
diff changeset
161 if (const auto *FloatLit = dyn_cast<FloatingLiteral>(Expression)) {
anatofuz
parents:
diff changeset
162 llvm::APFloat FloatLitAbsValue = FloatLit->getValue();
anatofuz
parents:
diff changeset
163 FloatLitAbsValue.clearSign();
anatofuz
parents:
diff changeset
164 return (FloatLitAbsValue.bitcastToAPInt() == 0) ? "false" : "true";
anatofuz
parents:
diff changeset
165 }
anatofuz
parents:
diff changeset
166
anatofuz
parents:
diff changeset
167 if (const auto *CharLit = dyn_cast<CharacterLiteral>(Expression)) {
anatofuz
parents:
diff changeset
168 return (CharLit->getValue() == 0) ? "false" : "true";
anatofuz
parents:
diff changeset
169 }
anatofuz
parents:
diff changeset
170
anatofuz
parents:
diff changeset
171 if (isa<StringLiteral>(Expression->IgnoreCasts())) {
anatofuz
parents:
diff changeset
172 return "true";
anatofuz
parents:
diff changeset
173 }
anatofuz
parents:
diff changeset
174
anatofuz
parents:
diff changeset
175 return StringRef();
anatofuz
parents:
diff changeset
176 }
anatofuz
parents:
diff changeset
177
anatofuz
parents:
diff changeset
178 void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
anatofuz
parents:
diff changeset
179 const ImplicitCastExpr *Cast,
anatofuz
parents:
diff changeset
180 ASTContext &Context, StringRef OtherType) {
anatofuz
parents:
diff changeset
181 const Expr *SubExpr = Cast->getSubExpr();
anatofuz
parents:
diff changeset
182 bool NeedParens = !isa<ParenExpr>(SubExpr);
anatofuz
parents:
diff changeset
183
anatofuz
parents:
diff changeset
184 Diag << FixItHint::CreateInsertion(
anatofuz
parents:
diff changeset
185 Cast->getBeginLoc(),
anatofuz
parents:
diff changeset
186 (Twine("static_cast<") + OtherType + ">" + (NeedParens ? "(" : ""))
anatofuz
parents:
diff changeset
187 .str());
anatofuz
parents:
diff changeset
188
anatofuz
parents:
diff changeset
189 if (NeedParens) {
anatofuz
parents:
diff changeset
190 SourceLocation EndLoc = Lexer::getLocForEndOfToken(
anatofuz
parents:
diff changeset
191 Cast->getEndLoc(), 0, Context.getSourceManager(),
anatofuz
parents:
diff changeset
192 Context.getLangOpts());
anatofuz
parents:
diff changeset
193
anatofuz
parents:
diff changeset
194 Diag << FixItHint::CreateInsertion(EndLoc, ")");
anatofuz
parents:
diff changeset
195 }
anatofuz
parents:
diff changeset
196 }
anatofuz
parents:
diff changeset
197
anatofuz
parents:
diff changeset
198 StringRef getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
anatofuz
parents:
diff changeset
199 QualType DestType, ASTContext &Context) {
anatofuz
parents:
diff changeset
200 // Prior to C++11, false literal could be implicitly converted to pointer.
anatofuz
parents:
diff changeset
201 if (!Context.getLangOpts().CPlusPlus11 &&
anatofuz
parents:
diff changeset
202 (DestType->isPointerType() || DestType->isMemberPointerType()) &&
anatofuz
parents:
diff changeset
203 BoolLiteral->getValue() == false) {
anatofuz
parents:
diff changeset
204 return "0";
anatofuz
parents:
diff changeset
205 }
anatofuz
parents:
diff changeset
206
anatofuz
parents:
diff changeset
207 if (DestType->isFloatingType()) {
anatofuz
parents:
diff changeset
208 if (Context.hasSameType(DestType, Context.FloatTy)) {
anatofuz
parents:
diff changeset
209 return BoolLiteral->getValue() ? "1.0f" : "0.0f";
anatofuz
parents:
diff changeset
210 }
anatofuz
parents:
diff changeset
211 return BoolLiteral->getValue() ? "1.0" : "0.0";
anatofuz
parents:
diff changeset
212 }
anatofuz
parents:
diff changeset
213
anatofuz
parents:
diff changeset
214 if (DestType->isUnsignedIntegerType()) {
anatofuz
parents:
diff changeset
215 return BoolLiteral->getValue() ? "1u" : "0u";
anatofuz
parents:
diff changeset
216 }
anatofuz
parents:
diff changeset
217 return BoolLiteral->getValue() ? "1" : "0";
anatofuz
parents:
diff changeset
218 }
anatofuz
parents:
diff changeset
219
anatofuz
parents:
diff changeset
220 bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
anatofuz
parents:
diff changeset
221 ASTContext &Context) {
anatofuz
parents:
diff changeset
222 std::queue<const Stmt *> Q;
anatofuz
parents:
diff changeset
223 Q.push(Cast);
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
224
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
225 TraversalKindScope RAII(Context, TK_AsIs);
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
226
150
anatofuz
parents:
diff changeset
227 while (!Q.empty()) {
anatofuz
parents:
diff changeset
228 for (const auto &N : Context.getParents(*Q.front())) {
anatofuz
parents:
diff changeset
229 const Stmt *S = N.get<Stmt>();
anatofuz
parents:
diff changeset
230 if (!S)
anatofuz
parents:
diff changeset
231 return false;
anatofuz
parents:
diff changeset
232 if (isa<IfStmt>(S) || isa<ConditionalOperator>(S) || isa<ForStmt>(S) ||
anatofuz
parents:
diff changeset
233 isa<WhileStmt>(S) || isa<BinaryConditionalOperator>(S))
anatofuz
parents:
diff changeset
234 return true;
anatofuz
parents:
diff changeset
235 if (isa<ParenExpr>(S) || isa<ImplicitCastExpr>(S) ||
anatofuz
parents:
diff changeset
236 isUnaryLogicalNotOperator(S) ||
anatofuz
parents:
diff changeset
237 (isa<BinaryOperator>(S) && cast<BinaryOperator>(S)->isLogicalOp())) {
anatofuz
parents:
diff changeset
238 Q.push(S);
anatofuz
parents:
diff changeset
239 } else {
anatofuz
parents:
diff changeset
240 return false;
anatofuz
parents:
diff changeset
241 }
anatofuz
parents:
diff changeset
242 }
anatofuz
parents:
diff changeset
243 Q.pop();
anatofuz
parents:
diff changeset
244 }
anatofuz
parents:
diff changeset
245 return false;
anatofuz
parents:
diff changeset
246 }
anatofuz
parents:
diff changeset
247
anatofuz
parents:
diff changeset
248 } // anonymous namespace
anatofuz
parents:
diff changeset
249
anatofuz
parents:
diff changeset
250 ImplicitBoolConversionCheck::ImplicitBoolConversionCheck(
anatofuz
parents:
diff changeset
251 StringRef Name, ClangTidyContext *Context)
anatofuz
parents:
diff changeset
252 : ClangTidyCheck(Name, Context),
anatofuz
parents:
diff changeset
253 AllowIntegerConditions(Options.get("AllowIntegerConditions", false)),
anatofuz
parents:
diff changeset
254 AllowPointerConditions(Options.get("AllowPointerConditions", false)) {}
anatofuz
parents:
diff changeset
255
anatofuz
parents:
diff changeset
256 void ImplicitBoolConversionCheck::storeOptions(
anatofuz
parents:
diff changeset
257 ClangTidyOptions::OptionMap &Opts) {
anatofuz
parents:
diff changeset
258 Options.store(Opts, "AllowIntegerConditions", AllowIntegerConditions);
anatofuz
parents:
diff changeset
259 Options.store(Opts, "AllowPointerConditions", AllowPointerConditions);
anatofuz
parents:
diff changeset
260 }
anatofuz
parents:
diff changeset
261
anatofuz
parents:
diff changeset
262 void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) {
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
263 auto ExceptionCases =
150
anatofuz
parents:
diff changeset
264 expr(anyOf(allOf(isMacroExpansion(), unless(isNULLMacroExpansion())),
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
265 has(ignoringImplicit(
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
266 memberExpr(hasDeclaration(fieldDecl(hasBitWidth(1)))))),
150
anatofuz
parents:
diff changeset
267 hasParent(explicitCastExpr())));
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
268 auto ImplicitCastFromBool = implicitCastExpr(
150
anatofuz
parents:
diff changeset
269 anyOf(hasCastKind(CK_IntegralCast), hasCastKind(CK_IntegralToFloating),
anatofuz
parents:
diff changeset
270 // Prior to C++11 cast from bool literal to pointer was allowed.
anatofuz
parents:
diff changeset
271 allOf(anyOf(hasCastKind(CK_NullToPointer),
anatofuz
parents:
diff changeset
272 hasCastKind(CK_NullToMemberPointer)),
anatofuz
parents:
diff changeset
273 hasSourceExpression(cxxBoolLiteral()))),
anatofuz
parents:
diff changeset
274 hasSourceExpression(expr(hasType(booleanType()))),
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
275 unless(ExceptionCases));
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
276 auto BoolXor =
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
277 binaryOperator(hasOperatorName("^"), hasLHS(ImplicitCastFromBool),
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
278 hasRHS(ImplicitCastFromBool));
150
anatofuz
parents:
diff changeset
279 Finder->addMatcher(
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
280 traverse(TK_AsIs,
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
281 implicitCastExpr(
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
282 anyOf(hasCastKind(CK_IntegralToBoolean),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
283 hasCastKind(CK_FloatingToBoolean),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
284 hasCastKind(CK_PointerToBoolean),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
285 hasCastKind(CK_MemberPointerToBoolean)),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
286 // Exclude case of using if or while statements with variable
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
287 // declaration, e.g.:
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
288 // if (int var = functionCall()) {}
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
289 unless(hasParent(
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
290 stmt(anyOf(ifStmt(), whileStmt()), has(declStmt())))),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
291 // Exclude cases common to implicit cast to and from bool.
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
292 unless(ExceptionCases), unless(has(BoolXor)),
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
293 // Retrieve also parent statement, to check if we need
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
294 // additional parens in replacement.
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
295 anyOf(hasParent(stmt().bind("parentStmt")), anything()),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
296 unless(isInTemplateInstantiation()),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
297 unless(hasAncestor(functionTemplateDecl())))
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
298 .bind("implicitCastToBool")),
150
anatofuz
parents:
diff changeset
299 this);
anatofuz
parents:
diff changeset
300
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
301 auto BoolComparison = binaryOperator(hasAnyOperatorName("==", "!="),
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
302 hasLHS(ImplicitCastFromBool),
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
303 hasRHS(ImplicitCastFromBool));
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
304 auto BoolOpAssignment = binaryOperator(hasAnyOperatorName("|=", "&="),
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
305 hasLHS(expr(hasType(booleanType()))));
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
306 auto BitfieldAssignment = binaryOperator(
150
anatofuz
parents:
diff changeset
307 hasLHS(memberExpr(hasDeclaration(fieldDecl(hasBitWidth(1))))));
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
308 auto BitfieldConstruct = cxxConstructorDecl(hasDescendant(cxxCtorInitializer(
150
anatofuz
parents:
diff changeset
309 withInitializer(equalsBoundNode("implicitCastFromBool")),
anatofuz
parents:
diff changeset
310 forField(hasBitWidth(1)))));
anatofuz
parents:
diff changeset
311 Finder->addMatcher(
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
312 traverse(
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
313 TK_AsIs,
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
314 implicitCastExpr(
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
315 ImplicitCastFromBool,
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
316 // Exclude comparisons of bools, as they are always cast to
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
317 // integers in such context:
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
318 // bool_expr_a == bool_expr_b
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
319 // bool_expr_a != bool_expr_b
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
320 unless(hasParent(
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
321 binaryOperator(anyOf(BoolComparison, BoolXor,
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
322 BoolOpAssignment, BitfieldAssignment)))),
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
323 implicitCastExpr().bind("implicitCastFromBool"),
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
324 unless(hasParent(BitfieldConstruct)),
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
325 // Check also for nested casts, for example: bool -> int -> float.
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
326 anyOf(hasParent(implicitCastExpr().bind("furtherImplicitCast")),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
327 anything()),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
328 unless(isInTemplateInstantiation()),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
329 unless(hasAncestor(functionTemplateDecl())))),
150
anatofuz
parents:
diff changeset
330 this);
anatofuz
parents:
diff changeset
331 }
anatofuz
parents:
diff changeset
332
anatofuz
parents:
diff changeset
333 void ImplicitBoolConversionCheck::check(
anatofuz
parents:
diff changeset
334 const MatchFinder::MatchResult &Result) {
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
335
150
anatofuz
parents:
diff changeset
336 if (const auto *CastToBool =
anatofuz
parents:
diff changeset
337 Result.Nodes.getNodeAs<ImplicitCastExpr>("implicitCastToBool")) {
anatofuz
parents:
diff changeset
338 const auto *Parent = Result.Nodes.getNodeAs<Stmt>("parentStmt");
anatofuz
parents:
diff changeset
339 return handleCastToBool(CastToBool, Parent, *Result.Context);
anatofuz
parents:
diff changeset
340 }
anatofuz
parents:
diff changeset
341
anatofuz
parents:
diff changeset
342 if (const auto *CastFromBool =
anatofuz
parents:
diff changeset
343 Result.Nodes.getNodeAs<ImplicitCastExpr>("implicitCastFromBool")) {
anatofuz
parents:
diff changeset
344 const auto *NextImplicitCast =
anatofuz
parents:
diff changeset
345 Result.Nodes.getNodeAs<ImplicitCastExpr>("furtherImplicitCast");
anatofuz
parents:
diff changeset
346 return handleCastFromBool(CastFromBool, NextImplicitCast, *Result.Context);
anatofuz
parents:
diff changeset
347 }
anatofuz
parents:
diff changeset
348 }
anatofuz
parents:
diff changeset
349
anatofuz
parents:
diff changeset
350 void ImplicitBoolConversionCheck::handleCastToBool(const ImplicitCastExpr *Cast,
anatofuz
parents:
diff changeset
351 const Stmt *Parent,
anatofuz
parents:
diff changeset
352 ASTContext &Context) {
anatofuz
parents:
diff changeset
353 if (AllowPointerConditions &&
anatofuz
parents:
diff changeset
354 (Cast->getCastKind() == CK_PointerToBoolean ||
anatofuz
parents:
diff changeset
355 Cast->getCastKind() == CK_MemberPointerToBoolean) &&
anatofuz
parents:
diff changeset
356 isCastAllowedInCondition(Cast, Context)) {
anatofuz
parents:
diff changeset
357 return;
anatofuz
parents:
diff changeset
358 }
anatofuz
parents:
diff changeset
359
anatofuz
parents:
diff changeset
360 if (AllowIntegerConditions && Cast->getCastKind() == CK_IntegralToBoolean &&
anatofuz
parents:
diff changeset
361 isCastAllowedInCondition(Cast, Context)) {
anatofuz
parents:
diff changeset
362 return;
anatofuz
parents:
diff changeset
363 }
anatofuz
parents:
diff changeset
364
anatofuz
parents:
diff changeset
365 auto Diag = diag(Cast->getBeginLoc(), "implicit conversion %0 -> bool")
anatofuz
parents:
diff changeset
366 << Cast->getSubExpr()->getType();
anatofuz
parents:
diff changeset
367
anatofuz
parents:
diff changeset
368 StringRef EquivalentLiteral =
anatofuz
parents:
diff changeset
369 getEquivalentBoolLiteralForExpr(Cast->getSubExpr(), Context);
anatofuz
parents:
diff changeset
370 if (!EquivalentLiteral.empty()) {
anatofuz
parents:
diff changeset
371 Diag << tooling::fixit::createReplacement(*Cast, EquivalentLiteral);
anatofuz
parents:
diff changeset
372 } else {
anatofuz
parents:
diff changeset
373 fixGenericExprCastToBool(Diag, Cast, Parent, Context);
anatofuz
parents:
diff changeset
374 }
anatofuz
parents:
diff changeset
375 }
anatofuz
parents:
diff changeset
376
anatofuz
parents:
diff changeset
377 void ImplicitBoolConversionCheck::handleCastFromBool(
anatofuz
parents:
diff changeset
378 const ImplicitCastExpr *Cast, const ImplicitCastExpr *NextImplicitCast,
anatofuz
parents:
diff changeset
379 ASTContext &Context) {
anatofuz
parents:
diff changeset
380 QualType DestType =
anatofuz
parents:
diff changeset
381 NextImplicitCast ? NextImplicitCast->getType() : Cast->getType();
anatofuz
parents:
diff changeset
382 auto Diag = diag(Cast->getBeginLoc(), "implicit conversion bool -> %0")
anatofuz
parents:
diff changeset
383 << DestType;
anatofuz
parents:
diff changeset
384
anatofuz
parents:
diff changeset
385 if (const auto *BoolLiteral =
anatofuz
parents:
diff changeset
386 dyn_cast<CXXBoolLiteralExpr>(Cast->getSubExpr())) {
anatofuz
parents:
diff changeset
387 Diag << tooling::fixit::createReplacement(
anatofuz
parents:
diff changeset
388 *Cast, getEquivalentForBoolLiteral(BoolLiteral, DestType, Context));
anatofuz
parents:
diff changeset
389 } else {
anatofuz
parents:
diff changeset
390 fixGenericExprCastFromBool(Diag, Cast, Context, DestType.getAsString());
anatofuz
parents:
diff changeset
391 }
anatofuz
parents:
diff changeset
392 }
anatofuz
parents:
diff changeset
393
anatofuz
parents:
diff changeset
394 } // namespace readability
anatofuz
parents:
diff changeset
395 } // namespace tidy
anatofuz
parents:
diff changeset
396 } // namespace clang