void DurationConversionCastCheck::registerMatchers(MatchFinder *Finder) { auto CallMatcher = ignoringImpCasts(callExpr( callee(functionDecl(DurationConversionFunction()).bind("func_decl")), hasArgument(0, expr().bind("arg")))); Finder->addMatcher( expr(anyOf( cxxStaticCastExpr(hasSourceExpression(CallMatcher)).bind("cast_expr"), cStyleCastExpr(hasSourceExpression(CallMatcher)).bind("cast_expr"), cxxFunctionalCastExpr(hasSourceExpression(CallMatcher)) .bind("cast_expr"))), this); }
void DeleteNullPointerCheck::registerMatchers(MatchFinder *Finder) { const auto DeleteExpr = cxxDeleteExpr(has(castExpr(has(declRefExpr( to(decl(equalsBoundNode("deletedPointer")))))))) .bind("deleteExpr"); const auto DeleteMemberExpr = cxxDeleteExpr(has(castExpr(has(memberExpr(hasDeclaration( fieldDecl(equalsBoundNode("deletedMemberPointer")))))))) .bind("deleteMemberExpr"); const auto PointerExpr = ignoringImpCasts(anyOf( declRefExpr(to(decl().bind("deletedPointer"))), memberExpr(hasDeclaration(fieldDecl().bind("deletedMemberPointer"))))); const auto PointerCondition = castExpr(hasCastKind(CK_PointerToBoolean), hasSourceExpression(PointerExpr)); const auto BinaryPointerCheckCondition = binaryOperator(hasEitherOperand(castExpr(hasCastKind(CK_NullToPointer))), hasEitherOperand(PointerExpr)); Finder->addMatcher( ifStmt(hasCondition(anyOf(PointerCondition, BinaryPointerCheckCondition)), hasThen(anyOf( DeleteExpr, DeleteMemberExpr, compoundStmt(anyOf(has(DeleteExpr), has(DeleteMemberExpr)), statementCountIs(1)) .bind("compound")))) .bind("ifWithDelete"), this); }
llvm::Optional<std::string> stripFloatCast(const ast_matchers::MatchFinder::MatchResult &Result, const Expr &Node) { if (const Expr *MaybeCastArg = selectFirst<const Expr>( "cast_arg", match(expr(anyOf(cxxStaticCastExpr( hasDestinationType(realFloatingPointType()), hasSourceExpression(expr().bind("cast_arg"))), cStyleCastExpr( hasDestinationType(realFloatingPointType()), hasSourceExpression(expr().bind("cast_arg"))), cxxFunctionalCastExpr( hasDestinationType(realFloatingPointType()), hasSourceExpression(expr().bind("cast_arg"))))), Node, *Result.Context))) return tooling::fixit::getText(*MaybeCastArg, *Result.Context).str(); return llvm::None; }
void ParentVirtualCallCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( cxxMemberCallExpr( callee(memberExpr(hasDescendant(implicitCastExpr( hasImplicitDestinationType(pointsTo( type(anything()).bind("castToType"))), hasSourceExpression(cxxThisExpr(hasType( type(anything()).bind("thisType"))))))) .bind("member")), callee(cxxMethodDecl(isVirtual()))), this); }
void ProBoundsArrayToPointerDecayCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; // The only allowed array to pointer decay // 1) just before array subscription // 2) inside a range-for over an array // 3) if it converts a string literal to a pointer Finder->addMatcher( implicitCastExpr(unless(hasParent(arraySubscriptExpr())), unless(hasParentIgnoringImpCasts(explicitCastExpr())), unless(isInsideOfRangeBeginEndStmt()), unless(hasSourceExpression(stringLiteral()))) .bind("cast"), this); }
/// Returns `true` if `Node` is a value which evaluates to a literal `0`. bool IsLiteralZero(const MatchFinder::MatchResult &Result, const Expr &Node) { auto ZeroMatcher = anyOf(integerLiteral(equals(0)), floatLiteral(equals(0.0))); // Check to see if we're using a zero directly. if (selectFirst<const clang::Expr>( "val", match(expr(ignoringImpCasts(ZeroMatcher)).bind("val"), Node, *Result.Context)) != nullptr) return true; // Now check to see if we're using a functional cast with a scalar // initializer expression, e.g. `int{0}`. if (selectFirst<const clang::Expr>( "val", match(cxxFunctionalCastExpr( hasDestinationType( anyOf(isInteger(), realFloatingPointType())), hasSourceExpression(initListExpr( hasInit(0, ignoringParenImpCasts(ZeroMatcher))))) .bind("val"), Node, *Result.Context)) != nullptr) return true; return false; }
void SuspiciousStringCompareCheck::registerMatchers(MatchFinder *Finder) { // Match relational operators. const auto ComparisonUnaryOperator = unaryOperator(hasOperatorName("!")); const auto ComparisonBinaryOperator = binaryOperator(matchers::isComparisonOperator()); const auto ComparisonOperator = expr(anyOf(ComparisonUnaryOperator, ComparisonBinaryOperator)); // Add the list of known string compare-like functions and add user-defined // functions. std::vector<std::string> FunctionNames = utils::options::parseStringList( (llvm::Twine(KnownStringCompareFunctions) + StringCompareLikeFunctions) .str()); // Match a call to a string compare functions. const auto FunctionCompareDecl = functionDecl(hasAnyName(std::vector<StringRef>(FunctionNames.begin(), FunctionNames.end()))) .bind("decl"); const auto DirectStringCompareCallExpr = callExpr(hasDeclaration(FunctionCompareDecl)).bind("call"); const auto MacroStringCompareCallExpr = conditionalOperator(anyOf( hasTrueExpression(ignoringParenImpCasts(DirectStringCompareCallExpr)), hasFalseExpression(ignoringParenImpCasts(DirectStringCompareCallExpr)))); // The implicit cast is not present in C. const auto StringCompareCallExpr = ignoringParenImpCasts( anyOf(DirectStringCompareCallExpr, MacroStringCompareCallExpr)); if (WarnOnImplicitComparison) { // Detect suspicious calls to string compare: // 'if (strcmp())' -> 'if (strcmp() != 0)' Finder->addMatcher( stmt(anyOf(ifStmt(hasCondition(StringCompareCallExpr)), whileStmt(hasCondition(StringCompareCallExpr)), doStmt(hasCondition(StringCompareCallExpr)), forStmt(hasCondition(StringCompareCallExpr)), binaryOperator( anyOf(hasOperatorName("&&"), hasOperatorName("||")), hasEitherOperand(StringCompareCallExpr)))) .bind("missing-comparison"), this); } if (WarnOnLogicalNotComparison) { // Detect suspicious calls to string compared with '!' operator: // 'if (!strcmp())' -> 'if (strcmp() == 0)' Finder->addMatcher(unaryOperator(hasOperatorName("!"), hasUnaryOperand(ignoringParenImpCasts( StringCompareCallExpr))) .bind("logical-not-comparison"), this); } // Detect suspicious cast to an inconsistant type (i.e. not integer type). Finder->addMatcher( implicitCastExpr(unless(hasType(isInteger())), hasSourceExpression(StringCompareCallExpr)) .bind("invalid-conversion"), this); // Detect suspicious operator with string compare function as operand. Finder->addMatcher( binaryOperator( unless(anyOf(matchers::isComparisonOperator(), hasOperatorName("&&"), hasOperatorName("||"), hasOperatorName("="))), hasEitherOperand(StringCompareCallExpr)) .bind("suspicious-operator"), this); // Detect comparison to invalid constant: 'strcmp() == -1'. const auto InvalidLiteral = ignoringParenImpCasts( anyOf(integerLiteral(unless(equals(0))), unaryOperator( hasOperatorName("-"), has(ignoringParenImpCasts(integerLiteral(unless(equals(0)))))), characterLiteral(), cxxBoolLiteral())); Finder->addMatcher(binaryOperator(matchers::isComparisonOperator(), hasEitherOperand(StringCompareCallExpr), hasEitherOperand(InvalidLiteral)) .bind("invalid-comparison"), this); }