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