@@ -68,7 +68,23 @@ void UnhandledSelfAssignmentCheck::registerMatchers(MatchFinder *Finder) {
6868 const auto HasNoNestedSelfAssign =
6969 cxxMethodDecl (unless (hasDescendant (cxxMemberCallExpr (callee (cxxMethodDecl (
7070 hasName (" operator=" ), ofClass (equalsBoundNode (" class" ))))))));
71-
71+
72+ // Checking that some kind of constructor is called and followed by a `swap`:
73+ // T& operator=(const T& other) {
74+ // T tmp{this->internal_data(), some, other, args};
75+ // swap(tmp);
76+ // return *this;
77+ // }
78+ const auto HasCopyAndSwap = cxxMethodDecl (
79+ ofClass (cxxRecordDecl (unless (hasAncestor (classTemplateDecl ())))),
80+ hasDescendant (
81+ stmt (hasDescendant (
82+ varDecl (hasType (cxxRecordDecl (equalsBoundNode (" class" ))))
83+ .bind (" tmp_var" )),
84+ hasDescendant (callExpr (callee (functionDecl (hasName (" swap" ))),
85+ hasAnyArgument (declRefExpr (to (varDecl (
86+ equalsBoundNode (" tmp_var" ))))))))));
87+
7288 DeclarationMatcher AdditionalMatcher = cxxMethodDecl ();
7389 if (WarnOnlyIfThisHasSuspiciousField) {
7490 // Matcher for standard smart pointers.
@@ -94,6 +110,7 @@ void UnhandledSelfAssignmentCheck::registerMatchers(MatchFinder *Finder) {
94110 HasReferenceParam, HasNoSelfCheck,
95111 unless (HasNonTemplateSelfCopy),
96112 unless (HasTemplateSelfCopy),
113+ unless (HasCopyAndSwap),
97114 HasNoNestedSelfAssign, AdditionalMatcher)
98115 .bind (" copyAssignmentOperator" ),
99116 this );
0 commit comments