1 // RUN: %check_clang_tidy %s readability-convert-member-functions-to-static %t
2 
3 class DoNotMakeEmptyStatic {
emptyMethod()4   void emptyMethod() {}
5   void empty_method_out_of_line();
6 };
7 
empty_method_out_of_line()8 void DoNotMakeEmptyStatic::empty_method_out_of_line() {}
9 
10 class A {
11   int field;
12   const int const_field;
13   static int static_field;
14 
no_use()15   void no_use() {
16     // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'no_use' can be made static
17     // CHECK-FIXES: {{^}}  static void no_use() {
18     int i = 1;
19   }
20 
read_field()21   int read_field() {
22     return field;
23   }
24 
write_field()25   void write_field() {
26     field = 1;
27   }
28 
call_non_const_member()29   int call_non_const_member() { return read_field(); }
30 
call_static_member()31   int call_static_member() {
32     // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'call_static_member' can be made static
33     // CHECK-FIXES: {{^}}  static int call_static_member() {
34     already_static();
35   }
36 
read_static()37   int read_static() {
38     // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_static' can be made static
39     // CHECK-FIXES: {{^}}  static int read_static() {
40     return static_field;
41   }
write_static()42   void write_static() {
43     // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'write_static' can be made static
44     // CHECK-FIXES: {{^}}  static void write_static() {
45     static_field = 1;
46   }
47 
static_nested()48   void static_nested() {
49     // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'static_nested' can be made static
50     // CHECK-FIXES: {{^}}  static void static_nested() {
51     struct Nested {
52       int Foo;
53       int getFoo() { return Foo; }
54     };
55   }
56 
write_nested()57   void write_nested() {
58     struct Nested {
59       int Foo;
60       int getFoo() { return Foo; }
61     };
62     // Ensure we still detect usages of `this` once we leave the nested class definition.
63     field = 1;
64   }
65 
already_static()66   static int already_static() { return static_field; }
67 
already_const() const68   int already_const() const { return field; }
69 
already_const_convert_to_static() const70   int already_const_convert_to_static() const {
71     // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'already_const_convert_to_static' can be made static
72     // CHECK-FIXES: {{^}}  static int already_const_convert_to_static() {
73     return static_field;
74   }
75 
76   static int out_of_line_already_static();
77 
78   void out_of_line_call_static();
79   // CHECK-FIXES: {{^}}  static void out_of_line_call_static();
80   int out_of_line_const_to_static() const;
81   // CHECK-FIXES: {{^}}  static int out_of_line_const_to_static() ;
82 };
83 
out_of_line_already_static()84 int A::out_of_line_already_static() { return 0; }
85 
out_of_line_call_static()86 void A::out_of_line_call_static() {
87   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: method 'out_of_line_call_static' can be made static
88   // CHECK-FIXES: {{^}}void A::out_of_line_call_static() {
89   already_static();
90 }
91 
out_of_line_const_to_static() const92 int A::out_of_line_const_to_static() const {
93   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'out_of_line_const_to_static' can be made static
94   // CHECK-FIXES: {{^}}int A::out_of_line_const_to_static() {
95   return 0;
96 }
97 
98 struct KeepVirtual {
fKeepVirtual99   virtual int f() { return 0; }
hKeepVirtual100   virtual int h() const { return 0; }
101 };
102 
103 struct KeepVirtualDerived : public KeepVirtual {
fKeepVirtualDerived104   int f() { return 0; }
hKeepVirtualDerived105   int h() const override { return 0; }
106 };
107 
108 // Don't add 'static' to special member functions and operators.
109 struct KeepSpecial {
KeepSpecialKeepSpecial110   KeepSpecial() { int L = 0; }
~KeepSpecialKeepSpecial111   ~KeepSpecial() { int L = 0; }
operator +KeepSpecial112   int operator+() { return 0; }
operator intKeepSpecial113   operator int() { return 0; }
114 };
115 
KeepLambdas()116 void KeepLambdas() {
117   using FT = int (*)();
118   auto F = static_cast<FT>([]() { return 0; });
119   auto F2 = []() { return 0; };
120 }
121 
122 template <class Base>
123 struct KeepWithTemplateBase : public Base {
124   int i;
125   // We cannot make these methods static because they might need to override
126   // a function from Base.
static_fKeepWithTemplateBase127   int static_f() { return 0; }
128 };
129 
130 template <class T>
131 struct KeepTemplateClass {
132   int i;
133   // We cannot make these methods static because a specialization
134   // might use *this differently.
static_fKeepTemplateClass135   int static_f() { return 0; }
136 };
137 
138 struct KeepTemplateMethod {
139   int i;
140   // We cannot make these methods static because a specialization
141   // might use *this differently.
142   template <class T>
static_fKeepTemplateMethod143   static int static_f() { return 0; }
144 };
145 
instantiate()146 void instantiate() {
147   struct S {};
148   KeepWithTemplateBase<S> I1;
149   I1.static_f();
150 
151   KeepTemplateClass<int> I2;
152   I2.static_f();
153 
154   KeepTemplateMethod I3;
155   I3.static_f<int>();
156 }
157 
158 struct Trailing {
gTrailing159   auto g() const -> int {
160     // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'g' can be made static
161     // CHECK-FIXES: {{^}}  static auto g() -> int {
162     return 0;
163   }
164 
volTrailing165   void vol() volatile {
166     // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'vol' can be made static
167     return;
168   }
169 
refTrailing170   void ref() const & {
171     // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'ref' can be made static
172     return;
173   }
refrefTrailing174   void refref() const && {
175     // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'refref' can be made static
176     return;
177   }
178 
restrTrailing179   void restr() __restrict {
180     // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'restr' can be made static
181     return;
182   }
183 };
184 
185 struct UnevaluatedContext {
fUnevaluatedContext186   void f() { sizeof(this); }
187 
188   void noex() noexcept(noexcept(this));
189 };
190 
191 struct LambdaCapturesThis {
192   int Field;
193 
explicitCaptureLambdaCapturesThis194   int explicitCapture() {
195     return [this]() { return Field; }();
196   }
197 
implicitCaptureLambdaCapturesThis198   int implicitCapture() {
199     return [&]() { return Field; }();
200   }
201 };
202 
203 struct NoFixitInMacro {
204 #define CONST const
no_use_macro_constNoFixitInMacro205   int no_use_macro_const() CONST {
206     // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'no_use_macro_const' can be made static
207     return 0;
208   }
209 
210 #define ADD_CONST(F) F const
ADD_CONSTNoFixitInMacro211   int ADD_CONST(no_use_macro2()) {
212     return 0;
213   }
214 
215 #define FUN no_use_macro()
216   int i;
217   int FUN {
218     return i;
219   }
220 
221 #define T(FunctionName, Keyword) \
222   Keyword int FunctionName() { return 0; }
223 #define EMPTY
224   T(A, EMPTY)
225   T(B, static)
226 
227 #define T2(FunctionName) \
228   int FunctionName() { return 0; }
229   T2(A2)
230 
231 #define VOLATILE volatile
232   void volatileMacro() VOLATILE {
233     // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'volatileMacro' can be made static
234     return;
235   }
236 };
237