// 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