1 //===--- BoolPointerImplicitConversionCheck.cpp - clang-tidy --------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "BoolPointerImplicitConversionCheck.h"
11 using namespace clang::ast_matchers
;
13 namespace clang::tidy::bugprone
{
15 void BoolPointerImplicitConversionCheck::registerMatchers(MatchFinder
*Finder
) {
16 // Look for ifs that have an implicit bool* to bool conversion in the
17 // condition. Filter negations.
22 hasCondition(findAll(implicitCastExpr(
23 unless(hasParent(unaryOperator(hasOperatorName("!")))),
24 hasSourceExpression(expr(
25 hasType(pointerType(pointee(booleanType()))),
26 ignoringParenImpCasts(anyOf(declRefExpr().bind("expr"),
27 memberExpr().bind("expr"))))),
28 hasCastKind(CK_PointerToBoolean
)))),
29 unless(isInTemplateInstantiation()))
34 static void checkImpl(const MatchFinder::MatchResult
&Result
, const Expr
*Ref
,
36 const ast_matchers::internal::Matcher
<Expr
> &RefMatcher
,
37 ClangTidyCheck
&Check
) {
39 if (Ref
->getBeginLoc().isMacroID())
42 // Only allow variable accesses and member exprs for now, no function calls.
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 if (!match(findAll(unaryOperator(hasOperatorName("*"),
48 hasUnaryOperand(RefMatcher
))),
51 !match(findAll(arraySubscriptExpr(hasBase(RefMatcher
))), *If
,
54 // FIXME: We should still warn if the paremater is implicitly converted to
57 findAll(callExpr(hasAnyArgument(ignoringParenImpCasts(RefMatcher
)))),
61 findAll(cxxDeleteExpr(has(ignoringParenImpCasts(expr(RefMatcher
))))),
66 Check
.diag(Ref
->getBeginLoc(),
67 "dubious check of 'bool *' against 'nullptr', did "
68 "you mean to dereference it?")
69 << FixItHint::CreateInsertion(Ref
->getBeginLoc(), "*");
72 void BoolPointerImplicitConversionCheck::check(
73 const MatchFinder::MatchResult
&Result
) {
74 const auto *If
= Result
.Nodes
.getNodeAs
<IfStmt
>("if");
75 if (const auto *E
= Result
.Nodes
.getNodeAs
<Expr
>("expr")) {
76 const Decl
*D
= isa
<DeclRefExpr
>(E
) ? cast
<DeclRefExpr
>(E
)->getDecl()
77 : cast
<MemberExpr
>(E
)->getMemberDecl();
79 ignoringParenImpCasts(anyOf(declRefExpr(to(equalsNode(D
))),
80 memberExpr(hasDeclaration(equalsNode(D
)))));
81 checkImpl(Result
, E
, If
, M
, *this);
85 } // namespace clang::tidy::bugprone