// RUN: %check_clang_tidy %s readability-make-member-function-const %t struct Str { void const_method() const; void non_const_method(); }; namespace Diagnose { struct A; void free_const_use(const A *); void free_const_use(const A &); struct A { int M; const int ConstM; struct { int M; } Struct; Str S; Str &Sref; void already_const() const; int read_field() { // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_field' can be made const // CHECK-FIXES: {{^}} int read_field() const { return M; } int read_struct_field() { // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_struct_field' can be made const // CHECK-FIXES: {{^}} int read_struct_field() const { return Struct.M; } int read_const_field() { // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_const_field' can be made const // CHECK-FIXES: {{^}} int read_const_field() const { return ConstM; } void call_const_member() { // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member' can be made const // CHECK-FIXES: {{^}} void call_const_member() const { already_const(); } void call_const_member_on_public_field() { // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member_on_public_field' can be made const // CHECK-FIXES: {{^}} void call_const_member_on_public_field() const { S.const_method(); } void call_const_member_on_public_field_ref() { // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member_on_public_field_ref' can be made const // CHECK-FIXES: {{^}} void call_const_member_on_public_field_ref() const { Sref.const_method(); } const Str &return_public_field_ref() { // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: method 'return_public_field_ref' can be made const // CHECK-FIXES: {{^}} const Str &return_public_field_ref() const { return S; } const A *return_this_const() { // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: method 'return_this_const' can be made const // CHECK-FIXES: {{^}} const A *return_this_const() const { return this; } const A &return_this_const_ref() { // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: method 'return_this_const_ref' can be made const // CHECK-FIXES: {{^}} const A &return_this_const_ref() const { return *this; } void const_use() { // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'const_use' can be made const // CHECK-FIXES: {{^}} void const_use() const { free_const_use(this); } void const_use_ref() { // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'const_use_ref' can be made const // CHECK-FIXES: {{^}} void const_use_ref() const { free_const_use(*this); } auto trailingReturn() -> int { // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'trailingReturn' can be made const // CHECK-FIXES: {{^}} auto trailingReturn() const -> int { return M; } int volatileFunction() volatile { // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'volatileFunction' can be made const // CHECK-FIXES: {{^}} int volatileFunction() const volatile { return M; } int restrictFunction() __restrict { // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'restrictFunction' can be made const // CHECK-FIXES: {{^}} int restrictFunction() const __restrict { return M; } int refFunction() & { // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'refFunction' can be made const // CHECK-FIXES: {{^}} int refFunction() const & { return M; } void out_of_line_call_const(); // CHECK-FIXES: {{^}} void out_of_line_call_const() const; }; void A::out_of_line_call_const() { // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: method 'out_of_line_call_const' can be made const // CHECK-FIXES: {{^}}void A::out_of_line_call_const() const { already_const(); } } // namespace Diagnose namespace Keep { struct Keep; void free_non_const_use(Keep *); void free_non_const_use(Keep &); struct Keep { private: void private_const_method() const; Str PrivateS; Str *Sptr; Str &Sref; public: int M; Str S; void keepTrivial() {} // See readability-convert-member-functions-to-static instead. void keepStatic() { int I = 0; } const int *keepConstCast() const; int *keepConstCast() { // Needs to stay non-const. return const_cast(static_cast(this)->keepConstCast()); } void non_const_use() { free_non_const_use(this); } void non_const_use_ref() { free_non_const_use(*this); } Keep *return_this() { return this; } Keep &return_this_ref() { return *this; } void escape_this() { Keep *Escaped = this; } void call_private_const_method() { private_const_method(); } int keepConst() const { return M; } virtual int keepVirtual() { return M; } void writeField() { M = 1; } void callNonConstMember() { writeField(); } void call_non_const_member_on_field() { S.non_const_method(); } void call_const_member_on_private_field() { // Technically, this method could be const-qualified, // but it might not be logically const. PrivateS.const_method(); } const Str &return_private_field_ref() { // Technically, this method could be const-qualified, // but it might not be logically const. return PrivateS; } void call_non_const_member_on_pointee() { Sptr->non_const_method(); } void call_const_member_on_pointee() { // Technically, this method could be const-qualified, // but it might not be logically const. Sptr->const_method(); } Str *return_pointer() { // Technically, this method could be const-qualified, // but it might not be logically const. return Sptr; } const Str *return_const_pointer() { // Technically, this method could be const-qualified, // but it might not be logically const. return Sptr; } void call_non_const_member_on_ref() { Sref.non_const_method(); } void escaped_private_field() { const auto &Escaped = Sref; } Str &return_field_ref() { // Technically, this method could be const-qualified, // but it might not be logically const. return Sref; } const Str &return_field_const_ref() { // Technically, this method could be const-qualified, // but it might not be logically const. return Sref; } }; struct KeepVirtualDerived : public Keep { int keepVirtual() { return M; } }; void KeepLambdas() { auto F = +[]() { return 0; }; auto F2 = []() { return 0; }; } template struct KeepWithDependentBase : public Base { int M; // We cannot make this method const because it might need to override // a function from Base. int const_f() { return M; } }; template struct KeepClassTemplate { int M; // We cannot make this method const because a specialization // might use *this differently. int const_f() { return M; } }; struct KeepMemberFunctionTemplate { int M; // We cannot make this method const because a specialization // might use *this differently. template int const_f() { return M; } }; void instantiate() { struct S {}; KeepWithDependentBase I1; I1.const_f(); KeepClassTemplate I2; I2.const_f(); KeepMemberFunctionTemplate I3; I3.const_f(); } struct NoFixitInMacro { int M; #define FUN const_use_macro() int FUN { return M; } #define T(FunctionName, Keyword) \ int FunctionName() Keyword { return M; } #define EMPTY T(A, EMPTY) T(B, const) #define T2(FunctionName) \ int FunctionName() { return M; } T2(A2) }; // Real-world code, see clang::ObjCInterfaceDecl. class DataPattern { int &data() const; public: const int &get() const { return const_cast(this)->get(); } // This member function must stay non-const, even though // it only calls other private const member functions. int &get() { return data(); } void set() { data() = 42; } }; struct MemberFunctionPointer { void call_non_const(void (MemberFunctionPointer::*FP)()) { (this->*FP)(); } void call_const(void (MemberFunctionPointer::*FP)() const) { (this->*FP)(); } }; } // namespace Keep