// RUN: %check_clang_tidy %s readability-static-accessed-through-instance %t struct C { static void foo(); static int x; int nsx; void mf() { (void)&x; // OK, x is accessed inside the struct. (void)&C::x; // OK, x is accessed using a qualified-id. foo(); // OK, foo() is accessed inside the struct. } void ns() const; }; int C::x = 0; struct CC { void foo(); int x; }; template struct CT { static T foo(); static T x; int nsx; void mf() { (void)&x; // OK, x is accessed inside the struct. (void)&C::x; // OK, x is accessed using a qualified-id. foo(); // OK, foo() is accessed inside the struct. } }; // Expressions with side effects C &f(int, int, int, int); void g() { f(1, 2, 3, 4).x; // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through instance [readability-static-accessed-through-instance] // CHECK-FIXES: {{^}} f(1, 2, 3, 4).x;{{$}} } int i(int &); void j(int); C h(); bool a(); int k(bool); void f(C c) { j(i(h().x)); // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: static member // CHECK-FIXES: {{^}} j(i(h().x));{{$}} // The execution of h() depends on the return value of a(). j(k(a() && h().x)); // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: static member // CHECK-FIXES: {{^}} j(k(a() && h().x));{{$}} if ([c]() { c.ns(); return c; }().x == 15) ; // CHECK-MESSAGES: :[[@LINE-5]]:7: warning: static member // CHECK-FIXES: {{^}} if ([c]() {{{$}} } // Nested specifiers namespace N { struct V { static int v; struct T { static int t; struct U { static int u; }; }; }; } void f(N::V::T::U u) { N::V v; v.v = 12; // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member // CHECK-FIXES: {{^}} N::V::v = 12;{{$}} N::V::T w; w.t = 12; // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member // CHECK-FIXES: {{^}} N::V::T::t = 12;{{$}} // u.u is not changed to N::V::T::U::u; because the nesting level is over 3. u.u = 12; // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member // CHECK-FIXES: {{^}} u.u = 12;{{$}} using B = N::V::T::U; B b; b.u; // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member // CHECK-FIXES: {{^}} B::u;{{$}} } // Templates template T CT::x; template struct CCT { T foo(); T x; }; typedef C D; using E = D; #define FOO(c) c.foo() #define X(c) c.x template void f(T t, C c) { t.x; // OK, t is a template parameter. c.x; // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member // CHECK-FIXES: {{^}} C::x;{{$}} } template struct S { static int x; }; template <> struct S<0> { int x; }; template void h() { S sN; sN.x; // OK, value of N affects whether x is static or not. S<2> s2; s2.x; // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member // CHECK-FIXES: {{^}} S<2>::x;{{$}} } void static_through_instance() { C *c1 = new C(); c1->foo(); // 1 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member // CHECK-FIXES: {{^}} C::foo(); // 1{{$}} c1->x; // 2 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member // CHECK-FIXES: {{^}} C::x; // 2{{$}} c1->nsx; // OK, nsx is a non-static member. const C *c2 = new C(); c2->foo(); // 2 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member // CHECK-FIXES: {{^}} C::foo(); // 2{{$}} C::foo(); // OK, foo() is accessed using a qualified-id. C::x; // OK, x is accessed using a qualified-id. D d; d.foo(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member // CHECK-FIXES: {{^}} D::foo();{{$}} d.x; // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member // CHECK-FIXES: {{^}} D::x;{{$}} E e; e.foo(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member // CHECK-FIXES: {{^}} E::foo();{{$}} e.x; // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member // CHECK-FIXES: {{^}} E::x;{{$}} CC *cc = new CC; f(*c1, *c1); f(*cc, *c1); // Macros: OK, macros are not checked. FOO((*c1)); X((*c1)); FOO((*cc)); X((*cc)); // Templates CT ct; ct.foo(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member // CHECK-FIXES: {{^}} CT::foo();{{$}} ct.x; // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member // CHECK-FIXES: {{^}} CT::x;{{$}} ct.nsx; // OK, nsx is a non-static member CCT cct; cct.foo(); // OK, CCT has no static members. cct.x; // OK, CCT has no static members. h<4>(); } // Overloaded member access operator struct Q { static int K; int y = 0; }; int Q::K = 0; struct Qptr { Q *q; explicit Qptr(Q *qq) : q(qq) {} Q *operator->() { ++q->y; return q; } }; int func(Qptr qp) { qp->y = 10; // OK, the overloaded operator might have side-effects. qp->K = 10; // }