// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -std=c++11 -DPEDANTIC -verify %s

// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -std=c++11 -verify %s

//===----------------------------------------------------------------------===//
// Default constructor test.
//===----------------------------------------------------------------------===//

class CompilerGeneratedConstructorTest {
  int a, b, c, d, e, f, g, h, i, j;

public:
  CompilerGeneratedConstructorTest() = default;
};

void fCompilerGeneratedConstructorTest() {
  CompilerGeneratedConstructorTest();
}

#ifdef PEDANTIC
class DefaultConstructorTest {
  int a; // expected-note{{uninitialized field 'this->a'}}

public:
  DefaultConstructorTest();
};

DefaultConstructorTest::DefaultConstructorTest() = default;

void fDefaultConstructorTest() {
  DefaultConstructorTest(); // expected-warning{{1 uninitialized field}}
}
#else
class DefaultConstructorTest {
  int a;

public:
  DefaultConstructorTest();
};

DefaultConstructorTest::DefaultConstructorTest() = default;

void fDefaultConstructorTest() {
  DefaultConstructorTest();
}
#endif // PEDANTIC

//===----------------------------------------------------------------------===//
// Initializer list test.
//===----------------------------------------------------------------------===//

class InitListTest1 {
  int a;
  int b;

public:
  InitListTest1()
      : a(1),
        b(2) {
    // All good!
  }
};

void fInitListTest1() {
  InitListTest1();
}

class InitListTest2 {
  int a;
  int b; // expected-note{{uninitialized field 'this->b'}}

public:
  InitListTest2()
      : a(3) {} // expected-warning{{1 uninitialized field}}
};

void fInitListTest2() {
  InitListTest2();
}

class InitListTest3 {
  int a; // expected-note{{uninitialized field 'this->a'}}
  int b;

public:
  InitListTest3()
      : b(4) {} // expected-warning{{1 uninitialized field}}
};

void fInitListTest3() {
  InitListTest3();
}

//===----------------------------------------------------------------------===//
// Constructor body test.
//===----------------------------------------------------------------------===//

class CtorBodyTest1 {
  int a, b;

public:
  CtorBodyTest1() {
    a = 5;
    b = 6;
    // All good!
  }
};

void fCtorBodyTest1() {
  CtorBodyTest1();
}

class CtorBodyTest2 {
  int a;
  int b; // expected-note{{uninitialized field 'this->b'}}

public:
  CtorBodyTest2() {
    a = 7; // expected-warning{{1 uninitialized field}}
  }
};

void fCtorBodyTest2() {
  CtorBodyTest2();
}

class CtorBodyTest3 {
  int a; // expected-note{{uninitialized field 'this->a'}}
  int b;

public:
  CtorBodyTest3() {
    b = 8; // expected-warning{{1 uninitialized field}}
  }
};

void fCtorBodyTest3() {
  CtorBodyTest3();
}

#ifdef PEDANTIC
class CtorBodyTest4 {
  int a; // expected-note{{uninitialized field 'this->a'}}
  int b; // expected-note{{uninitialized field 'this->b'}}

public:
  CtorBodyTest4() {}
};

void fCtorBodyTest4() {
  CtorBodyTest4(); // expected-warning{{2 uninitialized fields}}
}
#else
class CtorBodyTest4 {
  int a;
  int b;

public:
  CtorBodyTest4() {}
};

void fCtorBodyTest4() {
  CtorBodyTest4();
}
#endif

//===----------------------------------------------------------------------===//
// Constructor delegation test.
//===----------------------------------------------------------------------===//

class CtorDelegationTest1 {
  int a;
  int b;

public:
  CtorDelegationTest1(int)
      : a(9) {
    // leaves 'b' unintialized, but we'll never check this function
  }

  CtorDelegationTest1()
      : CtorDelegationTest1(int{}) { // Initializing 'a'
    b = 10;
    // All good!
  }
};

void fCtorDelegationTest1() {
  CtorDelegationTest1();
}

class CtorDelegationTest2 {
  int a; // expected-note{{uninitialized field 'this->a'}}
  int b;

public:
  CtorDelegationTest2(int)
      : b(11) {
    // leaves 'a' unintialized, but we'll never check this function
  }

  CtorDelegationTest2()
      : CtorDelegationTest2(int{}) { // expected-warning{{1 uninitialized field}}
  }
};

void fCtorDelegationTest2() {
  CtorDelegationTest2();
}

//===----------------------------------------------------------------------===//
// Tests for classes containing records.
//===----------------------------------------------------------------------===//

class ContainsRecordTest1 {
  struct RecordType {
    int x;
    int y;
  } rec;
  int c, d;

public:
  ContainsRecordTest1()
      : rec({12, 13}),
        c(14),
        d(15) {
    // All good!
  }
};

void fContainsRecordTest1() {
  ContainsRecordTest1();
}

class ContainsRecordTest2 {
  struct RecordType {
    int x;
    int y; // expected-note{{uninitialized field 'this->rec.y'}}
  } rec;
  int c, d;

public:
  ContainsRecordTest2()
      : c(16),
        d(17) {
    rec.x = 18; // expected-warning{{1 uninitialized field}}
  }
};

void fContainsRecordTest2() {
  ContainsRecordTest2();
}

class ContainsRecordTest3 {
  struct RecordType {
    int x; // expected-note{{uninitialized field 'this->rec.x'}}
    int y; // expected-note{{uninitialized field 'this->rec.y'}}
  } rec;
  int c, d;

public:
  ContainsRecordTest3()
      : c(19),
        d(20) { // expected-warning{{2 uninitialized fields}}
  }
};

void fContainsRecordTest3() {
  ContainsRecordTest3();
}

class ContainsRecordTest4 {
  struct RecordType {
    int x; // expected-note{{uninitialized field 'this->rec.x'}}
    int y; // expected-note{{uninitialized field 'this->rec.y'}}
  } rec;
  int c, d; // expected-note{{uninitialized field 'this->d'}}

public:
  ContainsRecordTest4()
      : c(19) { // expected-warning{{3 uninitialized fields}}
  }
};

void fContainsRecordTest4() {
  ContainsRecordTest4();
}

//===----------------------------------------------------------------------===//
// Tests for template classes.
//===----------------------------------------------------------------------===//

template <class T>
class IntTemplateClassTest1 {
  T t;
  int b;

public:
  IntTemplateClassTest1(T i) {
    b = 21;
    t = i;
    // All good!
  }
};

void fIntTemplateClassTest1() {
  IntTemplateClassTest1<int>(22);
}

template <class T>
class IntTemplateClassTest2 {
  T t; // expected-note{{uninitialized field 'this->t'}}
  int b;

public:
  IntTemplateClassTest2() {
    b = 23; // expected-warning{{1 uninitialized field}}
  }
};

void fIntTemplateClassTest2() {
  IntTemplateClassTest2<int>();
}

struct Record {
  int x; // expected-note{{uninitialized field 'this->t.x'}}
  int y; // expected-note{{uninitialized field 'this->t.y'}}
};

template <class T>
class RecordTemplateClassTest {
  T t;
  int b;

public:
  RecordTemplateClassTest() {
    b = 24; // expected-warning{{2 uninitialized fields}}
  }
};

void fRecordTemplateClassTest() {
  RecordTemplateClassTest<Record>();
}

//===----------------------------------------------------------------------===//
// Tests involving functions with unknown implementations.
//===----------------------------------------------------------------------===//

template <class T>
void mayInitialize(T &);

template <class T>
void wontInitialize(const T &);

class PassingToUnknownFunctionTest1 {
  int a, b;

public:
  PassingToUnknownFunctionTest1() {
    mayInitialize(a);
    mayInitialize(b);
    // All good!
  }

  PassingToUnknownFunctionTest1(int) {
    mayInitialize(a);
    // All good!
  }

  PassingToUnknownFunctionTest1(int, int) {
    mayInitialize(*this);
    // All good!
  }
};

void fPassingToUnknownFunctionTest1() {
  PassingToUnknownFunctionTest1();
  PassingToUnknownFunctionTest1(int());
  PassingToUnknownFunctionTest1(int(), int());
}

class PassingToUnknownFunctionTest2 {
  int a; // expected-note{{uninitialized field 'this->a'}}
  int b;

public:
  PassingToUnknownFunctionTest2() {
    wontInitialize(a);
    b = 4; // expected-warning{{1 uninitialized field}}
  }
};

