// RUN: mkdir -p %t.dir
// RUN: echo "static void staticFunctionHeader(int i) {;}" > %t.dir/header.h
// RUN: echo "static void staticFunctionHeader(int  /*i*/) {;}" > %t.dir/header-fixed.h
// RUN: %check_clang_tidy -std=c++11 %s misc-unused-parameters %t.dir/code -- -header-filter='.*' -- -fno-delayed-template-parsing
// RUN: diff %t.dir/header.h %t.dir/header-fixed.h
// FIXME: Make the test work in all language modes.

#include "header.h"

// Basic removal
// =============
void a(int i) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused [misc-unused-parameters]
// CHECK-FIXES: void a(int  /*i*/) {;}

void b(int i = 1) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused [misc-unused-parameters]
// CHECK-FIXES: void b(int  /*i*/ = 1) {;}

void c(int *i) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: parameter 'i' is unused [misc-unused-parameters]
// CHECK-FIXES: void c(int * /*i*/) {;}

void d(int i[]) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused [misc-unused-parameters]
// CHECK-FIXES: void d(int  /*i*/[]) {;}

void e(int i[1]) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused [misc-unused-parameters]
// CHECK-FIXES: void e(int  /*i*/[1]) {;}

void f(void (*fn)()) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: parameter 'fn' is unused [misc-unused-parameters]
// CHECK-FIXES: void f(void (* /*fn*/)()) {;}

int *k([[clang::lifetimebound]] int *i) { return nullptr; }
// CHECK-MESSAGES: :[[@LINE-1]]:38: warning: parameter 'i' is unused [misc-unused-parameters]
// CHECK-FIXES: int *k({{\[\[clang::lifetimebound\]\]}} int * /*i*/) { return nullptr; }

#define ATTR_BEFORE(x) [[clang::lifetimebound]] x
int* m(ATTR_BEFORE(const int *i)) { return nullptr; }
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: parameter 'i' is unused [misc-unused-parameters]
// CHECK-FIXES: int* m(ATTR_BEFORE(const int * /*i*/)) { return nullptr; }
#undef ATTR_BEFORE

// Unchanged cases
// ===============
void f(int i); // Don't remove stuff in declarations
void g(int i = 1);
void h(int i[]);
void s(int i[1]);
void u(void (*fn)());
void w(int i) { (void)i; } // Don't remove used parameters

// Don't reanchor the attribute to the type:
int *x(int *i [[clang::lifetimebound]]) { return nullptr; }
#define ATTR_AFTER(x) x [[clang::lifetimebound]]
int* y(ATTR_AFTER(const int *i)) { return nullptr; }
#undef ATTR_AFTER

bool useLambda(int (*fn)(int));
static bool static_var = useLambda([] (int a) { return a; });

// Remove parameters of local functions
// ====================================
static void staticFunctionA(int i);
// CHECK-FIXES: static void staticFunctionA();
static void staticFunctionA(int i) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning
// CHECK-FIXES: static void staticFunctionA() {;}

static void staticFunctionB(int i, int j) { (void)i; }
// CHECK-MESSAGES: :[[@LINE-1]]:40: warning
// CHECK-FIXES: static void staticFunctionB(int i) { (void)i; }

static void staticFunctionC(int i, int j) { (void)j; }
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning
// CHECK-FIXES: static void staticFunctionC(int j) { (void)j; }

static void staticFunctionD(int i, int j, int k) { (void)i; (void)k; }
// CHECK-MESSAGES: :[[@LINE-1]]:40: warning
// CHECK-FIXES: static void staticFunctionD(int i, int k) { (void)i; (void)k; }

static void staticFunctionE(int i = 4) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning
// CHECK-FIXES: static void staticFunctionE() {;}

static void staticFunctionF(int i = 4);
// CHECK-FIXES: static void staticFunctionF();
static void staticFunctionF(int i) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning
// CHECK-FIXES: static void staticFunctionF() {;}

static void staticFunctionG(int i[]);
// CHECK-FIXES: static void staticFunctionG();
static void staticFunctionG(int i[]) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning
// CHECK-FIXES: static void staticFunctionG() {;}

static void staticFunctionH(void (*fn)());
// CHECK-FIXES: static void staticFunctionH();
static void staticFunctionH(void (*fn)()) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:36: warning
// CHECK-FIXES: static void staticFunctionH() {;}

static void someCallSites() {
  staticFunctionA(1);
// CHECK-FIXES: staticFunctionA();
  staticFunctionB(1, 2);
// CHECK-FIXES: staticFunctionB(1);
  staticFunctionC(1, 2);
// CHECK-FIXES: staticFunctionC(2);
  staticFunctionD(1, 2, 3);
// CHECK-FIXES: staticFunctionD(1, 3);
  staticFunctionE(1);
// CHECK-FIXES: staticFunctionE();
  staticFunctionF(1);
// CHECK-FIXES: staticFunctionF();
  staticFunctionF();
// CHECK-FIXES: staticFunctionF();
  int t[] = {1};
  staticFunctionG(t);
// CHECK-FIXES: staticFunctionG();
  void func();
  staticFunctionH(&func);
// CHECK-FIXES: staticFunctionH();
}

/*
 * FIXME: This fails because the removals overlap and ClangTidy doesn't apply
 *        them.
 * static void bothVarsUnused(int a, int b) {;}
 */

