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;
mfC19 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;
mfCT38 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);
g()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
f(C c)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
f(N::V::T::U u)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
f(T t,C c)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
h()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
static_through_instance()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(*c1, *c1);
201 f(*cc, *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
usep()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
usensp()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
QptrQptr259 explicit Qptr(Q *qq) : q(qq) {}
260
operator ->Qptr261 Q *operator->() {
262 ++q->y;
263 return q;
264 }
265 };
266
func(Qptr qp)267 int 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
use_anonymous()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
use_inline()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 {
fllvm_issue_61736::__anon879790500408322 static void f() {}
323 } AnonStruct, *AnonStructPointer;
324
325 class {
326 public:
f()327 static void f() {}
328 } AnonClass, *AnonClassPointer;
329
testAnonymousStructAndClass()330 void testAnonymousStructAndClass() {
331 AnonStruct.f();
332 AnonStructPointer->f();
333
334 AnonClass.f();
335 AnonClassPointer->f();
336 }
337
338 struct Embedded {
339 struct {
fllvm_issue_61736::Embedded::__anon879790500608340 static void f() {}
341 } static EmbeddedStruct, *EmbeddedStructPointer;
342
343 class {
344 public:
f()345 static void f() {}
346 } static EmbeddedClass, *EmbeddedClassPointer;
347 };
348
testEmbeddedAnonymousStructAndClass()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
getBar()381 inline int Foo::getBar() { return 42; }
382
test()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
test(Ptr & ptr)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