void fPassingToUnknownFunctionTest2() {
  PassingToUnknownFunctionTest2();
}

//===----------------------------------------------------------------------===//
// Tests for classes containing unions.
//===----------------------------------------------------------------------===//

// FIXME: As of writing this checker, there is no good support for union types
// in the Static Analyzer. Here is non-exhaustive list of cases.
// Note that the rules for unions are different in C and C++.
// http://lists.llvm.org/pipermail/cfe-dev/2017-March/052910.html

class ContainsSimpleUnionTest1 {
  union SimpleUnion {
    float uf;
    int ui;
    char uc;
  } u;

public:
  ContainsSimpleUnionTest1() {
    u.uf = 3.14;
    // All good!
  }
};

void fContainsSimpleUnionTest1() {
  ContainsSimpleUnionTest1();
}

class ContainsSimpleUnionTest2 {
  union SimpleUnion {
    float uf;
    int ui;
    char uc;
    // TODO: we'd expect the note: {{uninitialized field 'this->u'}}
  } u; // no-note

public:
  ContainsSimpleUnionTest2() {}
};

void fContainsSimpleUnionTest2() {
  // TODO: we'd expect the warning: {{1 uninitialized field}}
  ContainsSimpleUnionTest2(); // no-warning
}

class UnionPointerTest1 {
public:
  union SimpleUnion {
    float uf;
    int ui;
    char uc;
  };

private:
  SimpleUnion *uptr;

public:
  UnionPointerTest1(SimpleUnion *uptr, int) : uptr(uptr) {
    // All good!
  }
};

void fUnionPointerTest1() {
  UnionPointerTest1::SimpleUnion u;
  u.uf = 41;
  UnionPointerTest1(&u, int());
}

class UnionPointerTest2 {
public:
  union SimpleUnion {
    float uf;
    int ui;
    char uc;
  };

private:
  // TODO: we'd expect the note: {{uninitialized field 'this->uptr'}}
  SimpleUnion *uptr; // no-note

public:
  UnionPointerTest2(SimpleUnion *uptr, char) : uptr(uptr) {}
};

void fUnionPointerTest2() {
  UnionPointerTest2::SimpleUnion u;
  // TODO: we'd expect the warning: {{1 uninitialized field}}
  UnionPointerTest2(&u, int()); // no-warning
}

class ContainsUnionWithRecordTest1 {
  union UnionWithRecord {
    struct RecordType {
      int x;
      int y;
    } us;
    double ud;
    long ul;

    UnionWithRecord(){};
  } u;

public:
  ContainsUnionWithRecordTest1() {
    u.ud = 3.14;
    // All good!
  }
};

void fContainsUnionWithRecordTest1() {
  ContainsUnionWithRecordTest1();
}

class ContainsUnionWithRecordTest2 {
  union UnionWithRecord {
    struct RecordType {
      int x;
      int y;
    } us;
    double ud;
    long ul;

    UnionWithRecord(){};
  } u;

public:
  ContainsUnionWithRecordTest2() {
    u.us = UnionWithRecord::RecordType{42, 43};
    // All good!
  }
};

void fContainsUnionWithRecordTest2() {
  ContainsUnionWithRecordTest1();
}

class ContainsUnionWithRecordTest3 {
  union UnionWithRecord {
    struct RecordType {
      int x;
      int y;
    } us;
    double ud;
    long ul;

    UnionWithRecord(){};
    // TODO: we'd expect the note: {{uninitialized field 'this->u'}}
  } u; // no-note

public:
  ContainsUnionWithRecordTest3() {
    UnionWithRecord::RecordType rec;
    rec.x = 44;
    // TODO: we'd expect the warning: {{1 uninitialized field}}
    u.us = rec; // no-warning
  }
};

void fContainsUnionWithRecordTest3() {
  ContainsUnionWithRecordTest3();
}

class ContainsUnionWithSimpleUnionTest1 {
  union UnionWithSimpleUnion {
    union SimpleUnion {
      float uf;
      int ui;
      char uc;
    } usu;
    long ul;
    unsigned uu;
  } u;

public:
  ContainsUnionWithSimpleUnionTest1() {
    u.usu.ui = 5;
    // All good!
  }
};

void fContainsUnionWithSimpleUnionTest1() {
  ContainsUnionWithSimpleUnionTest1();
}

class ContainsUnionWithSimpleUnionTest2 {
  union UnionWithSimpleUnion {
    union SimpleUnion {
      float uf;
      int ui;
      char uc;
    } usu;
    long ul;
    unsigned uu;
    // TODO: we'd expect the note: {{uninitialized field 'this->u'}}
  } u; // no-note

public:
  ContainsUnionWithSimpleUnionTest2() {}
};

void fContainsUnionWithSimpleUnionTest2() {
  // TODO: we'd expect the warning: {{1 uninitialized field}}
  ContainsUnionWithSimpleUnionTest2(); // no-warning
}

//===----------------------------------------------------------------------===//
// Zero initialization tests.
//===----------------------------------------------------------------------===//

struct GlobalVariableTest {
  int i;

  GlobalVariableTest() {}
};

GlobalVariableTest gvt; // no-warning

//===----------------------------------------------------------------------===//
// Copy and move constructor tests.
//===----------------------------------------------------------------------===//

template <class T>
void funcToSquelchCompilerWarnings(const T &t);

#ifdef PEDANTIC
struct CopyConstructorTest {
  int i; // expected-note{{uninitialized field 'this->i'}}

  CopyConstructorTest() : i(1337) {}
  CopyConstructorTest(const CopyConstructorTest &other) {}
};

void fCopyConstructorTest() {
  CopyConstructorTest cct;
  CopyConstructorTest copy = cct; // expected-warning{{1 uninitialized field}}
  funcToSquelchCompilerWarnings(copy);
}
#else
struct CopyConstructorTest {
  int i;

  CopyConstructorTest() : i(1337) {}
  CopyConstructorTest(const CopyConstructorTest &other) {}
};

void fCopyConstructorTest() {
  CopyConstructorTest cct;
  CopyConstructorTest copy = cct;
  funcToSquelchCompilerWarnings(copy);
}
#endif // PEDANTIC

struct MoveConstructorTest {
  // TODO: we'd expect the note: {{uninitialized field 'this->i'}}
  int i; // no-note

  MoveConstructorTest() : i(1337) {}
  MoveConstructorTest(const CopyConstructorTest &other) = delete;
  MoveConstructorTest(const CopyConstructorTest &&other) {}
};

void fMoveConstructorTest() {
  MoveConstructorTest cct;
  // TODO: we'd expect the warning: {{1 uninitialized field}}
  MoveConstructorTest copy(static_cast<MoveConstructorTest &&>(cct)); // no-warning
  funcToSquelchCompilerWarnings(copy);
}

//===----------------------------------------------------------------------===//
// Array tests.
//===----------------------------------------------------------------------===//

struct IntArrayTest {
  int arr[256];

  IntArrayTest() {
    // All good!
  }
};

void fIntArrayTest() {
  IntArrayTest();
}

struct RecordTypeArrayTest {
  struct RecordType {
    int x, y;
  } arr[256];

  RecordTypeArrayTest() {
    // All good!
  }
};

void fRecordTypeArrayTest() {
  RecordTypeArrayTest();
}

template <class T>
class CharArrayPointerTest {
  T *t; // no-crash

public:
  CharArrayPointerTest(T *t, int) : t(t) {}
};

void fCharArrayPointerTest() {
  char str[16] = "012345678912345";
  CharArrayPointerTest<char[16]>(&str, int());
}

//===----------------------------------------------------------------------===//
// Memset tests.
//===----------------------------------------------------------------------===//

struct MemsetTest1 {
  int a, b, c;

  MemsetTest1() {
    __builtin_memset(this, 0, sizeof(decltype(*this)));
  }
};

void fMemsetTest1() {
  MemsetTest1();
}

struct MemsetTest2 {
  int a;

  MemsetTest2() {
    __builtin_memset(&a, 0, sizeof(int));
  }
};

void fMemsetTest2() {
  MemsetTest2();
}

//===----------------------------------------------------------------------===//
// Lambda tests.
//===----------------------------------------------------------------------===//

template <class Callable>
struct LambdaTest1 {
  Callable functor;

  LambdaTest1(const Callable &functor, int) : functor(functor) {
    // All good!
  }
};

