// RUN: %check_clang_tidy %s misc-unused-using-decls %t -- -- -fno-delayed-template-parsing -isystem %S/Inputs/


// ----- Definitions -----
template <typename T> class vector {};
namespace n {
class A;
class B;
class C;
class D;
class D { public: static int i; };
template <typename T> class E {};
template <typename T> class F {};
class G { public: static void func() {} };
class H { public: static int i; };
class I {
 public:
  static int ii;
};
template <typename T> class J {};
class G;
class H;

template <typename T> class K {};
template <template <typename> class S>
class L {};

template <typename T> class M {};
class N {};

template <int T> class P {};
const int Constant = 0;

class Base {
 public:
  void f();
};

D UsedInstance;
D UnusedInstance;

int UsedFunc() { return 1; }
int UnusedFunc() { return 1; }
template <typename T> int UsedTemplateFunc() { return 1; }
template <typename T> int UnusedTemplateFunc() { return 1; }
template <typename T> int UsedInTemplateFunc() { return 1; }
void OverloadFunc(int);
void OverloadFunc(double);
int FuncUsedByUsingDeclInMacro() { return 1; }

class ostream {
public:
  ostream &operator<<(ostream &(*PF)(ostream &));
};
extern ostream cout;
ostream &endl(ostream &os);

enum Color1 { Green };

enum Color2 { Red };

enum Color3 { Yellow };

enum Color4 { Blue };

}  // namespace n

#include "unused-using-decls.h"
namespace ns {
template <typename T>
class AA {
  T t;
};
template <typename T>
T ff() { T t; return t; }
} // namespace ns

// ----- Using declarations -----
// eol-comments aren't removed (yet)
using n::A; // A
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'A' is unused
// CHECK-FIXES: {{^}}// A
using n::B;
using n::C;
using n::D;
using n::E; // E
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'E' is unused
// CHECK-FIXES: {{^}}// E
using n::F;
using n::G;
using n::H;
using n::I;
int I::ii = 1;
class Derived : public n::Base {
 public:
  using Base::f;
};
using n::UsedInstance;
using n::UsedFunc;
using n::UsedTemplateFunc;
using n::UnusedInstance; // UnusedInstance
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'UnusedInstance' is unused
// CHECK-FIXES: {{^}}// UnusedInstance
using n::UnusedFunc; // UnusedFunc
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'UnusedFunc' is unused
// CHECK-FIXES: {{^}}// UnusedFunc
using n::cout;
using n::endl;

using n::UsedInTemplateFunc;
using n::J;
template <typename T> void Callee() {
  J<T> j;
  UsedInTemplateFunc<T>();
}

using n::OverloadFunc; // OverloadFunc
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'OverloadFunc' is unused
// CHECK-FIXES: {{^}}// OverloadFunc

#define DEFINE_INT(name)        \
  namespace INT {               \
  static const int _##name = 1; \
  }                             \
  using INT::_##name
DEFINE_INT(test);
#undef DEFIND_INT

#define USING_FUNC \
  using n::FuncUsedByUsingDeclInMacro;
USING_FUNC
#undef USING_FUNC

namespace N1 {
// n::G is used in namespace N2.
// Currently, the check doesn't support multiple scopes. All the relevant
// using-decls will be marked as used once we see an usage even the usage is in
// other scope.
using n::G;
}

namespace N2 {
using n::G;
void f(G g);
}

void IgnoreFunctionScope() {
// Using-decls defined in function scope will be ignored.
using n::H;
}

using n::Color1;
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'Color1' is unused
using n::Green;
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'Green' is unused
using n::Color2;
using n::Color3;
using n::Blue;

using ns::AA;
using ns::ff;

using n::K;

using n::N;

// FIXME: Currently non-type template arguments are not supported.
using n::Constant;
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'Constant' is unused

// ----- Usages -----
void f(B b);
void g() {
  vector<C> data;
  D::i = 1;
  F<int> f;
  void (*func)() = &G::func;
  int *i = &H::i;
  UsedInstance.i;
  UsedFunc();
  UsedTemplateFunc<int>();
  cout << endl;
  Color2 color2;
  int t1 = Color3::Yellow;
  int t2 = Blue;

  MyClass a;
  int t3 = 0;
  a.func1<AA>(&t3);
  a.func2<int, ff>(t3);

  n::L<K> l;
}

template<class T>
void h(n::M<T>* t) {}
// n::N is used the explicit template instantiation.
template void h(n::M<N>* t);

// Test on Non-type template arguments.
template <int T>
void i(n::P<T>* t) {}
template void i(n::P<Constant>* t);
