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
11using namespace clang::ast_matchers;
12
13namespace clang::tidy::bugprone {
14
15void BoolPointerImplicitConversionCheck::registerMatchers(MatchFinder *Finder) {
16 // Look for ifs that have an implicit bool* to bool conversion in the
17 // condition. Filter negations.
18 Finder->addMatcher(
19 NodeMatch: traverse(
20 TK: TK_AsIs,
21 InnerMatcher: ifStmt(
22 hasCondition(InnerMatcher: findAll(Matcher: implicitCastExpr(
23 unless(hasParent(unaryOperator(hasOperatorName(Name: "!")))),
24 hasSourceExpression(InnerMatcher: expr(
25 hasType(InnerMatcher: pointerType(pointee(booleanType()))),
26 ignoringParenImpCasts(InnerMatcher: anyOf(declRefExpr().bind(ID: "expr"),
27 memberExpr().bind(ID: "expr"))))),
28 hasCastKind(Kind: CK_PointerToBoolean)))),
29 unless(isInTemplateInstantiation()))
30 .bind(ID: "if")),
31 Action: this);
32}
33
34static void checkImpl(const MatchFinder::MatchResult &Result, const Expr *Ref,
35 const IfStmt *If,
36 const ast_matchers::internal::Matcher<Expr> &RefMatcher,
37 ClangTidyCheck &Check) {
38 // Ignore macros.
39 if (Ref->getBeginLoc().isMacroID())
40 return;
41
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(Matcher: findAll(Matcher: unaryOperator(hasOperatorName(Name: "*"),
48 hasUnaryOperand(InnerMatcher: RefMatcher))),
49 Node: *If, Context&: *Result.Context)
50 .empty() ||
51 !match(Matcher: findAll(Matcher: arraySubscriptExpr(hasBase(InnerMatcher: RefMatcher))), Node: *If,
52 Context&: *Result.Context)
53 .empty() ||
54 // FIXME: We should still warn if the paremater is implicitly converted to
55 // bool.
56 !match(
57 Matcher: findAll(Matcher: callExpr(hasAnyArgument(InnerMatcher: ignoringParenImpCasts(InnerMatcher: RefMatcher)))),
58 Node: *If, Context&: *Result.Context)
59 .empty() ||
60 !match(
61 Matcher: findAll(Matcher: cxxDeleteExpr(has(ignoringParenImpCasts(InnerMatcher: expr(RefMatcher))))),
62 Node: *If, Context&: *Result.Context)
63 .empty())
64 return;
65
66 Check.diag(Ref->getBeginLoc(),
67 "dubious check of 'bool *' against 'nullptr', did "
68 "you mean to dereference it?")
69 << FixItHint::CreateInsertion(InsertionLoc: Ref->getBeginLoc(), Code: "*");
70}
71
72void BoolPointerImplicitConversionCheck::check(
73 const MatchFinder::MatchResult &Result) {
74 const auto *If = Result.Nodes.getNodeAs<IfStmt>(ID: "if");
75 if (const auto *E = Result.Nodes.getNodeAs<Expr>(ID: "expr")) {
76 const Decl *D = isa<DeclRefExpr>(Val: E) ? cast<DeclRefExpr>(Val: E)->getDecl()
77 : cast<MemberExpr>(Val: E)->getMemberDecl();
78 const auto M =
79 ignoringParenImpCasts(InnerMatcher: anyOf(declRefExpr(to(InnerMatcher: equalsNode(Other: D))),
80 memberExpr(hasDeclaration(InnerMatcher: equalsNode(Other: D)))));
81 checkImpl(Result, E, If, M, *this);
82 }
83}
84
85} // namespace clang::tidy::bugprone
86

source code of clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp