brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.4 KiB · df85524 Raw
86 lines · cpp
1//===----------------------------------------------------------------------===//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-exception6//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 the17  // condition. Filter negations.18  Finder->addMatcher(19      traverse(20          TK_AsIs,21          ifStmt(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()))30              .bind("if")),31      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. This44  // avoids false positives for checks of the pointer for nullptr before it is45  // dereferenced. If there is a dereferencing operator on this variable don't46  // emit a diagnostic. Also ignore array subscripts.47  if (!match(findAll(unaryOperator(hasOperatorName("*"),48                                   hasUnaryOperand(RefMatcher))),49             *If, *Result.Context)50           .empty() ||51      !match(findAll(arraySubscriptExpr(hasBase(RefMatcher))), *If,52             *Result.Context)53           .empty() ||54      // FIXME: We should still warn if the paremater is implicitly converted to55      // bool.56      !match(57           findAll(callExpr(hasAnyArgument(ignoringParenImpCasts(RefMatcher)))),58           *If, *Result.Context)59           .empty() ||60      !match(61           findAll(cxxDeleteExpr(has(ignoringParenImpCasts(expr(RefMatcher))))),62           *If, *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(Ref->getBeginLoc(), "*");70}71 72void 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();78    const auto M =79        ignoringParenImpCasts(anyOf(declRefExpr(to(equalsNode(D))),80                                    memberExpr(hasDeclaration(equalsNode(D)))));81    checkImpl(Result, E, If, M, *this);82  }83}84 85} // namespace clang::tidy::bugprone86