1// RUN: %check_clang_tidy %s cert-oop58-cpp %t
2
3// Example test cases from CERT rule
4// https://wiki.sei.cmu.edu/confluence/display/cplusplus/OOP58-CPP.+Copy+operations+must+not+mutate+the+source+object
5namespace test_mutating_noncompliant_example {
6class A {
7 mutable int m;
8
9public:
10 A() : m(0) {}
11 explicit A(int m) : m(m) {}
12
13 A(const A &other) : m(other.m) {
14 other.m = 0;
15 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: mutating copied object
16 }
17
18 A &operator=(const A &other) {
19 if (&other != this) {
20 m = other.m;
21 other.m = 0;
22 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: mutating copied object
23 }
24 return *this;
25 }
26
27 int get_m() const { return m; }
28};
29} // namespace test_mutating_noncompliant_example
30
31namespace test_mutating_compliant_example {
32class B {
33 int m;
34
35public:
36 B() : m(0) {}
37 explicit B(int m) : m(m) {}
38
39 B(const B &other) : m(other.m) {}
40 B(B &&other) : m(other.m) {
41 other.m = 0; //no-warning: mutation allowed in move constructor
42 }
43
44 B &operator=(const B &other) {
45 if (&other != this) {
46 m = other.m;
47 }
48 return *this;
49 }
50
51 B &operator=(B &&other) {
52 m = other.m;
53 other.m = 0; //no-warning: mutation allowed in move assignment operator
54 return *this;
55 }
56
57 int get_m() const { return m; }
58};
59} // namespace test_mutating_compliant_example
60
61namespace test_mutating_pointer {
62class C {
63 C *ptr;
64 int value;
65
66 C();
67 C(C &other) {
68 other = {};
69 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: mutating copied object
70 other.ptr = nullptr;
71 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: mutating copied object
72 other.value = 0;
73 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: mutating copied object
74
75 // no-warning: mutating a pointee is allowed
76 other.ptr->value = 0;
77 *other.ptr = {};
78 }
79};
80} // namespace test_mutating_pointer
81
82namespace test_mutating_indirect_member {
83struct S {
84 int x;
85};
86
87class D {
88 S s;
89 D(D &other) {
90 other.s = {};
91 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: mutating copied object
92 other.s.x = 0;
93 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: mutating copied object
94 }
95};
96} // namespace test_mutating_indirect_member
97
98namespace test_mutating_other_object {
99class E {
100 E();
101 E(E &other) {
102 E tmp;
103 // no-warning: mutating an object that is not the source is allowed
104 tmp = {};
105 }
106};
107} // namespace test_mutating_other_object
108
109namespace test_mutating_member_function {
110class F {
111 int a;
112
113public:
114 void bad_func() { a = 12; }
115 void fine_func() const;
116 void fine_func_2(int x) { x = 5; }
117 void questionable_func();
118
119 F(F &other) : a(other.a) {
120 this->bad_func(); // no-warning: mutating this is allowed
121
122 other.bad_func();
123 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: call mutates copied object
124
125 other.fine_func();
126 other.fine_func_2(x: 42);
127 other.questionable_func();
128 }
129};
130} // namespace test_mutating_member_function
131
132namespace test_mutating_function_on_nested_object {
133struct S {
134 int x;
135 void mutate(int y) {
136 x = y;
137 }
138};
139
140class G {
141 S s;
142 G(G &other) {
143 s.mutate(y: 0); // no-warning: mutating this is allowed
144
145 other.s.mutate(y: 0);
146 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: call mutates copied object
147 }
148};
149} // namespace test_mutating_function_on_nested_object
150

source code of clang-tools-extra/test/clang-tidy/checkers/cert/oop58-cpp.cpp