void fLambdaTest1() {
  auto isEven = [](int a) { return a % 2 == 0; };
  LambdaTest1<decltype(isEven)>(isEven, int());
}

#ifdef PEDANTIC
template <class Callable>
struct LambdaTest2 {
  Callable functor;

  LambdaTest2(const Callable &functor, int) : functor(functor) {} // expected-warning{{1 uninitialized field}}
};

void fLambdaTest2() {
  int b;
  auto equals = [&b](int a) { return a == b; }; // expected-note{{uninitialized field 'this->functor.'}}
  LambdaTest2<decltype(equals)>(equals, int());
}
#else
template <class Callable>
struct LambdaTest2 {
  Callable functor;

  LambdaTest2(const Callable &functor, int) : functor(functor) {}
};

void fLambdaTest2() {
  int b;
  auto equals = [&b](int a) { return a == b; };
  LambdaTest2<decltype(equals)>(equals, int());
}
#endif //PEDANTIC

#ifdef PEDANTIC
namespace LT3Detail {

struct RecordType {
  int x; // expected-note{{uninitialized field 'this->functor..x'}}
  int y; // expected-note{{uninitialized field 'this->functor..y'}}
};

} // namespace LT3Detail
template <class Callable>
struct LambdaTest3 {
  Callable functor;

  LambdaTest3(const Callable &functor, int) : functor(functor) {} // expected-warning{{2 uninitialized fields}}
};

void fLambdaTest3() {
  LT3Detail::RecordType rec1;
  auto equals = [&rec1](LT3Detail::RecordType rec2) {
    return rec1.x == rec2.x;
  };
  LambdaTest3<decltype(equals)>(equals, int());
}
#else
namespace LT3Detail {

struct RecordType {
  int x;
  int y;
};

} // namespace LT3Detail
template <class Callable>
struct LambdaTest3 {
  Callable functor;

  LambdaTest3(const Callable &functor, int) : functor(functor) {}
};

void fLambdaTest3() {
  LT3Detail::RecordType rec1;
  auto equals = [&rec1](LT3Detail::RecordType rec2) {
    return rec1.x == rec2.x;
  };
  LambdaTest3<decltype(equals)>(equals, int());
}
#endif //PEDANTIC

//===----------------------------------------------------------------------===//
// System header tests.
//===----------------------------------------------------------------------===//

#include "Inputs/system-header-simulator-for-cxx-uninitialized-object.h"

struct SystemHeaderTest1 {
  RecordInSystemHeader rec; // defined in the system header simulator

  SystemHeaderTest1() {
    // All good!
  }
};

void fSystemHeaderTest1() {
  SystemHeaderTest1();
}

#ifdef PEDANTIC
struct SystemHeaderTest2 {
  struct RecordType {
    int x; // expected-note{{uninitialized field 'this->container.t.x}}
    int y; // expected-note{{uninitialized field 'this->container.t.y}}
  };
  ContainerInSystemHeader<RecordType> container;

  SystemHeaderTest2(RecordType &rec, int) : container(rec) {} // expected-warning{{2 uninitialized fields}}
};

void fSystemHeaderTest2() {
  SystemHeaderTest2::RecordType rec;
  SystemHeaderTest2(rec, int());
}
#else
struct SystemHeaderTest2 {
  struct RecordType {
    int x;
    int y;
  };
  ContainerInSystemHeader<RecordType> container;

  SystemHeaderTest2(RecordType &rec, int) : container(rec) {}
};

void fSystemHeaderTest2() {
  SystemHeaderTest2::RecordType rec;
  SystemHeaderTest2(rec, int());
}
#endif //PEDANTIC

//===----------------------------------------------------------------------===//
// Incomplete type tests.
//===----------------------------------------------------------------------===//

struct IncompleteTypeTest1 {
  struct RecordType;
  // no-crash
  RecordType *recptr; // expected-note{{uninitialized pointer 'this->recptr}}
  int dontGetFilteredByNonPedanticMode = 0;

  IncompleteTypeTest1() {} // expected-warning{{1 uninitialized field}}
};

void fIncompleteTypeTest1() {
  IncompleteTypeTest1();
}

