339 lines · cpp
1// RUN: %check_clang_tidy %s readability-make-member-function-const %t2 3struct Str {4 void const_method() const;5 void non_const_method();6};7 8namespace Diagnose {9struct A;10 11void free_const_use(const A *);12void free_const_use(const A &);13 14struct A {15 int M;16 const int ConstM;17 struct {18 int M;19 } Struct;20 Str S;21 Str &Sref;22 23 void already_const() const;24 25 int read_field() {26 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_field' can be made const27 // CHECK-FIXES: int read_field() const {28 return M;29 }30 31 int read_struct_field() {32 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_struct_field' can be made const33 // CHECK-FIXES: int read_struct_field() const {34 return Struct.M;35 }36 37 int read_const_field() {38 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_const_field' can be made const39 // CHECK-FIXES: int read_const_field() const {40 return ConstM;41 }42 43 int read_fields_in_parentheses() {44 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_fields_in_parentheses' can be made const45 // CHECK-FIXES: int read_fields_in_parentheses() const {46 return (this)->M + (((((Struct.M))))) + ((this->ConstM));47 }48 49 void call_const_member() {50 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member' can be made const51 // CHECK-FIXES: void call_const_member() const {52 already_const();53 }54 55 void call_const_member_on_public_field() {56 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member_on_public_field' can be made const57 // CHECK-FIXES: void call_const_member_on_public_field() const {58 S.const_method();59 }60 61 void call_const_member_on_public_field_ref() {62 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member_on_public_field_ref' can be made const63 // CHECK-FIXES: void call_const_member_on_public_field_ref() const {64 Sref.const_method();65 }66 67 const Str &return_public_field_ref() {68 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: method 'return_public_field_ref' can be made const69 // CHECK-FIXES: const Str &return_public_field_ref() const {70 return S;71 }72 73 const A *return_this_const() {74 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: method 'return_this_const' can be made const75 // CHECK-FIXES: const A *return_this_const() const {76 return this;77 }78 79 const A &return_this_const_ref() {80 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: method 'return_this_const_ref' can be made const81 // CHECK-FIXES: const A &return_this_const_ref() const {82 return *this;83 }84 85 void const_use() {86 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'const_use' can be made const87 // CHECK-FIXES: void const_use() const {88 free_const_use(this);89 }90 91 void const_use_ref() {92 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'const_use_ref' can be made const93 // CHECK-FIXES: void const_use_ref() const {94 free_const_use(*this);95 }96 97 auto trailingReturn() -> int {98 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'trailingReturn' can be made const99 // CHECK-FIXES: auto trailingReturn() const -> int {100 return M;101 }102 103 int volatileFunction() volatile {104 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'volatileFunction' can be made const105 // CHECK-FIXES: int volatileFunction() const volatile {106 return M;107 }108 109 int restrictFunction() __restrict {110 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'restrictFunction' can be made const111 // CHECK-FIXES: int restrictFunction() const __restrict {112 return M;113 }114 115 int refFunction() & {116 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'refFunction' can be made const117 // CHECK-FIXES: int refFunction() const & {118 return M;119 }120 121 void out_of_line_call_const();122 // CHECK-FIXES: void out_of_line_call_const() const;123};124 125void A::out_of_line_call_const() {126 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: method 'out_of_line_call_const' can be made const127 // CHECK-FIXES: void A::out_of_line_call_const() const {128 already_const();129}130} // namespace Diagnose131 132namespace Keep {133struct Keep;134void free_non_const_use(Keep *);135void free_non_const_use(Keep &);136 137struct Keep {138private:139 void private_const_method() const;140 Str PrivateS;141 Str *Sptr;142 Str &Sref;143 144public:145 int M;146 Str S;147 148 void keepTrivial() {}149 150 // See readability-convert-member-functions-to-static instead.151 void keepStatic() { int I = 0; }152 153 const int *keepConstCast() const;154 int *keepConstCast() { // Needs to stay non-const.155 return const_cast<int *>(static_cast<const Keep *>(this)->keepConstCast());156 }157 158 void non_const_use() { free_non_const_use(this); }159 void non_const_use_ref() { free_non_const_use(*this); }160 161 Keep *return_this() {162 return this;163 }164 165 Keep &return_this_ref() {166 return *this;167 }168 169 void escape_this() {170 Keep *Escaped = this;171 }172 173 void call_private_const_method() {174 private_const_method();175 }176 177 int keepConst() const { return M; }178 179 virtual int keepVirtual() { return M; }180 181 void writeField() {182 M = 1;183 }184 185 void callNonConstMember() { writeField(); }186 187 void call_non_const_member_on_field() { S.non_const_method(); }188 189 void call_const_member_on_private_field() {190 // Technically, this method could be const-qualified,191 // but it might not be logically const.192 PrivateS.const_method();193 }194 195 const Str &return_private_field_ref() {196 // Technically, this method could be const-qualified,197 // but it might not be logically const.198 return PrivateS;199 }200 201 void call_non_const_member_on_pointee() {202 Sptr->non_const_method();203 }204 205 void call_const_member_on_pointee() {206 // Technically, this method could be const-qualified,207 // but it might not be logically const.208 Sptr->const_method();209 }210 211 Str *return_pointer() {212 // Technically, this method could be const-qualified,213 // but it might not be logically const.214 return Sptr;215 }216 217 const Str *return_const_pointer() {218 // Technically, this method could be const-qualified,219 // but it might not be logically const.220 return Sptr;221 }222 223 void call_non_const_member_on_ref() {224 Sref.non_const_method();225 }226 227 void escaped_private_field() {228 const auto &Escaped = Sref;229 }230 231 Str &return_field_ref() {232 // Technically, this method could be const-qualified,233 // but it might not be logically const.234 return Sref;235 }236 237 const Str &return_field_const_ref() {238 // Technically, this method could be const-qualified,239 // but it might not be logically const.240 return Sref;241 }242};243 244struct KeepVirtualDerived : public Keep {245 int keepVirtual() { return M; }246};247 248void KeepLambdas() {249 auto F = +[]() { return 0; };250 auto F2 = []() { return 0; };251}252 253template <class Base>254struct KeepWithDependentBase : public Base {255 int M;256 // We cannot make this method const because it might need to override257 // a function from Base.258 int const_f() { return M; }259};260 261template <class T>262struct KeepClassTemplate {263 int M;264 // We cannot make this method const because a specialization265 // might use *this differently.266 int const_f() { return M; }267};268 269struct KeepMemberFunctionTemplate {270 int M;271 // We cannot make this method const because a specialization272 // might use *this differently.273 template <class T>274 int const_f() { return M; }275};276 277void instantiate() {278 struct S {};279 KeepWithDependentBase<S> I1;280 I1.const_f();281 282 KeepClassTemplate<int> I2;283 I2.const_f();284 285 KeepMemberFunctionTemplate I3;286 I3.const_f<int>();287}288 289struct NoFixitInMacro {290 int M;291 292#define FUN const_use_macro()293 int FUN {294 return M;295 }296 297#define T(FunctionName, Keyword) \298 int FunctionName() Keyword { return M; }299#define EMPTY300 T(A, EMPTY)301 T(B, const)302 303#define T2(FunctionName) \304 int FunctionName() { return M; }305 T2(A2)306};307 308// Real-world code, see clang::ObjCInterfaceDecl.309class DataPattern {310 int &data() const;311 312public:313 const int &get() const {314 return const_cast<DataPattern *>(this)->get();315 }316 317 // This member function must stay non-const, even though318 // it only calls other private const member functions.319 int &get() {320 return data();321 }322 323 void set() {324 data() = 42;325 }326};327 328struct MemberFunctionPointer {329 void call_non_const(void (MemberFunctionPointer::*FP)()) {330 (this->*FP)();331 }332 333 void call_const(void (MemberFunctionPointer::*FP)() const) {334 (this->*FP)();335 }336};337 338} // namespace Keep339