text: // 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;
    }
  
    int read_fields_in_parentheses() {
      // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_fields_in_parentheses' can be made const
      // CHECK-FIXES: {{^}}  int read_fields_in_parentheses() const {
      return (this)->M + (((((Struct.M))))) + ((this->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<int *>(static_cast<const Keep *>(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 <class Base>
  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 <class T>
  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 <class T>
    int const_f() { return M; }
  };
  
  void instantiate() {
    struct S {};
    KeepWithDependentBase<S> I1;
    I1.const_f();
  
    KeepClassTemplate<int> I2;
    I2.const_f();
  
    KeepMemberFunctionTemplate I3;
    I3.const_f<int>();
  }
  
  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<DataPattern *>(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
  