struct IncompleteTypeTest2 {
  struct RecordType;
  RecordType *recptr; // no-crash
  int dontGetFilteredByNonPedanticMode = 0;

  RecordType *recordTypeFactory();

  IncompleteTypeTest2() : recptr(recordTypeFactory()) {}
};

void fIncompleteTypeTest2() {
  IncompleteTypeTest2();
}

struct IncompleteTypeTest3 {
  struct RecordType;
  RecordType &recref; // no-crash
  int dontGetFilteredByNonPedanticMode = 0;

  RecordType &recordTypeFactory();

  IncompleteTypeTest3() : recref(recordTypeFactory()) {}
};

void fIncompleteTypeTest3() {
  IncompleteTypeTest3();
}

//===----------------------------------------------------------------------===//
// Builtin type or enumeration type related tests.
//===----------------------------------------------------------------------===//

struct IntegralTypeTest {
  int a; // expected-note{{uninitialized field 'this->a'}}
  int dontGetFilteredByNonPedanticMode = 0;

  IntegralTypeTest() {} // expected-warning{{1 uninitialized field}}
};

void fIntegralTypeTest() {
  IntegralTypeTest();
}

struct FloatingTypeTest {
  float a; // expected-note{{uninitialized field 'this->a'}}
  int dontGetFilteredByNonPedanticMode = 0;

  FloatingTypeTest() {} // expected-warning{{1 uninitialized field}}
};

void fFloatingTypeTest() {
  FloatingTypeTest();
}

struct NullptrTypeTypeTest {
  decltype(nullptr) a; // expected-note{{uninitialized field 'this->a'}}
  int dontGetFilteredByNonPedanticMode = 0;

  NullptrTypeTypeTest() {} // expected-warning{{1 uninitialized field}}
};

void fNullptrTypeTypeTest() {
  NullptrTypeTypeTest();
}

struct EnumTest {
  enum Enum {
    A,
    B
  } enum1; // expected-note{{uninitialized field 'this->enum1'}}
  enum class Enum2 {
    A,
    B
  } enum2; // expected-note{{uninitialized field 'this->enum2'}}
  int dontGetFilteredByNonPedanticMode = 0;

  EnumTest() {} // expected-warning{{2 uninitialized fields}}
};

void fEnumTest() {
  EnumTest();
}

//===----------------------------------------------------------------------===//
// Tests for constructor calls within another cunstructor, without the two
// records being in any relation.
//===----------------------------------------------------------------------===//

void halt() __attribute__((__noreturn__));
void assert(int b) {
  if (!b)
    halt();
}

// While a singleton would make more sense as a static variable, that would zero
// initialize all of its fields, hence the not too practical implementation.
struct Singleton {
  // TODO: we'd expect the note: {{uninitialized field 'this->i'}}
  int i; // no-note

  Singleton() {
    assert(!isInstantiated);
    // TODO: we'd expect the warning: {{1 uninitialized field}}
    isInstantiated = true; // no-warning
  }

  ~Singleton() {
    isInstantiated = false;
  }

  static bool isInstantiated;
};

bool Singleton::isInstantiated = false;

struct SingletonTest {
  int dontGetFilteredByNonPedanticMode = 0;

  SingletonTest() {
    Singleton();
  }
};

void fSingletonTest() {
  SingletonTest();
}

//===----------------------------------------------------------------------===//
// C++11 member initializer tests.
//===----------------------------------------------------------------------===//

struct CXX11MemberInitTest1 {
  int a = 3;
  int b;
  CXX11MemberInitTest1() : b(2) {
    // All good!
  }
};

void fCXX11MemberInitTest1() {
  CXX11MemberInitTest1();
}

struct CXX11MemberInitTest2 {
  struct RecordType {
    // TODO: we'd expect the note: {{uninitialized field 'this->rec.a'}}
    int a; // no-note
    // TODO: we'd expect the note: {{uninitialized field 'this->rec.b'}}
    int b; // no-note

    RecordType(int) {}
  };

  RecordType rec = RecordType(int());
  int dontGetFilteredByNonPedanticMode = 0;

  CXX11MemberInitTest2() {}
};

void fCXX11MemberInitTest2() {
  // TODO: we'd expect the warning: {{2 uninitializeds field}}
  CXX11MemberInitTest2(); // no-warning
}
