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