void SuspiciousEnumUsageCheck::registerMatchers(MatchFinder *Finder) { const auto enumExpr = [](StringRef RefName, StringRef DeclName) { return allOf(ignoringImpCasts(expr().bind(RefName)), ignoringImpCasts(hasType(enumDecl().bind(DeclName)))); }; Finder->addMatcher( binaryOperator(hasOperatorName("|"), hasLHS(enumExpr("", "enumDecl")), hasRHS(allOf(enumExpr("", "otherEnumDecl"), ignoringImpCasts(hasType(enumDecl( unless(equalsBoundNode("enumDecl")))))))) .bind("diffEnumOp"), this); Finder->addMatcher( binaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("|")), hasLHS(enumExpr("lhsExpr", "enumDecl")), hasRHS(allOf(enumExpr("rhsExpr", ""), ignoringImpCasts(hasType(enumDecl( equalsBoundNode("enumDecl"))))))), this); Finder->addMatcher( binaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("|")), hasEitherOperand( allOf(hasType(isInteger()), unless(enumExpr("", "")))), hasEitherOperand(enumExpr("enumExpr", "enumDecl"))), this); Finder->addMatcher( binaryOperator(anyOf(hasOperatorName("|="), hasOperatorName("+=")), hasRHS(enumExpr("enumExpr", "enumDecl"))), this); }
void IncorrectRoundings::registerMatchers(MatchFinder *MatchFinder) { // Match a floating literal with value 0.5. auto FloatHalf = floatLiteral(floatHalf()); // Match a floating point expression. auto FloatType = expr(hasType(realFloatingPointType())); // Match a floating literal of 0.5 or a floating literal of 0.5 implicitly. // cast to floating type. auto FloatOrCastHalf = anyOf(FloatHalf, implicitCastExpr(FloatType, has(FloatHalf))); // Match if either the LHS or RHS is a floating literal of 0.5 or a floating // literal of 0.5 and the other is of type double or vice versa. auto OneSideHalf = anyOf(allOf(hasLHS(FloatOrCastHalf), hasRHS(FloatType)), allOf(hasRHS(FloatOrCastHalf), hasLHS(FloatType))); // Find expressions of cast to int of the sum of a floating point expression // and 0.5. MatchFinder->addMatcher( implicitCastExpr( hasImplicitDestinationType(isInteger()), ignoringParenCasts(binaryOperator(hasOperatorName("+"), OneSideHalf))) .bind("CastExpr"), this); }
void PointerAndIntegralOperationCheck::registerMatchers(MatchFinder *Finder) { const auto PointerExpr = expr(hasType(pointerType())); const auto BoolExpr = ignoringParenImpCasts(hasType(booleanType())); const auto CharExpr = ignoringParenImpCasts(hasType(isAnyCharacter())); const auto BinOpWithPointerExpr = binaryOperator(unless(anyOf(hasOperatorName(","), hasOperatorName("="))), hasEitherOperand(PointerExpr)); const auto AssignToPointerExpr = binaryOperator(hasOperatorName("="), hasLHS(PointerExpr)); const auto CompareToPointerExpr = binaryOperator(matchers::isRelationalOperator(), hasEitherOperand(PointerExpr)); // Detect expression like: ptr = (x != y); Finder->addMatcher(binaryOperator(AssignToPointerExpr, hasRHS(BoolExpr)) .bind("assign-bool-to-pointer"), this); // Detect expression like: ptr = A[i]; where A is char*. Finder->addMatcher(binaryOperator(AssignToPointerExpr, hasRHS(CharExpr)) .bind("assign-char-to-pointer"), this); // Detect expression like: ptr < false; Finder->addMatcher( binaryOperator(BinOpWithPointerExpr, hasEitherOperand(ignoringParenImpCasts(cxxBoolLiteral()))) .bind("pointer-and-bool-literal"), this); // Detect expression like: ptr < 'a'; Finder->addMatcher(binaryOperator(BinOpWithPointerExpr, hasEitherOperand(ignoringParenImpCasts( characterLiteral()))) .bind("pointer-and-char-literal"), this); // Detect expression like: ptr < 0; Finder->addMatcher(binaryOperator(CompareToPointerExpr, hasEitherOperand(ignoringParenImpCasts( integerLiteral(equals(0))))) .bind("compare-pointer-to-zero"), this); // Detect expression like: ptr < nullptr; Finder->addMatcher(binaryOperator(CompareToPointerExpr, hasEitherOperand(ignoringParenImpCasts( cxxNullPtrLiteralExpr()))) .bind("compare-pointer-to-null"), this); }
void MisplacedOperatorInStrlenInAllocCheck::registerMatchers( MatchFinder *Finder) { const auto StrLenFunc = functionDecl(anyOf( hasName("::strlen"), hasName("::std::strlen"), hasName("::strnlen"), hasName("::std::strnlen"), hasName("::strnlen_s"), hasName("::std::strnlen_s"), hasName("::wcslen"), hasName("::std::wcslen"), hasName("::wcsnlen"), hasName("::std::wcsnlen"), hasName("::wcsnlen_s"), hasName("std::wcsnlen_s"))); const auto BadUse = callExpr(callee(StrLenFunc), hasAnyArgument(ignoringImpCasts( binaryOperator( hasOperatorName("+"), hasRHS(ignoringParenImpCasts(integerLiteral(equals(1))))) .bind("BinOp")))) .bind("StrLen"); const auto BadArg = anyOf( allOf(unless(binaryOperator( hasOperatorName("+"), hasLHS(BadUse), hasRHS(ignoringParenImpCasts(integerLiteral(equals(1)))))), hasDescendant(BadUse)), BadUse); const auto Alloc0Func = functionDecl(anyOf(hasName("::malloc"), hasName("std::malloc"), hasName("::alloca"), hasName("std::alloca"))); const auto Alloc1Func = functionDecl(anyOf(hasName("::calloc"), hasName("std::calloc"), hasName("::realloc"), hasName("std::realloc"))); const auto Alloc0FuncPtr = varDecl(hasType(isConstQualified()), hasInitializer(ignoringParenImpCasts( declRefExpr(hasDeclaration(Alloc0Func))))); const auto Alloc1FuncPtr = varDecl(hasType(isConstQualified()), hasInitializer(ignoringParenImpCasts( declRefExpr(hasDeclaration(Alloc1Func))))); Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc0Func, Alloc0FuncPtr))), hasArgument(0, BadArg)) .bind("Alloc"), this); Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc1Func, Alloc1FuncPtr))), hasArgument(1, BadArg)) .bind("Alloc"), this); Finder->addMatcher( cxxNewExpr(isArray(), hasArraySize(BadArg)).bind("Alloc"), this); }
void SignedBitwiseCheck::registerMatchers(MatchFinder *Finder) { const auto SignedIntegerOperand = expr(ignoringImpCasts(hasType(isSignedInteger()))).bind("signed-operand"); // The standard [bitmask.types] allows some integral types to be implemented // as signed types. Exclude these types from diagnosing for bitwise or(|) and // bitwise and(&). Shifting and complementing such values is still not // allowed. const auto BitmaskType = namedDecl(anyOf( hasName("::std::locale::category"), hasName("::std::ctype_base::mask"), hasName("::std::ios_base::fmtflags"), hasName("::std::ios_base::iostate"), hasName("::std::ios_base::openmode"))); const auto IsStdBitmask = ignoringImpCasts(declRefExpr(hasType(BitmaskType))); // Match binary bitwise operations on signed integer arguments. Finder->addMatcher( binaryOperator( allOf(anyOf(hasOperatorName("^"), hasOperatorName("|"), hasOperatorName("&"), hasOperatorName("^="), hasOperatorName("|="), hasOperatorName("&=")), unless(allOf(hasLHS(IsStdBitmask), hasRHS(IsStdBitmask))), hasEitherOperand(SignedIntegerOperand), hasLHS(hasType(isInteger())), hasRHS(hasType(isInteger())))) .bind("binary-no-sign-interference"), this); // Shifting and complement is not allowed for any signed integer type because // the sign bit may corrupt the result. Finder->addMatcher( binaryOperator( allOf(anyOf(hasOperatorName("<<"), hasOperatorName(">>"), hasOperatorName("<<="), hasOperatorName(">>=")), hasEitherOperand(SignedIntegerOperand), hasLHS(hasType(isInteger())), hasRHS(hasType(isInteger())))) .bind("binary-sign-interference"), this); // Match unary operations on signed integer types. Finder->addMatcher(unaryOperator(allOf(hasOperatorName("~"), hasUnaryOperand(SignedIntegerOperand))) .bind("unary-signed"), this); }
void SizeofContainerCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( expr(unless(isInTemplateInstantiation()), expr(sizeOfExpr(has(ignoringParenImpCasts( expr(hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl( matchesName("^(::std::|::string)"), unless(matchesName("^::std::(bitset|array)$")), hasMethod(cxxMethodDecl(hasName("size"), isPublic(), isConst()))))))))))) .bind("sizeof"), // Ignore ARRAYSIZE(<array of containers>) pattern. unless(hasAncestor(binaryOperator( anyOf(hasOperatorName("/"), hasOperatorName("%")), hasLHS(ignoringParenCasts(sizeOfExpr(expr()))), hasRHS(ignoringParenCasts(equalsBoundNode("sizeof"))))))), this); }
void MisplacedWideningCastCheck::registerMatchers(MatchFinder *Finder) { const auto Calc = expr(anyOf(binaryOperator( anyOf(hasOperatorName("+"), hasOperatorName("-"), hasOperatorName("*"), hasOperatorName("<<"))), unaryOperator(hasOperatorName("~"))), hasType(isInteger())) .bind("Calc"); const auto ExplicitCast = explicitCastExpr(hasDestinationType(isInteger()), has(ignoringParenImpCasts(Calc))); const auto ImplicitCast = implicitCastExpr(hasImplicitDestinationType(isInteger()), has(ignoringParenImpCasts(Calc))); const auto Cast = expr(anyOf(ExplicitCast, ImplicitCast)).bind("Cast"); Finder->addMatcher(varDecl(hasInitializer(Cast)), this); Finder->addMatcher(returnStmt(hasReturnValue(Cast)), this); Finder->addMatcher(callExpr(hasAnyArgument(Cast)), this); Finder->addMatcher(binaryOperator(hasOperatorName("="), hasRHS(Cast)), this); Finder->addMatcher( binaryOperator(matchers::isComparisonOperator(), hasEitherOperand(Cast)), this); }
#include "ASTUtility.h" // int *x = NULL or int *x = 0 DeclarationMatcher nullPointerMatcher = varDecl(hasType(pointerType()), hasInitializer(implicitCastExpr().bind("cast"))).bind("var"); // x == NULL or x == 0 StatementMatcher biOpMatcher1 = binaryOperator(hasRHS(implicitCastExpr().bind("castR1")), hasOperatorName("==")).bind("bo1"); // x != NULL or x != 0 StatementMatcher biOpMatcher2 = binaryOperator(hasRHS(implicitCastExpr().bind("castR2")), hasOperatorName("!=")).bind("bo2"); // x != NULL or x != 0 StatementMatcher biOpMatcher3 = binaryOperator(hasRHS(implicitCastExpr().bind("castR3")), hasOperatorName("=")).bind("bo3"); class NullPointerPrinter : public MatchFinder::MatchCallback { public: virtual void run(const MatchFinder::MatchResult &Result) { //get the node clang::ASTContext *Context = Result.Context; const clang::ImplicitCastExpr *cast = Result.Nodes.getNodeAs<clang::ImplicitCastExpr>("cast"); const clang::ImplicitCastExpr *castR1 = Result.Nodes.getNodeAs<clang::ImplicitCastExpr>("castR1"); const clang::ImplicitCastExpr *castR2 = Result.Nodes.getNodeAs<clang::ImplicitCastExpr>("castR2"); const clang::ImplicitCastExpr *castR3 = Result.Nodes.getNodeAs<clang::ImplicitCastExpr>("castR3"); const clang::BinaryOperator *bo1 = Result.Nodes.getNodeAs<clang::BinaryOperator>("bo1"); const clang::BinaryOperator *bo2 = Result.Nodes.getNodeAs<clang::BinaryOperator>("bo2"); const clang::BinaryOperator *bo3 = Result.Nodes.getNodeAs<clang::BinaryOperator>("bo3");