// RUN: %check_clang_tidy %s cert-oop58-cpp %t // Example test cases from CERT rule // https://wiki.sei.cmu.edu/confluence/display/cplusplus/OOP58-CPP.+Copy+operations+must+not+mutate+the+source+object namespace test_mutating_noncompliant_example { class A { mutable int m; public: A() : m(0) {} explicit A(int m) : m(m) {} A(const A &other) : m(other.m) { other.m = 0; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: mutating copied object } A &operator=(const A &other) { if (&other != this) { m = other.m; other.m = 0; // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: mutating copied object } return *this; } int get_m() const { return m; } }; } // namespace test_mutating_noncompliant_example namespace test_mutating_compliant_example { class B { int m; public: B() : m(0) {} explicit B(int m) : m(m) {} B(const B &other) : m(other.m) {} B(B &&other) : m(other.m) { other.m = 0; //no-warning: mutation allowed in move constructor } B &operator=(const B &other) { if (&other != this) { m = other.m; } return *this; } B &operator=(B &&other) { m = other.m; other.m = 0; //no-warning: mutation allowed in move assignment operator return *this; } int get_m() const { return m; } }; } // namespace test_mutating_compliant_example namespace test_mutating_pointer { class C { C *ptr; int value; C(); C(C &other) { other = {}; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: mutating copied object other.ptr = nullptr; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: mutating copied object other.value = 0; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: mutating copied object // no-warning: mutating a pointee is allowed other.ptr->value = 0; *other.ptr = {}; } }; } // namespace test_mutating_pointer namespace test_mutating_indirect_member { struct S { int x; }; class D { S s; D(D &other) { other.s = {}; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: mutating copied object other.s.x = 0; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: mutating copied object } }; } // namespace test_mutating_indirect_member namespace test_mutating_other_object { class E { E(); E(E &other) { E tmp; // no-warning: mutating an object that is not the source is allowed tmp = {}; } }; } // namespace test_mutating_other_object namespace test_mutating_member_function { class F { int a; public: void bad_func() { a = 12; } void fine_func() const; void fine_func_2(int x) { x = 5; } void questionable_func(); F(F &other) : a(other.a) { this->bad_func(); // no-warning: mutating this is allowed other.bad_func(); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: call mutates copied object other.fine_func(); other.fine_func_2(42); other.questionable_func(); } }; } // namespace test_mutating_member_function namespace test_mutating_function_on_nested_object { struct S { int x; void mutate(int y) { x = y; } }; class G { S s; G(G &other) { s.mutate(0); // no-warning: mutating this is allowed other.s.mutate(0); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: call mutates copied object } }; } // namespace test_mutating_function_on_nested_object