void PassByValueCheck::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; Finder->addMatcher( cxxConstructorDecl( forEachConstructorInitializer( cxxCtorInitializer( // Clang builds a CXXConstructExpr only whin it knows which // constructor will be called. In dependent contexts a // ParenListExpr is generated instead of a CXXConstructExpr, // filtering out templates automatically for us. withInitializer(cxxConstructExpr( has(ignoringParenImpCasts(declRefExpr(to( parmVarDecl( hasType(qualType( // Match only const-ref or a non-const value // parameters. Rvalues and const-values // shouldn't be modified. anyOf(constRefType(), nonConstValueType())))) .bind("Param"))))), hasDeclaration(cxxConstructorDecl( isCopyConstructor(), unless(isDeleted()), hasDeclContext( cxxRecordDecl(isMoveConstructible()))))))) .bind("Initializer"))) .bind("Ctor"), this); }
void UseEqualsDeleteCheck::registerMatchers(MatchFinder *Finder) { auto PrivateSpecialFn = cxxMethodDecl( isPrivate(), anyOf(cxxConstructorDecl(anyOf(isDefaultConstructor(), isCopyConstructor(), isMoveConstructor())), cxxMethodDecl( anyOf(isCopyAssignmentOperator(), isMoveAssignmentOperator())), cxxDestructorDecl())); Finder->addMatcher( cxxMethodDecl( PrivateSpecialFn, unless(anyOf(hasBody(stmt()), isDefaulted(), isDeleted(), ast_matchers::isTemplateInstantiation(), // Ensure that all methods except private special member // functions are defined. hasParent(cxxRecordDecl(hasMethod(unless( anyOf(PrivateSpecialFn, hasBody(stmt()), isPure(), isDefaulted(), isDeleted())))))))) .bind(SpecialFunction), this); Finder->addMatcher( cxxMethodDecl(isDeleted(), unless(isPublic())).bind(DeletedNotPublic), this); }
void MoveConstructorInitCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++11; the functionality currently does not // provide any benefit to other languages, despite being benign. if (!getLangOpts().CPlusPlus11) return; Finder->addMatcher( cxxConstructorDecl( unless(isImplicit()), allOf(isMoveConstructor(), hasAnyConstructorInitializer( cxxCtorInitializer( withInitializer(cxxConstructExpr(hasDeclaration( cxxConstructorDecl(isCopyConstructor()) .bind("ctor"))))) .bind("move-init")))), this); auto NonConstValueMovableAndExpensiveToCopy = qualType(allOf(unless(pointerType()), unless(isConstQualified()), hasDeclaration(cxxRecordDecl(hasMethod(cxxConstructorDecl( isMoveConstructor(), unless(isDeleted()))))), matchers::isExpensiveToCopy())); // This checker is also used to implement cert-oop11-cpp, but when using that // form of the checker, we do not want to diagnose movable parameters. if (!UseCERTSemantics) { Finder->addMatcher( cxxConstructorDecl( allOf( unless(isMoveConstructor()), hasAnyConstructorInitializer(withInitializer(cxxConstructExpr( hasDeclaration(cxxConstructorDecl(isCopyConstructor())), hasArgument( 0, declRefExpr( to(parmVarDecl( hasType( NonConstValueMovableAndExpensiveToCopy)) .bind("movable-param"))) .bind("init-arg"))))))) .bind("ctor-decl"), this); } }
void ThrownExceptionTypeCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; Finder->addMatcher( cxxThrowExpr(has(ignoringParenImpCasts( cxxConstructExpr(hasDeclaration(cxxConstructorDecl( isCopyConstructor(), unless(isNoThrow())))) .bind("expr")))), this); }
void MoveConstructorInitCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++11; the functionality currently does not // provide any benefit to other languages, despite being benign. if (getLangOpts().CPlusPlus11) { Finder->addMatcher( constructorDecl(unless(isImplicit()), allOf( isMoveConstructor(), hasAnyConstructorInitializer( ctorInitializer(withInitializer(constructExpr(hasDeclaration( constructorDecl(isCopyConstructor()).bind("ctor") )))).bind("init") ) )), this); } }
void SlicingCheck::registerMatchers(MatchFinder *Finder) { // When we see: // class B : public A { ... }; // A a; // B b; // a = b; // The assignment is OK if: // - the assignment operator is defined as taking a B as second parameter, // or // - B does not define any additional members (either variables or // overrides) wrt A. // // The same holds for copy ctor calls. This also captures stuff like: // void f(A a); // f(b); // Helpers. const auto OfBaseClass = ofClass(cxxRecordDecl().bind("BaseDecl")); const auto IsDerivedFromBaseDecl = cxxRecordDecl(isDerivedFrom(equalsBoundNode("BaseDecl"))) .bind("DerivedDecl"); const auto HasTypeDerivedFromBaseDecl = anyOf(hasType(IsDerivedFromBaseDecl), hasType(references(IsDerivedFromBaseDecl))); const auto IsWithinDerivedCtor = hasParent(cxxConstructorDecl(ofClass(equalsBoundNode("DerivedDecl")))); // Assignement slicing: "a = b;" and "a = std::move(b);" variants. const auto SlicesObjectInAssignment = callExpr(callee(cxxMethodDecl(anyOf(isCopyAssignmentOperator(), isMoveAssignmentOperator()), OfBaseClass)), hasArgument(1, HasTypeDerivedFromBaseDecl)); // Construction slicing: "A a{b};" and "f(b);" variants. Note that in case of // slicing the letter will create a temporary and therefore call a ctor. const auto SlicesObjectInCtor = cxxConstructExpr( hasDeclaration(cxxConstructorDecl( anyOf(isCopyConstructor(), isMoveConstructor()), OfBaseClass)), hasArgument(0, HasTypeDerivedFromBaseDecl), // We need to disable matching on the call to the base copy/move // constructor in DerivedDecl's constructors. unless(IsWithinDerivedCtor)); Finder->addMatcher( expr(anyOf(SlicesObjectInAssignment, SlicesObjectInCtor)).bind("Call"), this); }
void SpecialMemberFunctionsCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; Finder->addMatcher( cxxRecordDecl( eachOf( has(cxxDestructorDecl(unless(isImplicit())).bind("dtor")), has(cxxConstructorDecl(isCopyConstructor(), unless(isImplicit())) .bind("copy-ctor")), has(cxxMethodDecl(isCopyAssignmentOperator(), unless(isImplicit())) .bind("copy-assign")), has(cxxConstructorDecl(isMoveConstructor(), unless(isImplicit())) .bind("move-ctor")), has(cxxMethodDecl(isMoveAssignmentOperator(), unless(isImplicit())) .bind("move-assign")))) .bind("class-def"), this); }