// RUN: %check_clang_tidy %s modernize-use-equals-default %t -- -- -fno-delayed-template-parsing -fexceptions

// Out of line definition.
class OL {
public:
  OL();
  ~OL();
};

OL::OL() {}
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use '= default' to define a trivial default constructor [modernize-use-equals-default]
// CHECK-FIXES: OL::OL() = default;
OL::~OL() {}
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use '= default' to define a trivial destructor [modernize-use-equals-default]
// CHECK-FIXES: OL::~OL() = default;

// Inline definitions.
class IL {
public:
  IL() {}
  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
  // CHECK-FIXES: IL() = default;
  ~IL() {}
  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
  // CHECK-FIXES: ~IL() = default;
};

// Non-empty body.
void f();
class NE {
public:
  NE() { f(); }
  ~NE() { f(); }
};

// Initializer or arguments.
class IA {
public:
  // Constructor with initializer.
  IA() : Field(5) {}
  // Constructor with arguments.
  IA(int Arg1, int Arg2) {}
  int Field;
};

// Default member initializer
class DMI {
public:
  DMI() {}
  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
  // CHECK-FIXES: DMI() = default;
  int Field = 5;
};

// Class member
class CM {
public:
  CM() {}
  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
  // CHECK-FIXES: CM() = default;
  OL o;
};

// Private constructor/destructor.
class Priv {
  Priv() {}
  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
  // CHECK-FIXES: Priv() = default;
  ~Priv() {}
  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
  // CHECK-FIXES: ~Priv() = default;
};

// struct.
struct ST {
  ST() {}
  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
  // CHECK-FIXES: ST() = default;
  ~ST() {}
  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
  // CHECK-FIXES: ST() = default;
};

// Deleted constructor/destructor.
class Del {
public:
  Del() = delete;
  ~Del() = delete;
};

// Do not remove other keywords.
class KW {
public:
  explicit KW() {}
  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use '= default'
  // CHECK-FIXES: explicit KW() = default;
  virtual ~KW() {}
  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use '= default'
  // CHECK-FIXES: virtual ~KW() = default;
};

// Nested class.
struct N {
  struct NN {
    NN() {}
    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use '= default'
    // CHECK-FIXES: NN() = default;
    ~NN() {}
    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use '= default'
    // CHECK-FIXES: ~NN() = default;
  };
  int Int;
};

// Class template.
template <class T>
class Temp {
public:
  Temp() {}
  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
  // CHECK-FIXES: Temp() = default;
  ~Temp() {}
  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
  // CHECK-FIXES: ~Temp() = default;
};

// Class template out of line with explicit instantiation.
template <class T>
class TempODef {
public:
  TempODef();
  ~TempODef();
};

template <class T>
TempODef<T>::TempODef() {}
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use '= default'
// CHECK-FIXES: TempODef<T>::TempODef() = default;
template <class T>
TempODef<T>::~TempODef() {}
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use '= default'
// CHECK-FIXES: TempODef<T>::~TempODef() = default;

template class TempODef<int>;
template class TempODef<double>;

// Non user-provided constructor/destructor.
struct Imp {
  int Int;
};
void g() {
  Imp *PtrImp = new Imp();
  PtrImp->~Imp();
  delete PtrImp;
}

// Already using default.
struct IDef {
  IDef() = default;
  ~IDef() = default;
};
struct ODef {
  ODef();
  ~ODef();
};
ODef::ODef() = default;
ODef::~ODef() = default;

// Delegating constructor and overriden destructor.
struct DC : KW {
  DC() : KW() {}
  ~DC() override {}
  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
  // CHECK-FIXES: ~DC() override = default;
};

struct Comments {
  Comments() {
    // Don't erase comments inside the body.
  }
  // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use '= default'
  ~Comments() {
    // Don't erase comments inside the body.
  }
  // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use '= default'
};

// Try-catch.
struct ITC {
  ITC() try {} catch(...) {}
  ~ITC() try {} catch(...) {}
};

struct OTC {
  OTC();
  ~OTC();
};
OTC::OTC() try {} catch(...) {}
OTC::~OTC() try {} catch(...) {}

#define STRUCT_WITH_DEFAULT(_base, _type) \
  struct _type {                          \
    _type() {}                            \
    _base value;                          \
  };

STRUCT_WITH_DEFAULT(unsigned char, InMacro)
