1 // RUN: %check_clang_tidy %s readability-static-accessed-through-instance %t
2 
3 struct C {
4   static void foo();
5   static int x;
6   int nsx;
mfC7   void mf() {
8     (void)&x;    // OK, x is accessed inside the struct.
9     (void)&C::x; // OK, x is accessed using a qualified-id.
10     foo();       // OK, foo() is accessed inside the struct.
11   }
12   void ns() const;
13 };
14 
15 int C::x = 0;
16 
17 struct CC {
18   void foo();
19   int x;
20 };
21 
22 template <typename T> struct CT {
23   static T foo();
24   static T x;
25   int nsx;
mfCT26   void mf() {
27     (void)&x;    // OK, x is accessed inside the struct.
28     (void)&C::x; // OK, x is accessed using a qualified-id.
29     foo();       // OK, foo() is accessed inside the struct.
30   }
31 };
32 
33 // Expressions with side effects
34 C &f(int, int, int, int);
g()35 void g() {
36   f(1, 2, 3, 4).x;
37   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through instance  [readability-static-accessed-through-instance]
38   // CHECK-FIXES: {{^}}  f(1, 2, 3, 4).x;{{$}}
39 }
40 
41 int i(int &);
42 void j(int);
43 C h();
44 bool a();
45 int k(bool);
46 
f(C c)47 void f(C c) {
48   j(i(h().x));
49   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: static member
50   // CHECK-FIXES: {{^}}  j(i(h().x));{{$}}
51 
52   // The execution of h() depends on the return value of a().
53   j(k(a() && h().x));
54   // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: static member
55   // CHECK-FIXES: {{^}}  j(k(a() && h().x));{{$}}
56 
57   if ([c]() {
58         c.ns();
59         return c;
60       }().x == 15)
61     ;
62   // CHECK-MESSAGES: :[[@LINE-5]]:7: warning: static member
63   // CHECK-FIXES: {{^}}  if ([c]() {{{$}}
64 }
65 
66 // Nested specifiers
67 namespace N {
68 struct V {
69   static int v;
70   struct T {
71     static int t;
72     struct U {
73       static int u;
74     };
75   };
76 };
77 }
78 
f(N::V::T::U u)79 void f(N::V::T::U u) {
80   N::V v;
81   v.v = 12;
82   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
83   // CHECK-FIXES: {{^}}  N::V::v = 12;{{$}}
84 
85   N::V::T w;
86   w.t = 12;
87   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
88   // CHECK-FIXES: {{^}}  N::V::T::t = 12;{{$}}
89 
90   // u.u is not changed to N::V::T::U::u; because the nesting level is over 3.
91   u.u = 12;
92   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
93   // CHECK-FIXES: {{^}}  u.u = 12;{{$}}
94 
95   using B = N::V::T::U;
96   B b;
97   b.u;
98   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
99   // CHECK-FIXES: {{^}}  B::u;{{$}}
100 }
101 
102 // Templates
103 template <typename T> T CT<T>::x;
104 
105 template <typename T> struct CCT {
106   T foo();
107   T x;
108 };
109 
110 typedef C D;
111 
112 using E = D;
113 
114 #define FOO(c) c.foo()
115 #define X(c) c.x
116 
f(T t,C c)117 template <typename T> void f(T t, C c) {
118   t.x; // OK, t is a template parameter.
119   c.x;
120   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
121   // CHECK-FIXES: {{^}}  C::x;{{$}}
122 }
123 
124 template <int N> struct S { static int x; };
125 
126 template <> struct S<0> { int x; };
127 
h()128 template <int N> void h() {
129   S<N> sN;
130   sN.x; // OK, value of N affects whether x is static or not.
131 
132   S<2> s2;
133   s2.x;
134   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
135   // CHECK-FIXES: {{^}}  S<2>::x;{{$}}
136 }
137 
static_through_instance()138 void static_through_instance() {
139   C *c1 = new C();
140   c1->foo(); // 1
141   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
142   // CHECK-FIXES: {{^}}  C::foo(); // 1{{$}}
143   c1->x; // 2
144   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
145   // CHECK-FIXES: {{^}}  C::x; // 2{{$}}
146   c1->nsx; // OK, nsx is a non-static member.
147 
148   const C *c2 = new C();
149   c2->foo(); // 2
150   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
151   // CHECK-FIXES: {{^}}  C::foo(); // 2{{$}}
152 
153   C::foo(); // OK, foo() is accessed using a qualified-id.
154   C::x;     // OK, x is accessed using a qualified-id.
155 
156   D d;
157   d.foo();
158   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
159   // CHECK-FIXES: {{^}}  D::foo();{{$}}
160   d.x;
161   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
162   // CHECK-FIXES: {{^}}  D::x;{{$}}
163 
164   E e;
165   e.foo();
166   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
167   // CHECK-FIXES: {{^}}  E::foo();{{$}}
168   e.x;
169   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
170   // CHECK-FIXES: {{^}}  E::x;{{$}}
171 
172   CC *cc = new CC;
173 
174   f(*c1, *c1);
175   f(*cc, *c1);
176 
177   // Macros: OK, macros are not checked.
178   FOO((*c1));
179   X((*c1));
180   FOO((*cc));
181   X((*cc));
182 
183   // Templates
184   CT<int> ct;
185   ct.foo();
186   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
187   // CHECK-FIXES: {{^}}  CT<int>::foo();{{$}}
188   ct.x;
189   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
190   // CHECK-FIXES: {{^}}  CT<int>::x;{{$}}
191   ct.nsx; // OK, nsx is a non-static member
192 
193   CCT<int> cct;
194   cct.foo(); // OK, CCT has no static members.
195   cct.x;     // OK, CCT has no static members.
196 
197   h<4>();
198 }
199 
200 // Overloaded member access operator
201 struct Q {
202   static int K;
203   int y = 0;
204 };
205 
206 int Q::K = 0;
207 
208 struct Qptr {
209   Q *q;
210 
QptrQptr211   explicit Qptr(Q *qq) : q(qq) {}
212 
operator ->Qptr213   Q *operator->() {
214     ++q->y;
215     return q;
216   }
217 };
218 
func(Qptr qp)219 int func(Qptr qp) {
220   qp->y = 10; // OK, the overloaded operator might have side-effects.
221   qp->K = 10; //
222 }
223 
224 namespace {
225   struct Anonymous {
226     static int I;
227   };
228 }
229 
use_anonymous()230 void use_anonymous() {
231   Anonymous Anon;
232   Anon.I;
233   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
234   // CHECK-FIXES: {{^}}  Anonymous::I;{{$}}
235 }
236 
237 namespace Outer {
238   inline namespace Inline {
239     struct S {
240       static int I;
241     };
242   }
243 }
244 
use_inline()245 void use_inline() {
246   Outer::S V;
247   V.I;
248   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
249   // CHECK-FIXES: {{^}}  Outer::S::I;{{$}}
250 }
251