blob: f831125838d745d8d5f13ca56f1f548f90e7b787 [file] [log] [blame]
Alexander Kornienko5b982e52015-03-09 11:48:54 +00001//===--- BoolPointerImplicitConversionCheck.cpp - clang-tidy --------------===//
Benjamin Kramer1c8b3172014-07-11 08:08:47 +00002//
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
Alexander Kornienko5b982e52015-03-09 11:48:54 +000010#include "BoolPointerImplicitConversionCheck.h"
Benjamin Kramer1c8b3172014-07-11 08:08:47 +000011
12using namespace clang::ast_matchers;
13
14namespace clang {
Etienne Bergeron456177b2016-05-02 18:00:29 +000015namespace tidy {
16namespace misc {
17
Alexander Kornienko5b982e52015-03-09 11:48:54 +000018void BoolPointerImplicitConversionCheck::registerMatchers(MatchFinder *Finder) {
Benjamin Kramer1c8b3172014-07-11 08:08:47 +000019 // 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 allOf(unless(hasParent(unaryOperator(hasOperatorName("!")))),
24 hasSourceExpression(expr(
Etienne Bergeron9d265992016-04-21 16:57:56 +000025 hasType(pointerType(pointee(booleanType()))),
Benjamin Kramer1c8b3172014-07-11 08:08:47 +000026 ignoringParenImpCasts(declRefExpr().bind("expr")))),
Etienne Bergerone15ef2f2016-05-17 19:36:09 +000027 hasCastKind(CK_PointerToBoolean))))),
Mandeep Singh Grang7c7ea7d2016-11-08 07:50:19 +000028 unless(isInTemplateInstantiation()))
29 .bind("if"),
Benjamin Kramer1c8b3172014-07-11 08:08:47 +000030 this);
31}
32
Alexander Kornienko5b982e52015-03-09 11:48:54 +000033void BoolPointerImplicitConversionCheck::check(
34 const MatchFinder::MatchResult &Result) {
Alexander Kornienko9f58fe02016-12-13 16:19:19 +000035 auto *If = Result.Nodes.getNodeAs<IfStmt>("if");
36 auto *Var = Result.Nodes.getNodeAs<DeclRefExpr>("expr");
Benjamin Kramer1c8b3172014-07-11 08:08:47 +000037
Benjamin Kramer242b5b82014-08-12 12:12:57 +000038 // Ignore macros.
39 if (Var->getLocStart().isMacroID())
40 return;
41
Benjamin Kramer1c8b3172014-07-11 08:08:47 +000042 // 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))),
Piotr Padlewskie93a73f2016-05-31 15:26:56 +000051 *If, *Result.Context)
52 .empty() ||
Benjamin Kramer1c8b3172014-07-11 08:08:47 +000053 !match(findAll(arraySubscriptExpr(hasBase(DeclRef))), *If,
Piotr Padlewskie93a73f2016-05-31 15:26:56 +000054 *Result.Context)
55 .empty() ||
Benjamin Kramer1c8b3172014-07-11 08:08:47 +000056 // FIXME: We should still warn if the paremater is implicitly converted to
57 // bool.
Gabor Horvath5273f612016-04-06 12:04:51 +000058 !match(findAll(callExpr(hasAnyArgument(ignoringParenImpCasts(DeclRef)))),
59 *If, *Result.Context)
Benjamin Kramer1c8b3172014-07-11 08:08:47 +000060 .empty() ||
Piotr Padlewskie93a73f2016-05-31 15:26:56 +000061 !match(findAll(cxxDeleteExpr(has(ignoringParenImpCasts(expr(DeclRef))))),
62 *If, *Result.Context)
Benjamin Kramer1c8b3172014-07-11 08:08:47 +000063 .empty())
64 return;
65
66 diag(Var->getLocStart(), "dubious check of 'bool *' against 'nullptr', did "
67 "you mean to dereference it?")
68 << FixItHint::CreateInsertion(Var->getLocStart(), "*");
69}
70
Alexander Kornienko2b3124202015-03-02 12:25:03 +000071} // namespace misc
Benjamin Kramer1c8b3172014-07-11 08:08:47 +000072} // namespace tidy
73} // namespace clang