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
4enum OutEnum {
5 E0,
6};
7
8struct 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
27int C::x = 0;
28
29struct CC {
30 void foo();
31 int x;
32};
33
34template <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
46C &f(int, int, int, int);
47void 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
53int i(int &);
54void j(int);
55C h();
56bool a();
57int k(bool);
58
59void 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
79namespace N {
80struct V {
81 static int v;
82 struct T {
83 static int t;
84 struct U {
85 static int u;
86 };
87 };
88};
89}
90
91void 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
115template <typename T> T CT<T>::x;
116
117template <typename T> struct CCT {
118 T foo();
119 T x;
120};
121
122typedef C D;
123
124using E = D;
125
126#define FOO(c) c.foo()
127#define X(c) c.x
128
129template <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
136template <int N> struct S { static int x; };
137
138template <> struct S<0> { int x; };
139
140template <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
150void 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
222struct SP {
223 static int I;
224} P;
225
226void usep() {
227 P.I;
228 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
229 // CHECK-FIXES: {{^}} SP::I;{{$}}
230}
231
232namespace NSP {
233struct SP {
234 static int I;
235} P;
236} // namespace NSP
237
238void 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
245struct Q {
246 static int K;
247 int y = 0;
248};
249
250int Q::K = 0;
251
252struct 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
263int func(Qptr qp) {
264 qp->y = 10; // OK, the overloaded operator might have side-effects.
265 qp->K = 10; //
266}
267
268namespace {
269 struct Anonymous {
270 static int I;
271 };
272}
273
274void use_anonymous() {
275 Anonymous Anon;
276 Anon.I;
277 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
278 // CHECK-FIXES: {{^}} Anonymous::I;{{$}}
279}
280
281namespace Outer {
282 inline namespace Inline {
283 struct S {
284 static int I;
285 };
286 }
287}
288
289void 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
297namespace Bugzilla_48758 {
298
299unsigned int x1 = threadIdx.x;
300// CHECK-MESSAGES-NOT: :[[@LINE-1]]:10: warning: static member
301unsigned int x2 = blockIdx.x;
302// CHECK-MESSAGES-NOT: :[[@LINE-1]]:10: warning: static member
303unsigned int x3 = blockDim.x;
304// CHECK-MESSAGES-NOT: :[[@LINE-1]]:10: warning: static member
305unsigned 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
311namespace llvm_issue_61736
312{
313
314struct {
315 static void f() {}
316} AnonStruct, *AnonStructPointer;
317
318class {
319 public:
320 static void f() {}
321} AnonClass, *AnonClassPointer;
322
323void testAnonymousStructAndClass() {
324 AnonStruct.f();
325 AnonStructPointer->f();
326
327 AnonClass.f();
328 AnonClassPointer->f();
329}
330
331struct 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
342void 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
367namespace 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

source code of clang-tools-extra/test/clang-tidy/checkers/readability/static-accessed-through-instance.cpp