void InaccurateEraseCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not // provide any benefit to other languages, despite being benign. if (!getLangOpts().CPlusPlus) return; const auto EndCall = callExpr( callee(functionDecl(hasAnyName("remove", "remove_if", "unique"))), hasArgument( 1, anyOf(cxxConstructExpr(has(ignoringImplicit( cxxMemberCallExpr(callee(cxxMethodDecl(hasName("end")))) .bind("end")))), anything()))) .bind("alg"); const auto DeclInStd = type(hasUnqualifiedDesugaredType( tagType(hasDeclaration(decl(isInStdNamespace()))))); Finder->addMatcher( cxxMemberCallExpr( on(anyOf(hasType(DeclInStd), hasType(pointsTo(DeclInStd)))), callee(cxxMethodDecl(hasName("erase"))), argumentCountIs(1), hasArgument(0, has(ignoringImplicit( anyOf(EndCall, has(ignoringImplicit(EndCall)))))), unless(isInTemplateInstantiation())) .bind("erase"), this); }
void MakeSmartPtrCheck::registerMatchers(ast_matchers::MatchFinder *Finder) { if (!isLanguageVersionSupported(getLangOpts())) return; // Calling make_smart_ptr from within a member function of a type with a // private or protected constructor would be ill-formed. auto CanCallCtor = unless(has(ignoringImpCasts( cxxConstructExpr(hasDeclaration(decl(unless(isPublic()))))))); Finder->addMatcher( cxxBindTemporaryExpr(has(ignoringParenImpCasts( cxxConstructExpr( hasType(getSmartPointerTypeMatcher()), argumentCountIs(1), hasArgument(0, cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType( equalsBoundNode(PointerType))))), CanCallCtor) .bind(NewExpression)), unless(isInTemplateInstantiation())) .bind(ConstructorCall)))), this); Finder->addMatcher( cxxMemberCallExpr( thisPointerType(getSmartPointerTypeMatcher()), callee(cxxMethodDecl(hasName("reset"))), hasArgument(0, cxxNewExpr(CanCallCtor).bind(NewExpression)), unless(isInTemplateInstantiation())) .bind(ResetCall), this); }
void CloexecAcceptCheck::registerMatchers(MatchFinder *Finder) { auto SockAddrPointerType = hasType(pointsTo(recordDecl(isStruct(), hasName("sockaddr")))); auto SockLenPointerType = hasType(pointsTo(namedDecl(hasName("socklen_t")))); registerMatchersImpl(Finder, functionDecl(returns(isInteger()), hasName("accept"), hasParameter(0, hasType(isInteger())), hasParameter(1, SockAddrPointerType), hasParameter(2, SockLenPointerType))); }
void RedundantVoidArgCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher(functionDecl(parameterCountIs(0), unless(isImplicit()), unless(isExternC())) .bind(FunctionId), this); Finder->addMatcher(typedefNameDecl().bind(TypedefId), this); auto ParenFunctionType = parenType(innerType(functionType())); auto PointerToFunctionType = pointee(ParenFunctionType); auto FunctionOrMemberPointer = anyOf(hasType(pointerType(PointerToFunctionType)), hasType(memberPointerType(PointerToFunctionType))); Finder->addMatcher(fieldDecl(FunctionOrMemberPointer).bind(FieldId), this); Finder->addMatcher(varDecl(FunctionOrMemberPointer).bind(VarId), this); auto CastDestinationIsFunction = hasDestinationType(pointsTo(ParenFunctionType)); Finder->addMatcher( cStyleCastExpr(CastDestinationIsFunction).bind(CStyleCastId), this); Finder->addMatcher( cxxStaticCastExpr(CastDestinationIsFunction).bind(NamedCastId), this); Finder->addMatcher( cxxReinterpretCastExpr(CastDestinationIsFunction).bind(NamedCastId), this); Finder->addMatcher( cxxConstCastExpr(CastDestinationIsFunction).bind(NamedCastId), this); Finder->addMatcher(lambdaExpr().bind(LambdaId), this); }
void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) { const auto WrongUse = anyOf( hasParent( binaryOperator( anyOf(has(integerLiteral(equals(0))), allOf(anyOf(hasOperatorName("<"), hasOperatorName(">="), hasOperatorName(">"), hasOperatorName("<=")), hasEitherOperand(integerLiteral(equals(1)))))) .bind("SizeBinaryOp")), hasParent(implicitCastExpr( hasImplicitDestinationType(isBoolType()), anyOf( hasParent(unaryOperator(hasOperatorName("!")).bind("NegOnSize")), anything()))), hasParent(explicitCastExpr(hasDestinationType(isBoolType())))); Finder->addMatcher( memberCallExpr( on(expr(anyOf(hasType(namedDecl(stlContainer())), hasType(pointsTo(namedDecl(stlContainer()))), hasType(references(namedDecl(stlContainer()))))) .bind("STLObject")), callee(methodDecl(hasName("size"))), WrongUse).bind("SizeCallExpr"), this); }
void InefficientAlgorithmCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not // provide any benefit to other languages, despite being benign. if (!getLangOpts().CPlusPlus) return; const std::string Algorithms = "^::std::(find|count|equal_range|lower_bound|upper_bound)$"; const auto ContainerMatcher = classTemplateSpecializationDecl( matchesName("^::std::(unordered_)?(multi)?(set|map)$")); const auto Matcher = callExpr( callee(functionDecl(matchesName(Algorithms))), hasArgument( 0, constructExpr(has(memberCallExpr( callee(methodDecl(hasName("begin"))), on(declRefExpr( hasDeclaration(decl().bind("IneffContObj")), anyOf(hasType(ContainerMatcher.bind("IneffCont")), hasType(pointsTo( ContainerMatcher.bind("IneffContPtr"))))) .bind("IneffContExpr")))))), hasArgument(1, constructExpr(has(memberCallExpr( callee(methodDecl(hasName("end"))), on(declRefExpr(hasDeclaration( equalsBoundNode("IneffContObj")))))))), hasArgument(2, expr().bind("AlgParam")), unless(isInTemplateInstantiation())) .bind("IneffAlg"); Finder->addMatcher(Matcher, this); }
void FoldInitTypeCheck::registerMatchers(MatchFinder *Finder) { // We match functions of interest and bind the iterator and init value types. // Note: Right now we check only builtin types. const auto BuiltinTypeWithId = [](const char *ID) { return hasCanonicalType(builtinType().bind(ID)); }; const auto IteratorWithValueType = [&BuiltinTypeWithId](const char *ID) { return anyOf( // Pointer types. pointsTo(BuiltinTypeWithId(ID)), // Iterator types. recordType(hasDeclaration(has(typedefNameDecl( hasName("value_type"), hasType(BuiltinTypeWithId(ID))))))); }; const auto IteratorParam = parmVarDecl( hasType(hasCanonicalType(IteratorWithValueType("IterValueType")))); const auto Iterator2Param = parmVarDecl( hasType(hasCanonicalType(IteratorWithValueType("Iter2ValueType")))); const auto InitParam = parmVarDecl(hasType(BuiltinTypeWithId("InitType"))); // std::accumulate, std::reduce. Finder->addMatcher( callExpr(callee(functionDecl( hasAnyName("::std::accumulate", "::std::reduce"), hasParameter(0, IteratorParam), hasParameter(2, InitParam))), argumentCountIs(3)) .bind("Call"), this); // std::inner_product. Finder->addMatcher( callExpr(callee(functionDecl(hasName("::std::inner_product"), hasParameter(0, IteratorParam), hasParameter(2, Iterator2Param), hasParameter(3, InitParam))), argumentCountIs(4)) .bind("Call"), this); // std::reduce with a policy. Finder->addMatcher( callExpr(callee(functionDecl(hasName("::std::reduce"), hasParameter(1, IteratorParam), hasParameter(3, InitParam))), argumentCountIs(4)) .bind("Call"), this); // std::inner_product with a policy. Finder->addMatcher( callExpr(callee(functionDecl(hasName("::std::inner_product"), hasParameter(1, IteratorParam), hasParameter(3, Iterator2Param), hasParameter(4, InitParam))), argumentCountIs(5)) .bind("Call"), this); }
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 ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not // provide any benefit to other languages, despite being benign. if (!getLangOpts().CPlusPlus) return; const auto ValidContainer = cxxRecordDecl(isSameOrDerivedFrom( namedDecl( has(cxxMethodDecl( isConst(), parameterCountIs(0), isPublic(), hasName("size"), returns(qualType(isInteger(), unless(booleanType())))) .bind("size")), has(cxxMethodDecl(isConst(), parameterCountIs(0), isPublic(), hasName("empty"), returns(booleanType())) .bind("empty"))) .bind("container"))); const auto WrongUse = anyOf( hasParent(binaryOperator( matchers::isComparisonOperator(), hasEitherOperand(ignoringImpCasts(anyOf( integerLiteral(equals(1)), integerLiteral(equals(0)))))) .bind("SizeBinaryOp")), hasParent(implicitCastExpr( hasImplicitDestinationType(booleanType()), anyOf( hasParent(unaryOperator(hasOperatorName("!")).bind("NegOnSize")), anything()))), hasParent(explicitCastExpr(hasDestinationType(booleanType())))); Finder->addMatcher( cxxMemberCallExpr(on(expr(anyOf(hasType(ValidContainer), hasType(pointsTo(ValidContainer)), hasType(references(ValidContainer)))) .bind("STLObject")), callee(cxxMethodDecl(hasName("size"))), WrongUse) .bind("SizeCallExpr"), this); }
void CanRunScriptChecker::registerMatchers(MatchFinder *AstMatcher) { auto Refcounted = qualType(hasDeclaration(cxxRecordDecl(isRefCounted()))); auto InvalidArg = // We want to find any expression, ignoreTrivials(expr( // which has a refcounted pointer type, anyOf( hasType(Refcounted), hasType(pointsTo(Refcounted)), hasType(references(Refcounted)) ), // and which is not this, unless(cxxThisExpr()), // and which is not a method call on a smart ptr, unless(cxxMemberCallExpr(on(hasType(isSmartPtrToRefCounted())))), // and which is not calling operator* on a smart ptr. unless( allOf( cxxOperatorCallExpr(hasOverloadedOperatorName("*")), callExpr(allOf( hasAnyArgument(hasType(isSmartPtrToRefCounted())), argumentCountIs(1) )) ) ), // and which is not a parameter of the parent function, unless(declRefExpr(to(parmVarDecl()))), // and which is not a MOZ_KnownLive wrapped value. unless(callExpr(callee(functionDecl(hasName("MOZ_KnownLive"))))), expr().bind("invalidArg"))); auto OptionalInvalidExplicitArg = anyOf( // We want to find any argument which is invalid. hasAnyArgument(InvalidArg), // This makes this matcher optional. anything()); // Please note that the hasCanRunScriptAnnotation() matchers are not present // directly in the cxxMemberCallExpr, callExpr and constructExpr matchers // because we check that the corresponding functions can run script later in // the checker code. AstMatcher->addMatcher( expr( anyOf( // We want to match a method call expression, cxxMemberCallExpr( // which optionally has an invalid arg, OptionalInvalidExplicitArg, // or which optionally has an invalid implicit this argument, anyOf( // which derefs into an invalid arg, on(cxxOperatorCallExpr( anyOf(hasAnyArgument(InvalidArg), anything()))), // or is an invalid arg. on(InvalidArg), anything()), expr().bind("callExpr")), // or a regular call expression, callExpr( // which optionally has an invalid arg. OptionalInvalidExplicitArg, expr().bind("callExpr")), // or a construct expression, cxxConstructExpr( // which optionally has an invalid arg. OptionalInvalidExplicitArg, expr().bind("constructExpr"))), anyOf( // We want to match the parent function. forFunction(functionDecl().bind("nonCanRunScriptParentFunction")), // ... optionally. anything())), this); }