1 //===--- BoolPointerImplicitConversionCheck.cpp - clang-tidy --------------===// 2 // 3 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "BoolPointerImplicitConversionCheck.h" 10 11 using namespace clang::ast_matchers; 12 13 namespace clang { 14 namespace tidy { 15 namespace bugprone { 16 17 void BoolPointerImplicitConversionCheck::registerMatchers(MatchFinder *Finder) { 18 // Look for ifs that have an implicit bool* to bool conversion in the 19 // condition. Filter negations. 20 Finder->addMatcher( 21 ifStmt(hasCondition(findAll(implicitCastExpr( 22 unless(hasParent(unaryOperator(hasOperatorName("!")))), 23 hasSourceExpression( 24 expr(hasType(pointerType(pointee(booleanType()))), 25 ignoringParenImpCasts(declRefExpr().bind("expr")))), 26 hasCastKind(CK_PointerToBoolean)))), 27 unless(isInTemplateInstantiation())) 28 .bind("if"), 29 this); 30 } 31 32 void BoolPointerImplicitConversionCheck::check( 33 const MatchFinder::MatchResult &Result) { 34 auto *If = Result.Nodes.getNodeAs<IfStmt>("if"); 35 auto *Var = Result.Nodes.getNodeAs<DeclRefExpr>("expr"); 36 37 // Ignore macros. 38 if (Var->getBeginLoc().isMacroID()) 39 return; 40 41 // Only allow variable accesses for now, no function calls or member exprs. 42 // Check that we don't dereference the variable anywhere within the if. This 43 // avoids false positives for checks of the pointer for nullptr before it is 44 // dereferenced. If there is a dereferencing operator on this variable don't 45 // emit a diagnostic. Also ignore array subscripts. 46 const Decl *D = Var->getDecl(); 47 auto DeclRef = ignoringParenImpCasts(declRefExpr(to(equalsNode(D)))); 48 if (!match(findAll( 49 unaryOperator(hasOperatorName("*"), hasUnaryOperand(DeclRef))), 50 *If, *Result.Context) 51 .empty() || 52 !match(findAll(arraySubscriptExpr(hasBase(DeclRef))), *If, 53 *Result.Context) 54 .empty() || 55 // FIXME: We should still warn if the paremater is implicitly converted to 56 // bool. 57 !match(findAll(callExpr(hasAnyArgument(ignoringParenImpCasts(DeclRef)))), 58 *If, *Result.Context) 59 .empty() || 60 !match(findAll(cxxDeleteExpr(has(ignoringParenImpCasts(expr(DeclRef))))), 61 *If, *Result.Context) 62 .empty()) 63 return; 64 65 diag(Var->getBeginLoc(), "dubious check of 'bool *' against 'nullptr', did " 66 "you mean to dereference it?") 67 << FixItHint::CreateInsertion(Var->getBeginLoc(), "*"); 68 } 69 70 } // namespace bugprone 71 } // namespace tidy 72 } // namespace clang 73