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