1 // RUN: %check_clang_tidy %s readability-static-accessed-through-instance %t
2
3 struct C {
4 static void foo();
5 static int x;
6 int nsx;
mfC7 void mf() {
8 (void)&x; // OK, x is accessed inside the struct.
9 (void)&C::x; // OK, x is accessed using a qualified-id.
10 foo(); // OK, foo() is accessed inside the struct.
11 }
12 void ns() const;
13 };
14
15 int C::x = 0;
16
17 struct CC {
18 void foo();
19 int x;
20 };
21
22 template <typename T> struct CT {
23 static T foo();
24 static T x;
25 int nsx;
mfCT26 void mf() {
27 (void)&x; // OK, x is accessed inside the struct.
28 (void)&C::x; // OK, x is accessed using a qualified-id.
29 foo(); // OK, foo() is accessed inside the struct.
30 }
31 };
32
33 // Expressions with side effects
34 C &f(int, int, int, int);
g()35 void g() {
36 f(1, 2, 3, 4).x;
37 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through instance [readability-static-accessed-through-instance]
38 // CHECK-FIXES: {{^}} f(1, 2, 3, 4).x;{{$}}
39 }
40
41 int i(int &);
42 void j(int);
43 C h();
44 bool a();
45 int k(bool);
46
f(C c)47 void f(C c) {
48 j(i(h().x));
49 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: static member
50 // CHECK-FIXES: {{^}} j(i(h().x));{{$}}
51
52 // The execution of h() depends on the return value of a().
53 j(k(a() && h().x));
54 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: static member
55 // CHECK-FIXES: {{^}} j(k(a() && h().x));{{$}}
56
57 if ([c]() {
58 c.ns();
59 return c;
60 }().x == 15)
61 ;
62 // CHECK-MESSAGES: :[[@LINE-5]]:7: warning: static member
63 // CHECK-FIXES: {{^}} if ([c]() {{{$}}
64 }
65
66 // Nested specifiers
67 namespace N {
68 struct V {
69 static int v;
70 struct T {
71 static int t;
72 struct U {
73 static int u;
74 };
75 };
76 };
77 }
78
f(N::V::T::U u)79 void f(N::V::T::U u) {
80 N::V v;
81 v.v = 12;
82 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
83 // CHECK-FIXES: {{^}} N::V::v = 12;{{$}}
84
85 N::V::T w;
86 w.t = 12;
87 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
88 // CHECK-FIXES: {{^}} N::V::T::t = 12;{{$}}
89
90 // u.u is not changed to N::V::T::U::u; because the nesting level is over 3.
91 u.u = 12;
92 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
93 // CHECK-FIXES: {{^}} u.u = 12;{{$}}
94
95 using B = N::V::T::U;
96 B b;
97 b.u;
98 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
99 // CHECK-FIXES: {{^}} B::u;{{$}}
100 }
101
102 // Templates
103 template <typename T> T CT<T>::x;
104
105 template <typename T> struct CCT {
106 T foo();
107 T x;
108 };
109
110 typedef C D;
111
112 using E = D;
113
114 #define FOO(c) c.foo()
115 #define X(c) c.x
116
f(T t,C c)117 template <typename T> void f(T t, C c) {
118 t.x; // OK, t is a template parameter.
119 c.x;
120 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
121 // CHECK-FIXES: {{^}} C::x;{{$}}
122 }
123
124 template <int N> struct S { static int x; };
125
126 template <> struct S<0> { int x; };
127
h()128 template <int N> void h() {
129 S<N> sN;
130 sN.x; // OK, value of N affects whether x is static or not.
131
132 S<2> s2;
133 s2.x;
134 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
135 // CHECK-FIXES: {{^}} S<2>::x;{{$}}
136 }
137
static_through_instance()138 void static_through_instance() {
139 C *c1 = new C();
140 c1->foo(); // 1
141 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
142 // CHECK-FIXES: {{^}} C::foo(); // 1{{$}}
143 c1->x; // 2
144 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
145 // CHECK-FIXES: {{^}} C::x; // 2{{$}}
146 c1->nsx; // OK, nsx is a non-static member.
147
148 const C *c2 = new C();
149 c2->foo(); // 2
150 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
151 // CHECK-FIXES: {{^}} C::foo(); // 2{{$}}
152
153 C::foo(); // OK, foo() is accessed using a qualified-id.
154 C::x; // OK, x is accessed using a qualified-id.
155
156 D d;
157 d.foo();
158 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
159 // CHECK-FIXES: {{^}} D::foo();{{$}}
160 d.x;
161 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
162 // CHECK-FIXES: {{^}} D::x;{{$}}
163
164 E e;
165 e.foo();
166 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
167 // CHECK-FIXES: {{^}} E::foo();{{$}}
168 e.x;
169 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
170 // CHECK-FIXES: {{^}} E::x;{{$}}
171
172 CC *cc = new CC;
173
174 f(*c1, *c1);
175 f(*cc, *c1);
176
177 // Macros: OK, macros are not checked.
178 FOO((*c1));
179 X((*c1));
180 FOO((*cc));
181 X((*cc));
182
183 // Templates
184 CT<int> ct;
185 ct.foo();
186 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
187 // CHECK-FIXES: {{^}} CT<int>::foo();{{$}}
188 ct.x;
189 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
190 // CHECK-FIXES: {{^}} CT<int>::x;{{$}}
191 ct.nsx; // OK, nsx is a non-static member
192
193 CCT<int> cct;
194 cct.foo(); // OK, CCT has no static members.
195 cct.x; // OK, CCT has no static members.
196
197 h<4>();
198 }
199
200 // Overloaded member access operator
201 struct Q {
202 static int K;
203 int y = 0;
204 };
205
206 int Q::K = 0;
207
208 struct Qptr {
209 Q *q;
210
QptrQptr211 explicit Qptr(Q *qq) : q(qq) {}
212
operator ->Qptr213 Q *operator->() {
214 ++q->y;
215 return q;
216 }
217 };
218
func(Qptr qp)219 int func(Qptr qp) {
220 qp->y = 10; // OK, the overloaded operator might have side-effects.
221 qp->K = 10; //
222 }
223
224 namespace {
225 struct Anonymous {
226 static int I;
227 };
228 }
229
use_anonymous()230 void use_anonymous() {
231 Anonymous Anon;
232 Anon.I;
233 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
234 // CHECK-FIXES: {{^}} Anonymous::I;{{$}}
235 }
236
237 namespace Outer {
238 inline namespace Inline {
239 struct S {
240 static int I;
241 };
242 }
243 }
244
use_inline()245 void use_inline() {
246 Outer::S V;
247 V.I;
248 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
249 // CHECK-FIXES: {{^}} Outer::S::I;{{$}}
250 }
251