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