1 | // RUN: %check_clang_tidy %s readability-static-accessed-through-instance %t -- --fix-notes -- -isystem %S/Inputs/static-accessed-through-instance |
2 | #include <__clang_cuda_builtin_vars.h> |
3 | |
4 | enum OutEnum { |
5 | E0, |
6 | }; |
7 | |
8 | struct C { |
9 | static void foo(); |
10 | static int x; |
11 | int nsx; |
12 | enum { |
13 | Anonymous, |
14 | }; |
15 | enum E { |
16 | E1, |
17 | }; |
18 | using enum OutEnum; |
19 | void mf() { |
20 | (void)&x; // OK, x is accessed inside the struct. |
21 | (void)&C::x; // OK, x is accessed using a qualified-id. |
22 | foo(); // OK, foo() is accessed inside the struct. |
23 | } |
24 | void ns() const; |
25 | }; |
26 | |
27 | int C::x = 0; |
28 | |
29 | struct CC { |
30 | void foo(); |
31 | int x; |
32 | }; |
33 | |
34 | template <typename T> struct CT { |
35 | static T foo(); |
36 | static T x; |
37 | int nsx; |
38 | void mf() { |
39 | (void)&x; // OK, x is accessed inside the struct. |
40 | (void)&C::x; // OK, x is accessed using a qualified-id. |
41 | foo(); // OK, foo() is accessed inside the struct. |
42 | } |
43 | }; |
44 | |
45 | // Expressions with side effects |
46 | C &f(int, int, int, int); |
47 | void g() { |
48 | f(1, 2, 3, 4).x; |
49 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through instance [readability-static-accessed-through-instance] |
50 | // CHECK-MESSAGES: :[[@LINE-2]]:3: note: member base expression may carry some side effects |
51 | // CHECK-FIXES: {{^}} C::x;{{$}} |
52 | } |
53 | |
54 | int i(int &); |
55 | void j(int); |
56 | C h(); |
57 | bool a(); |
58 | int k(bool); |
59 | |
60 | void f(C c) { |
61 | j(i(h().x)); |
62 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: static member |
63 | // CHECK-MESSAGES: :[[@LINE-2]]:7: note: member base expression may carry some side effects |
64 | // CHECK-FIXES: {{^}} j(i(C::x));{{$}} |
65 | |
66 | // The execution of h() depends on the return value of a(). |
67 | j(k(a() && h().x)); |
68 | // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: static member |
69 | // CHECK-MESSAGES: :[[@LINE-2]]:14: note: member base expression may carry some side effects |
70 | // CHECK-FIXES: {{^}} j(k(a() && C::x));{{$}} |
71 | |
72 | if ([c]() { |
73 | c.ns(); |
74 | return c; |
75 | }().x == 15) |
76 | ; |
77 | // CHECK-MESSAGES: :[[@LINE-5]]:7: warning: static member |
78 | // CHECK-MESSAGES: :[[@LINE-6]]:7: note: member base expression may carry some side effects |
79 | // CHECK-FIXES: {{^}} if (C::x == 15){{$}} |
80 | } |
81 | |
82 | // Nested specifiers |
83 | namespace N { |
84 | struct V { |
85 | static int v; |
86 | struct T { |
87 | static int t; |
88 | struct U { |
89 | static int u; |
90 | }; |
91 | }; |
92 | }; |
93 | } |
94 | |
95 | void f(N::V::T::U u) { |
96 | N::V v; |
97 | v.v = 12; |
98 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
99 | // CHECK-FIXES: {{^}} N::V::v = 12;{{$}} |
100 | |
101 | N::V::T w; |
102 | w.t = 12; |
103 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
104 | // CHECK-FIXES: {{^}} N::V::T::t = 12;{{$}} |
105 | |
106 | // u.u is not changed to N::V::T::U::u; because the nesting level is over 3. |
107 | u.u = 12; |
108 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
109 | // CHECK-FIXES: {{^}} u.u = 12;{{$}} |
110 | |
111 | using B = N::V::T::U; |
112 | B b; |
113 | b.u; |
114 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
115 | // CHECK-FIXES: {{^}} B::u;{{$}} |
116 | } |
117 | |
118 | // Templates |
119 | template <typename T> T CT<T>::x; |
120 | |
121 | template <typename T> struct CCT { |
122 | T foo(); |
123 | T x; |
124 | }; |
125 | |
126 | typedef C D; |
127 | |
128 | using E = D; |
129 | |
130 | #define FOO(c) c.foo() |
131 | #define X(c) c.x |
132 | |
133 | template <typename T> void f(T t, C c) { |
134 | t.x; // OK, t is a template parameter. |
135 | c.x; |
136 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
137 | // CHECK-FIXES: {{^}} C::x;{{$}} |
138 | } |
139 | |
140 | template <int N> struct S { static int x; }; |
141 | |
142 | template <> struct S<0> { int x; }; |
143 | |
144 | template <int N> void h() { |
145 | S<N> sN; |
146 | sN.x; // OK, value of N affects whether x is static or not. |
147 | |
148 | S<2> s2; |
149 | s2.x; |
150 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
151 | // CHECK-FIXES: {{^}} S<2>::x;{{$}} |
152 | } |
153 | |
154 | void static_through_instance() { |
155 | C *c1 = new C(); |
156 | c1->foo(); // 1 |
157 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
158 | // CHECK-FIXES: {{^}} C::foo(); // 1{{$}} |
159 | c1->x; // 2 |
160 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
161 | // CHECK-FIXES: {{^}} C::x; // 2{{$}} |
162 | c1->Anonymous; // 3 |
163 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
164 | // CHECK-FIXES: {{^}} C::Anonymous; // 3{{$}} |
165 | c1->E1; // 4 |
166 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
167 | // CHECK-FIXES: {{^}} C::E1; // 4{{$}} |
168 | c1->E0; // 5 |
169 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
170 | // CHECK-FIXES: {{^}} C::E0; // 5{{$}} |
171 | |
172 | c1->nsx; // OK, nsx is a non-static member. |
173 | |
174 | const C *c2 = new C(); |
175 | c2->foo(); // 2 |
176 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
177 | // CHECK-FIXES: {{^}} C::foo(); // 2{{$}} |
178 | |
179 | C::foo(); // OK, foo() is accessed using a qualified-id. |
180 | C::x; // OK, x is accessed using a qualified-id. |
181 | |
182 | D d; |
183 | d.foo(); |
184 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
185 | // CHECK-FIXES: {{^}} D::foo();{{$}} |
186 | d.x; |
187 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
188 | // CHECK-FIXES: {{^}} D::x;{{$}} |
189 | |
190 | E e; |
191 | e.foo(); |
192 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
193 | // CHECK-FIXES: {{^}} E::foo();{{$}} |
194 | e.x; |
195 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
196 | // CHECK-FIXES: {{^}} E::x;{{$}} |
197 | |
198 | CC *cc = new CC; |
199 | |
200 | f(t: *c1, c: *c1); |
201 | f(t: *cc, c: *c1); |
202 | |
203 | // Macros: OK, macros are not checked. |
204 | FOO((*c1)); |
205 | X((*c1)); |
206 | FOO((*cc)); |
207 | X((*cc)); |
208 | |
209 | // Templates |
210 | CT<int> ct; |
211 | ct.foo(); |
212 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
213 | // CHECK-FIXES: {{^}} CT<int>::foo();{{$}} |
214 | ct.x; |
215 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
216 | // CHECK-FIXES: {{^}} CT<int>::x;{{$}} |
217 | ct.nsx; // OK, nsx is a non-static member |
218 | |
219 | CCT<int> cct; |
220 | cct.foo(); // OK, CCT has no static members. |
221 | cct.x; // OK, CCT has no static members. |
222 | |
223 | h<4>(); |
224 | } |
225 | |
226 | struct SP { |
227 | static int I; |
228 | } P; |
229 | |
230 | void usep() { |
231 | P.I; |
232 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
233 | // CHECK-FIXES: {{^}} SP::I;{{$}} |
234 | } |
235 | |
236 | namespace NSP { |
237 | struct SP { |
238 | static int I; |
239 | } P; |
240 | } // namespace NSP |
241 | |
242 | void usensp() { |
243 | NSP::P.I; |
244 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
245 | // CHECK-FIXES: {{^}} NSP::SP::I;{{$}} |
246 | } |
247 | |
248 | // Overloaded member access operator |
249 | struct Q { |
250 | static int K; |
251 | int y = 0; |
252 | }; |
253 | |
254 | int Q::K = 0; |
255 | |
256 | struct Qptr { |
257 | Q *q; |
258 | |
259 | explicit Qptr(Q *qq) : q(qq) {} |
260 | |
261 | Q *operator->() { |
262 | ++q->y; |
263 | return q; |
264 | } |
265 | }; |
266 | |
267 | void func(Qptr qp) { |
268 | qp->y = 10; |
269 | qp->K = 10; |
270 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through instance [readability-static-accessed-through-instance] |
271 | // CHECK-MESSAGES: :[[@LINE-2]]:3: note: member base expression may carry some side effects |
272 | // CHECK-FIXES: {{^}} Q::K = 10; |
273 | } |
274 | |
275 | namespace { |
276 | struct Anonymous { |
277 | static int I; |
278 | }; |
279 | } |
280 | |
281 | void use_anonymous() { |
282 | Anonymous Anon; |
283 | Anon.I; |
284 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
285 | // CHECK-FIXES: {{^}} Anonymous::I;{{$}} |
286 | } |
287 | |
288 | namespace Outer { |
289 | inline namespace Inline { |
290 | struct S { |
291 | static int I; |
292 | }; |
293 | } |
294 | } |
295 | |
296 | void use_inline() { |
297 | Outer::S V; |
298 | V.I; |
299 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member |
300 | // CHECK-FIXES: {{^}} Outer::S::I;{{$}} |
301 | } |
302 | |
303 | // https://bugs.llvm.org/show_bug.cgi?id=48758 |
304 | namespace Bugzilla_48758 { |
305 | |
306 | unsigned int x1 = threadIdx.x; |
307 | // CHECK-MESSAGES-NOT: :[[@LINE-1]]:10: warning: static member |
308 | unsigned int x2 = blockIdx.x; |
309 | // CHECK-MESSAGES-NOT: :[[@LINE-1]]:10: warning: static member |
310 | unsigned int x3 = blockDim.x; |
311 | // CHECK-MESSAGES-NOT: :[[@LINE-1]]:10: warning: static member |
312 | unsigned int x4 = gridDim.x; |
313 | // CHECK-MESSAGES-NOT: :[[@LINE-1]]:10: warning: static member |
314 | |
315 | } // namespace Bugzilla_48758 |
316 | |
317 | // https://github.com/llvm/llvm-project/issues/61736 |
318 | namespace llvm_issue_61736 |
319 | { |
320 | |
321 | struct { |
322 | static void f() {} |
323 | } AnonStruct, *AnonStructPointer; |
324 | |
325 | class { |
326 | public: |
327 | static void f() {} |
328 | } AnonClass, *AnonClassPointer; |
329 | |
330 | void testAnonymousStructAndClass() { |
331 | AnonStruct.f(); |
332 | AnonStructPointer->f(); |
333 | |
334 | AnonClass.f(); |
335 | AnonClassPointer->f(); |
336 | } |
337 | |
338 | struct Embedded { |
339 | struct { |
340 | static void f() {} |
341 | } static EmbeddedStruct, *EmbeddedStructPointer; |
342 | |
343 | class { |
344 | public: |
345 | static void f() {} |
346 | } static EmbeddedClass, *EmbeddedClassPointer; |
347 | }; |
348 | |
349 | void testEmbeddedAnonymousStructAndClass() { |
350 | Embedded::EmbeddedStruct.f(); |
351 | Embedded::EmbeddedStructPointer->f(); |
352 | |
353 | Embedded::EmbeddedClass.f(); |
354 | Embedded::EmbeddedClassPointer->f(); |
355 | |
356 | Embedded E; |
357 | E.EmbeddedStruct.f(); |
358 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through instance [readability-static-accessed-through-instance] |
359 | // CHECK-FIXES: {{^}} llvm_issue_61736::Embedded::EmbeddedStruct.f();{{$}} |
360 | E.EmbeddedStructPointer->f(); |
361 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through instance [readability-static-accessed-through-instance] |
362 | // CHECK-FIXES: {{^}} llvm_issue_61736::Embedded::EmbeddedStructPointer->f();{{$}} |
363 | |
364 | E.EmbeddedClass.f(); |
365 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through instance [readability-static-accessed-through-instance] |
366 | // CHECK-FIXES: {{^}} llvm_issue_61736::Embedded::EmbeddedClass.f();{{$}} |
367 | E.EmbeddedClassPointer->f(); |
368 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through instance [readability-static-accessed-through-instance] |
369 | // CHECK-FIXES: {{^}} llvm_issue_61736::Embedded::EmbeddedClassPointer->f();{{$}} |
370 | } |
371 | |
372 | } // namespace llvm_issue_61736 |
373 | |
374 | namespace PR51861 { |
375 | class Foo { |
376 | public: |
377 | static Foo& getInstance(); |
378 | static int getBar(); |
379 | }; |
380 | |
381 | inline int Foo::getBar() { return 42; } |
382 | |
383 | void test() { |
384 | auto& params = Foo::getInstance(); |
385 | params.getBar(); |
386 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: static member accessed through instance [readability-static-accessed-through-instance] |
387 | // CHECK-FIXES: {{^}} PR51861::Foo::getBar();{{$}} |
388 | } |
389 | } |
390 | |
391 | namespace PR75163 { |
392 | struct Static { |
393 | static void call(); |
394 | }; |
395 | |
396 | struct Ptr { |
397 | Static* operator->(); |
398 | }; |
399 | |
400 | void test(Ptr& ptr) { |
401 | ptr->call(); |
402 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: static member accessed through instance [readability-static-accessed-through-instance] |
403 | // CHECK-MESSAGES: :[[@LINE-2]]:5: note: member base expression may carry some side effects |
404 | // CHECK-FIXES: {{^}} PR75163::Static::call();{{$}} |
405 | } |
406 | } |
407 | |