diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy/misc/BoolPointerImplicitConversion.cpp')
-rw-r--r-- | clang-tools-extra/clang-tidy/misc/BoolPointerImplicitConversion.cpp | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/misc/BoolPointerImplicitConversion.cpp b/clang-tools-extra/clang-tidy/misc/BoolPointerImplicitConversion.cpp new file mode 100644 index 00000000000..6565874a340 --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/BoolPointerImplicitConversion.cpp @@ -0,0 +1,70 @@ +//===--- BoolPointerImplicitConversion.cpp - clang-tidy -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "BoolPointerImplicitConversion.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace ast_matchers { + +AST_MATCHER(CastExpr, isPointerToBoolean) { + return Node.getCastKind() == CK_PointerToBoolean; +} +AST_MATCHER(QualType, isBoolean) { return Node->isBooleanType(); } + +} // namespace ast_matchers + +namespace tidy { + +void BoolPointerImplicitConversion::registerMatchers(MatchFinder *Finder) { + // Look for ifs that have an implicit bool* to bool conversion in the + // condition. Filter negations. + Finder->addMatcher( + ifStmt(hasCondition(findAll(implicitCastExpr( + allOf(unless(hasParent(unaryOperator(hasOperatorName("!")))), + hasSourceExpression(expr( + hasType(pointerType(pointee(isBoolean()))), + ignoringParenImpCasts(declRefExpr().bind("expr")))), + isPointerToBoolean()))))).bind("if"), + this); +} + +void +BoolPointerImplicitConversion::check(const MatchFinder::MatchResult &Result) { + auto *If = Result.Nodes.getStmtAs<IfStmt>("if"); + auto *Var = Result.Nodes.getStmtAs<DeclRefExpr>("expr"); + + // Only allow variable accesses for now, no function calls or member exprs. + // Check that we don't dereference the variable anywhere within the if. This + // avoids false positives for checks of the pointer for nullptr before it is + // dereferenced. If there is a dereferencing operator on this variable don't + // emit a diagnostic. Also ignore array subscripts. + const Decl *D = Var->getDecl(); + auto DeclRef = ignoringParenImpCasts(declRefExpr(to(equalsNode(D)))); + if (!match(findAll( + unaryOperator(hasOperatorName("*"), hasUnaryOperand(DeclRef))), + *If, *Result.Context).empty() || + !match(findAll(arraySubscriptExpr(hasBase(DeclRef))), *If, + *Result.Context).empty() || + // FIXME: We should still warn if the paremater is implicitly converted to + // bool. + !match(findAll(callExpr(hasAnyArgument(DeclRef))), *If, *Result.Context) + .empty() || + !match(findAll(deleteExpr(has(expr(DeclRef)))), *If, *Result.Context) + .empty()) + return; + + diag(Var->getLocStart(), "dubious check of 'bool *' against 'nullptr', did " + "you mean to dereference it?") + << FixItHint::CreateInsertion(Var->getLocStart(), "*"); +} + +} // namespace tidy +} // namespace clang |