189a1d03eSRichard // RUN: %check_clang_tidy %s readability-convert-member-functions-to-static %t
289a1d03eSRichard 
389a1d03eSRichard class DoNotMakeEmptyStatic {
emptyMethod()489a1d03eSRichard   void emptyMethod() {}
589a1d03eSRichard   void empty_method_out_of_line();
689a1d03eSRichard };
789a1d03eSRichard 
empty_method_out_of_line()889a1d03eSRichard void DoNotMakeEmptyStatic::empty_method_out_of_line() {}
989a1d03eSRichard 
1089a1d03eSRichard class A {
1189a1d03eSRichard   int field;
1289a1d03eSRichard   const int const_field;
1389a1d03eSRichard   static int static_field;
1489a1d03eSRichard 
no_use()1589a1d03eSRichard   void no_use() {
1689a1d03eSRichard     // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'no_use' can be made static
1789a1d03eSRichard     // CHECK-FIXES: {{^}}  static void no_use() {
1889a1d03eSRichard     int i = 1;
1989a1d03eSRichard   }
2089a1d03eSRichard 
read_field()2189a1d03eSRichard   int read_field() {
2289a1d03eSRichard     return field;
2389a1d03eSRichard   }
2489a1d03eSRichard 
write_field()2589a1d03eSRichard   void write_field() {
2689a1d03eSRichard     field = 1;
2789a1d03eSRichard   }
2889a1d03eSRichard 
call_non_const_member()2989a1d03eSRichard   int call_non_const_member() { return read_field(); }
3089a1d03eSRichard 
call_static_member()3189a1d03eSRichard   int call_static_member() {
3289a1d03eSRichard     // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'call_static_member' can be made static
3389a1d03eSRichard     // CHECK-FIXES: {{^}}  static int call_static_member() {
3489a1d03eSRichard     already_static();
3589a1d03eSRichard   }
3689a1d03eSRichard 
read_static()3789a1d03eSRichard   int read_static() {
3889a1d03eSRichard     // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_static' can be made static
3989a1d03eSRichard     // CHECK-FIXES: {{^}}  static int read_static() {
4089a1d03eSRichard     return static_field;
4189a1d03eSRichard   }
write_static()4289a1d03eSRichard   void write_static() {
4389a1d03eSRichard     // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'write_static' can be made static
4489a1d03eSRichard     // CHECK-FIXES: {{^}}  static void write_static() {
4589a1d03eSRichard     static_field = 1;
4689a1d03eSRichard   }
4789a1d03eSRichard 
static_nested()48*67e05d38SNathan James   void static_nested() {
49*67e05d38SNathan James     // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'static_nested' can be made static
50*67e05d38SNathan James     // CHECK-FIXES: {{^}}  static void static_nested() {
51*67e05d38SNathan James     struct Nested {
52*67e05d38SNathan James       int Foo;
53*67e05d38SNathan James       int getFoo() { return Foo; }
54*67e05d38SNathan James     };
55*67e05d38SNathan James   }
56*67e05d38SNathan James 
write_nested()57*67e05d38SNathan James   void write_nested() {
58*67e05d38SNathan James     struct Nested {
59*67e05d38SNathan James       int Foo;
60*67e05d38SNathan James       int getFoo() { return Foo; }
61*67e05d38SNathan James     };
62*67e05d38SNathan James     // Ensure we still detect usages of `this` once we leave the nested class definition.
63*67e05d38SNathan James     field = 1;
64*67e05d38SNathan James   }
65*67e05d38SNathan James 
already_static()6689a1d03eSRichard   static int already_static() { return static_field; }
6789a1d03eSRichard 
already_const() const6889a1d03eSRichard   int already_const() const { return field; }
6989a1d03eSRichard 
already_const_convert_to_static() const7089a1d03eSRichard   int already_const_convert_to_static() const {
7189a1d03eSRichard     // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'already_const_convert_to_static' can be made static
7289a1d03eSRichard     // CHECK-FIXES: {{^}}  static int already_const_convert_to_static() {
7389a1d03eSRichard     return static_field;
7489a1d03eSRichard   }
7589a1d03eSRichard 
7689a1d03eSRichard   static int out_of_line_already_static();
7789a1d03eSRichard 
7889a1d03eSRichard   void out_of_line_call_static();
7989a1d03eSRichard   // CHECK-FIXES: {{^}}  static void out_of_line_call_static();
8089a1d03eSRichard   int out_of_line_const_to_static() const;
8189a1d03eSRichard   // CHECK-FIXES: {{^}}  static int out_of_line_const_to_static() ;
8289a1d03eSRichard };
8389a1d03eSRichard 
out_of_line_already_static()8489a1d03eSRichard int A::out_of_line_already_static() { return 0; }
8589a1d03eSRichard 
out_of_line_call_static()8689a1d03eSRichard void A::out_of_line_call_static() {
8789a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: method 'out_of_line_call_static' can be made static
8889a1d03eSRichard   // CHECK-FIXES: {{^}}void A::out_of_line_call_static() {
8989a1d03eSRichard   already_static();
9089a1d03eSRichard }
9189a1d03eSRichard 
out_of_line_const_to_static() const9289a1d03eSRichard int A::out_of_line_const_to_static() const {
9389a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'out_of_line_const_to_static' can be made static
9489a1d03eSRichard   // CHECK-FIXES: {{^}}int A::out_of_line_const_to_static() {
9589a1d03eSRichard   return 0;
9689a1d03eSRichard }
9789a1d03eSRichard 
9889a1d03eSRichard struct KeepVirtual {
fKeepVirtual9989a1d03eSRichard   virtual int f() { return 0; }
hKeepVirtual10089a1d03eSRichard   virtual int h() const { return 0; }
10189a1d03eSRichard };
10289a1d03eSRichard 
10389a1d03eSRichard struct KeepVirtualDerived : public KeepVirtual {
fKeepVirtualDerived10489a1d03eSRichard   int f() { return 0; }
hKeepVirtualDerived10589a1d03eSRichard   int h() const override { return 0; }
10689a1d03eSRichard };
10789a1d03eSRichard 
10889a1d03eSRichard // Don't add 'static' to special member functions and operators.
10989a1d03eSRichard struct KeepSpecial {
KeepSpecialKeepSpecial11089a1d03eSRichard   KeepSpecial() { int L = 0; }
~KeepSpecialKeepSpecial11189a1d03eSRichard   ~KeepSpecial() { int L = 0; }
operator +KeepSpecial11289a1d03eSRichard   int operator+() { return 0; }
operator intKeepSpecial11389a1d03eSRichard   operator int() { return 0; }
11489a1d03eSRichard };
11589a1d03eSRichard 
KeepLambdas()11689a1d03eSRichard void KeepLambdas() {
11789a1d03eSRichard   using FT = int (*)();
11889a1d03eSRichard   auto F = static_cast<FT>([]() { return 0; });
11989a1d03eSRichard   auto F2 = []() { return 0; };
12089a1d03eSRichard }
12189a1d03eSRichard 
12289a1d03eSRichard template <class Base>
12389a1d03eSRichard struct KeepWithTemplateBase : public Base {
12489a1d03eSRichard   int i;
12589a1d03eSRichard   // We cannot make these methods static because they might need to override
12689a1d03eSRichard   // a function from Base.
static_fKeepWithTemplateBase12789a1d03eSRichard   int static_f() { return 0; }
12889a1d03eSRichard };
12989a1d03eSRichard 
13089a1d03eSRichard template <class T>
13189a1d03eSRichard struct KeepTemplateClass {
13289a1d03eSRichard   int i;
13389a1d03eSRichard   // We cannot make these methods static because a specialization
13489a1d03eSRichard   // might use *this differently.
static_fKeepTemplateClass13589a1d03eSRichard   int static_f() { return 0; }
13689a1d03eSRichard };
13789a1d03eSRichard 
13889a1d03eSRichard struct KeepTemplateMethod {
13989a1d03eSRichard   int i;
14089a1d03eSRichard   // We cannot make these methods static because a specialization
14189a1d03eSRichard   // might use *this differently.
14289a1d03eSRichard   template <class T>
static_fKeepTemplateMethod14389a1d03eSRichard   static int static_f() { return 0; }
14489a1d03eSRichard };
14589a1d03eSRichard 
instantiate()14689a1d03eSRichard void instantiate() {
14789a1d03eSRichard   struct S {};
14889a1d03eSRichard   KeepWithTemplateBase<S> I1;
14989a1d03eSRichard   I1.static_f();
15089a1d03eSRichard 
15189a1d03eSRichard   KeepTemplateClass<int> I2;
15289a1d03eSRichard   I2.static_f();
15389a1d03eSRichard 
15489a1d03eSRichard   KeepTemplateMethod I3;
15589a1d03eSRichard   I3.static_f<int>();
15689a1d03eSRichard }
15789a1d03eSRichard 
15889a1d03eSRichard struct Trailing {
gTrailing15989a1d03eSRichard   auto g() const -> int {
16089a1d03eSRichard     // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'g' can be made static
16189a1d03eSRichard     // CHECK-FIXES: {{^}}  static auto g() -> int {
16289a1d03eSRichard     return 0;
16389a1d03eSRichard   }
16489a1d03eSRichard 
volTrailing16589a1d03eSRichard   void vol() volatile {
16689a1d03eSRichard     // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'vol' can be made static
16789a1d03eSRichard     return;
16889a1d03eSRichard   }
16989a1d03eSRichard 
refTrailing17089a1d03eSRichard   void ref() const & {
17189a1d03eSRichard     // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'ref' can be made static
17289a1d03eSRichard     return;
17389a1d03eSRichard   }
refrefTrailing17489a1d03eSRichard   void refref() const && {
17589a1d03eSRichard     // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'refref' can be made static
17689a1d03eSRichard     return;
17789a1d03eSRichard   }
17889a1d03eSRichard 
restrTrailing17989a1d03eSRichard   void restr() __restrict {
18089a1d03eSRichard     // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'restr' can be made static
18189a1d03eSRichard     return;
18289a1d03eSRichard   }
18389a1d03eSRichard };
18489a1d03eSRichard 
18589a1d03eSRichard struct UnevaluatedContext {
fUnevaluatedContext18689a1d03eSRichard   void f() { sizeof(this); }
18789a1d03eSRichard 
18889a1d03eSRichard   void noex() noexcept(noexcept(this));
18989a1d03eSRichard };
19089a1d03eSRichard 
19189a1d03eSRichard struct LambdaCapturesThis {
19289a1d03eSRichard   int Field;
19389a1d03eSRichard 
explicitCaptureLambdaCapturesThis19489a1d03eSRichard   int explicitCapture() {
19589a1d03eSRichard     return [this]() { return Field; }();
19689a1d03eSRichard   }
19789a1d03eSRichard 
implicitCaptureLambdaCapturesThis19889a1d03eSRichard   int implicitCapture() {
19989a1d03eSRichard     return [&]() { return Field; }();
20089a1d03eSRichard   }
20189a1d03eSRichard };
20289a1d03eSRichard 
20389a1d03eSRichard struct NoFixitInMacro {
20489a1d03eSRichard #define CONST const
no_use_macro_constNoFixitInMacro20589a1d03eSRichard   int no_use_macro_const() CONST {
20689a1d03eSRichard     // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'no_use_macro_const' can be made static
20789a1d03eSRichard     return 0;
20889a1d03eSRichard   }
20989a1d03eSRichard 
21089a1d03eSRichard #define ADD_CONST(F) F const
ADD_CONSTNoFixitInMacro21189a1d03eSRichard   int ADD_CONST(no_use_macro2()) {
21289a1d03eSRichard     return 0;
21389a1d03eSRichard   }
21489a1d03eSRichard 
21589a1d03eSRichard #define FUN no_use_macro()
21689a1d03eSRichard   int i;
21789a1d03eSRichard   int FUN {
21889a1d03eSRichard     return i;
21989a1d03eSRichard   }
22089a1d03eSRichard 
22189a1d03eSRichard #define T(FunctionName, Keyword) \
22289a1d03eSRichard   Keyword int FunctionName() { return 0; }
22389a1d03eSRichard #define EMPTY
22489a1d03eSRichard   T(A, EMPTY)
22589a1d03eSRichard   T(B, static)
22689a1d03eSRichard 
22789a1d03eSRichard #define T2(FunctionName) \
22889a1d03eSRichard   int FunctionName() { return 0; }
22989a1d03eSRichard   T2(A2)
23089a1d03eSRichard 
23189a1d03eSRichard #define VOLATILE volatile
23289a1d03eSRichard   void volatileMacro() VOLATILE {
23389a1d03eSRichard     // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'volatileMacro' can be made static
23489a1d03eSRichard     return;
23589a1d03eSRichard   }
23689a1d03eSRichard };
237