// Regression test for long variable names and expressions
// =======================================================
static int variableWithLongName1(int LongName1, int LongName2) {
// CHECK-MESSAGES: :[[@LINE-1]]:53: warning: parameter 'LongName2' is unused
// CHECK-FIXES: static int variableWithLongName1(int LongName1) {
  return LongName1;
}
static int variableWithLongName2(int LongName1, int LongName2) {
// CHECK-MESSAGES: :[[@LINE-1]]:38: warning: parameter 'LongName1' is unused
// CHECK-FIXES: static int variableWithLongName2(int LongName2) {
  return LongName2;
}
static void someLongNameCallSites() {
  int LongName1 = 7, LongName2 = 17;
  variableWithLongName1(LongName1, LongName2);
// CHECK-FIXES: variableWithLongName1(LongName1);
  variableWithLongName2(LongName1, LongName2);
// CHECK-FIXES: variableWithLongName2(LongName2);
}

class SomeClass {
  static void f(int i) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning
// CHECK-FIXES: static void f(int  /*i*/) {;}
  static void g(int i = 1) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning
// CHECK-FIXES: static void g(int  /*i*/ = 1) {;}
  static void h(int i[]) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning
// CHECK-FIXES: static void h(int  /*i*/[]) {;}
  static void s(void (*fn)()) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning
// CHECK-FIXES: static void s(void (* /*fn*/)()) {;}
};

namespace {
class C {
public:
  void f(int i);
// CHECK-FIXES: void f();
  void g(int i) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning
// CHECK-FIXES: void g() {;}
  void h(int i) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning
// CHECK-FIXES: void h(int  /*i*/) {;}
  void s(int i = 1) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning
// CHECK-FIXES: void s(int  /*i*/ = 1) {;}
  void u(int i[]) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning
// CHECK-FIXES: void u(int  /*i*/[]) {;}
  void w(void (*fn)()) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning
// CHECK-FIXES: void w(void (* /*fn*/)()) {;}
};

void C::f(int i) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning
// CHECK-FIXES: void C::f() {;}

template <typename T>
void useFunction(T t);

void someMoreCallSites() {
  C c;
  c.f(1);
// CHECK-FIXES: c.f();
  c.g(1);
// CHECK-FIXES: c.g();

  useFunction(&C::h);
  useFunction(&C::s);
  useFunction(&C::u);
  useFunction(&C::w);
}

class Base {
  virtual void f(int i);
};

class Derived : public Base {
  void f(int i) override {;}
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning
// CHECK-FIXES: void f(int  /*i*/) override {;}
};

} // end namespace

template <typename T> void someFunctionTemplate(T b, T e) { (void)b; (void)e; }

template <typename T> void someFunctionTemplateOneUnusedParam(T b, T e) { (void)e; }
// CHECK-MESSAGES: :[[@LINE-1]]:65: warning
// CHECK-FIXES: template <typename T> void someFunctionTemplateOneUnusedParam(T  /*b*/, T e) { (void)e; }

template <typename T> void someFunctionTemplateAllUnusedParams(T b, T e) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:66: warning
// CHECK-MESSAGES: :[[@LINE-2]]:71: warning
// CHECK-FIXES: template <typename T> void someFunctionTemplateAllUnusedParams(T  /*b*/, T  /*e*/) {;}

static void dontGetConfusedByParametersInFunctionTypes() { void (*F)(int i); }

template <typename T> class Function {};
static Function<void(int, int i)> dontGetConfusedByFunctionReturnTypes() {
  return Function<void(int, int)>();
}

namespace PR38055 {
namespace {
struct a {
  void b(int c) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: parameter 'c' is unused
// CHECK-FIXES: void b() {;}
};
template <class>
class d {
  a e;
  void f() { e.b(0); }
};
}  // namespace
}  // namespace PR38055

namespace strict_mode_off {
// Do not warn on empty function bodies.
void f1(int foo1) {}
void f2(int foo2) {
  // "empty" in the AST sense, not in textual sense.
}
void f3(int foo3) {;}
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: parameter 'foo3' is unused
// CHECK-FIXES: void f3(int  /*foo3*/) {;}

class E {
  int i;

public:
  E(int j) {}
};
class F {
  int i;

public:
  // Constructor initializer counts as a non-empty body.
  F(int j) : i() {}
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'j' is unused
// CHECK-FIXES: F(int  /*j*/) : i() {}
};

class A {
public:
  A();
  A(int);
};
class B : public A {
public:
  B(int i) : A() {}
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'i' is unused
// CHECK-FIXES: B(int  /*i*/) : A() {}
};
} // namespace strict_mode_off

namespace lambda {
using fn = void(int);
void f(fn *);
void test() {
  // CHECK-MESSAGES: :[[@LINE+2]]:12: warning: parameter 'I' is unused
  // CHECK-FIXES: f([](int  /*I*/) { return; });
  f([](int I) { return; });
}
} // namespace lambda

// Do not warn on naked functions.
[[gnu::naked]] int nakedFunction(int a, float b, const char *c) { ; }
__attribute__((naked)) void nakedFunction(int a, int b) { ; }

// CHECK-MESSAGES: header.h:1:38: warning
