[analyzer] Checker for uninitialized C++ objects

This checker analyzes C++ constructor calls, and reports uninitialized fields.

Due to the nature of this problem (uninitialized fields after an object
construction), this checker doesn't search for bugs, but rather is a tool to
enforce a specific programming model where every field needs to be initialized.

This checker lands in alpha for now, and a number of followup patches will be
made to reduce false negatives and to make it easier for the user to understand
what rules the checker relies on, eg. whether a derived class' constructor is
responsible for initializing inherited data members or whether it should be
handled in the base class' constructor.

Differential Revision: https://reviews.llvm.org/D45532

llvm-svn: 334935
diff --git a/clang/test/Analysis/cxx-uninitialized-object-inheritance.cpp b/clang/test/Analysis/cxx-uninitialized-object-inheritance.cpp
new file mode 100644
index 0000000..3b048b7
--- /dev/null
+++ b/clang/test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -0,0 +1,775 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -std=c++11 -verify %s
+
+//===----------------------------------------------------------------------===//
+// Non-polymorphic inheritance tests
+//===----------------------------------------------------------------------===//
+
+class NonPolymorphicLeft1 {
+  int x;
+
+protected:
+  int y;
+
+public:
+  NonPolymorphicLeft1() = default;
+  NonPolymorphicLeft1(int) : x(1) {}
+};
+
+class NonPolymorphicInheritanceTest1 : public NonPolymorphicLeft1 {
+  int z;
+
+public:
+  NonPolymorphicInheritanceTest1()
+      : NonPolymorphicLeft1(int{}) {
+    y = 2;
+    z = 3;
+    // All good!
+  }
+};
+
+void fNonPolymorphicInheritanceTest1() {
+  NonPolymorphicInheritanceTest1();
+}
+
+class NonPolymorphicBaseClass2 {
+  int x; // expected-note{{uninitialized field 'this->x'}}
+protected:
+  int y;
+
+public:
+  NonPolymorphicBaseClass2() = default;
+  NonPolymorphicBaseClass2(int) : x(4) {}
+};
+
+class NonPolymorphicInheritanceTest2 : public NonPolymorphicBaseClass2 {
+  int z;
+
+public:
+  NonPolymorphicInheritanceTest2() {
+    y = 5;
+    z = 6; // expected-warning{{1 uninitialized field}}
+  }
+};
+
+void fNonPolymorphicInheritanceTest2() {
+  NonPolymorphicInheritanceTest2();
+}
+
+class NonPolymorphicBaseClass3 {
+  int x;
+
+protected:
+  int y; // expected-note{{uninitialized field 'this->y'}}
+public:
+  NonPolymorphicBaseClass3() = default;
+  NonPolymorphicBaseClass3(int) : x(7) {}
+};
+
+class NonPolymorphicInheritanceTest3 : public NonPolymorphicBaseClass3 {
+  int z;
+
+public:
+  NonPolymorphicInheritanceTest3()
+      : NonPolymorphicBaseClass3(int{}) {
+    z = 8; // expected-warning{{1 uninitialized field}}
+  }
+};
+
+void fNonPolymorphicInheritanceTest3() {
+  NonPolymorphicInheritanceTest3();
+}
+
+class NonPolymorphicBaseClass4 {
+  int x;
+
+protected:
+  int y;
+
+public:
+  NonPolymorphicBaseClass4() = default;
+  NonPolymorphicBaseClass4(int) : x(9) {}
+};
+
+class NonPolymorphicInheritanceTest4 : public NonPolymorphicBaseClass4 {
+  int z; // expected-note{{uninitialized field 'this->z'}}
+
+public:
+  NonPolymorphicInheritanceTest4()
+      : NonPolymorphicBaseClass4(int{}) {
+    y = 10; // expected-warning{{1 uninitialized field}}
+  }
+};
+
+void fNonPolymorphicInheritanceTest4() {
+  NonPolymorphicInheritanceTest4();
+}
+
+//===----------------------------------------------------------------------===//
+// Polymorphic inheritance tests
+//===----------------------------------------------------------------------===//
+
+class PolymorphicLeft1 {
+  int x;
+
+protected:
+  int y;
+
+public:
+  virtual ~PolymorphicLeft1() = default;
+  PolymorphicLeft1() = default;
+  PolymorphicLeft1(int) : x(11) {}
+};
+
+class PolymorphicInheritanceTest1 : public PolymorphicLeft1 {
+  int z;
+
+public:
+  PolymorphicInheritanceTest1()
+      : PolymorphicLeft1(int{}) {
+    y = 12;
+    z = 13;
+    // All good!
+  }
+};
+
+void fPolymorphicInheritanceTest1() {
+  PolymorphicInheritanceTest1();
+}
+
+class PolymorphicRight1 {
+  int x; // expected-note{{uninitialized field 'this->x'}}
+protected:
+  int y;
+
+public:
+  virtual ~PolymorphicRight1() = default;
+  PolymorphicRight1() = default;
+  PolymorphicRight1(int) : x(14) {}
+};
+
+class PolymorphicInheritanceTest2 : public PolymorphicRight1 {
+  int z;
+
+public:
+  PolymorphicInheritanceTest2() {
+    y = 15;
+    z = 16; // expected-warning{{1 uninitialized field}}
+  }
+};
+
+void fPolymorphicInheritanceTest2() {
+  PolymorphicInheritanceTest2();
+}
+
+class PolymorphicBaseClass3 {
+  int x;
+
+protected:
+  int y; // expected-note{{uninitialized field 'this->y'}}
+public:
+  virtual ~PolymorphicBaseClass3() = default;
+  PolymorphicBaseClass3() = default;
+  PolymorphicBaseClass3(int) : x(17) {}
+};
+
+class PolymorphicInheritanceTest3 : public PolymorphicBaseClass3 {
+  int z;
+
+public:
+  PolymorphicInheritanceTest3()
+      : PolymorphicBaseClass3(int{}) {
+    z = 18; // expected-warning{{1 uninitialized field}}
+  }
+};
+
+void fPolymorphicInheritanceTest3() {
+  PolymorphicInheritanceTest3();
+}
+
+class PolymorphicBaseClass4 {
+  int x;
+
+protected:
+  int y;
+
+public:
+  virtual ~PolymorphicBaseClass4() = default;
+  PolymorphicBaseClass4() = default;
+  PolymorphicBaseClass4(int) : x(19) {}
+};
+
+class PolymorphicInheritanceTest4 : public PolymorphicBaseClass4 {
+  int z; // expected-note{{uninitialized field 'this->z'}}
+
+public:
+  PolymorphicInheritanceTest4()
+      : PolymorphicBaseClass4(int{}) {
+    y = 20; // expected-warning{{1 uninitialized field}}
+  }
+};
+
+void fPolymorphicInheritanceTest4() {
+  PolymorphicInheritanceTest4();
+}
+
+//===----------------------------------------------------------------------===//
+// Virtual inheritance tests
+//===----------------------------------------------------------------------===//
+
+class VirtualPolymorphicLeft1 {
+  int x;
+
+protected:
+  int y;
+
+public:
+  virtual ~VirtualPolymorphicLeft1() = default;
+  VirtualPolymorphicLeft1() = default;
+  VirtualPolymorphicLeft1(int) : x(21) {}
+};
+
+class VirtualInheritanceTest1 : virtual public VirtualPolymorphicLeft1 {
+  int z;
+
+public:
+  VirtualInheritanceTest1()
+      : VirtualPolymorphicLeft1(int()) {
+    y = 22;
+    z = 23;
+    // All good!
+  }
+};
+
+void fVirtualInheritanceTest1() {
+  VirtualInheritanceTest1();
+}
+
+class VirtualPolymorphicRight1 {
+  int x; // expected-note{{uninitialized field 'this->x'}}
+protected:
+  int y;
+
+public:
+  virtual ~VirtualPolymorphicRight1() = default;
+  VirtualPolymorphicRight1() = default;
+  VirtualPolymorphicRight1(int) : x(24) {}
+};
+
+class VirtualInheritanceTest2 : virtual public VirtualPolymorphicRight1 {
+  int z;
+
+public:
+  VirtualInheritanceTest2() {
+    y = 25;
+    z = 26; // expected-warning{{1 uninitialized field}}
+  }
+};
+
+void fVirtualInheritanceTest2() {
+  VirtualInheritanceTest2();
+}
+
+class VirtualPolymorphicBaseClass3 {
+  int x;
+
+protected:
+  int y; // expected-note{{uninitialized field 'this->y'}}
+public:
+  virtual ~VirtualPolymorphicBaseClass3() = default;
+  VirtualPolymorphicBaseClass3() = default;
+  VirtualPolymorphicBaseClass3(int) : x(27) {}
+};
+
+class VirtualInheritanceTest3 : virtual public VirtualPolymorphicBaseClass3 {
+  int z;
+
+public:
+  VirtualInheritanceTest3()
+      : VirtualPolymorphicBaseClass3(int{}) {
+    z = 28; // expected-warning{{1 uninitialized field}}
+  }
+};
+
+void fVirtualInheritanceTest3() {
+  VirtualInheritanceTest3();
+}
+
+//===----------------------------------------------------------------------===//
+// Multiple inheritance tests
+//===----------------------------------------------------------------------===//
+
+/*
+        Left        Right
+          \           /
+           \         /
+            \       /
+     MultipleInheritanceTest
+*/
+
+struct Left1 {
+  int x;
+  Left1() = default;
+  Left1(int) : x(29) {}
+};
+struct Right1 {
+  int y;
+  Right1() = default;
+  Right1(int) : y(30) {}
+};
+
+class MultipleInheritanceTest1 : public Left1, public Right1 {
+  int z;
+
+public:
+  MultipleInheritanceTest1()
+      : Left1(int{}),
+        Right1(char{}) {
+    z = 31;
+    // All good!
+  }
+
+  MultipleInheritanceTest1(int)
+      : Left1(int{}) {
+    y = 32;
+    z = 33;
+    // All good!
+  }
+
+  MultipleInheritanceTest1(int, int)
+      : Right1(char{}) {
+    x = 34;
+    z = 35;
+    // All good!
+  }
+};
+
+void fMultipleInheritanceTest1() {
+  MultipleInheritanceTest1();
+  MultipleInheritanceTest1(int());
+  MultipleInheritanceTest1(int(), int());
+}
+
+struct Left2 {
+  int x;
+  Left2() = default;
+  Left2(int) : x(36) {}
+};
+struct Right2 {
+  int y; // expected-note{{uninitialized field 'this->y'}}
+  Right2() = default;
+  Right2(int) : y(37) {}
+};
+
+class MultipleInheritanceTest2 : public Left2, public Right2 {
+  int z;
+
+public:
+  MultipleInheritanceTest2()
+      : Left2(int{}) {
+    z = 38; // expected-warning{{1 uninitialized field}}
+  }
+};
+
+void fMultipleInheritanceTest2() {
+  MultipleInheritanceTest2();
+}
+
+struct Left3 {
+  int x; // expected-note{{uninitialized field 'this->x'}}
+  Left3() = default;
+  Left3(int) : x(39) {}
+};
+struct Right3 {
+  int y;
+  Right3() = default;
+  Right3(int) : y(40) {}
+};
+
+class MultipleInheritanceTest3 : public Left3, public Right3 {
+  int z;
+
+public:
+  MultipleInheritanceTest3()
+      : Right3(char{}) {
+    z = 41; // expected-warning{{1 uninitialized field}}
+  }
+};
+
+void fMultipleInheritanceTest3() {
+  MultipleInheritanceTest3();
+}
+
+struct Left4 {
+  int x;
+  Left4() = default;
+  Left4(int) : x(42) {}
+};
+struct Right4 {
+  int y;
+  Right4() = default;
+  Right4(int) : y(43) {}
+};
+
+class MultipleInheritanceTest4 : public Left4, public Right4 {
+  int z; // expected-note{{uninitialized field 'this->z'}}
+
+public:
+  MultipleInheritanceTest4()
+      : Left4(int{}),
+        Right4(char{}) { // expected-warning{{1 uninitialized field}}
+  }
+};
+
+void fMultipleInheritanceTest4() {
+  MultipleInheritanceTest4();
+}
+
+struct Left5 {
+  int x;
+  Left5() = default;
+  Left5(int) : x(44) {}
+};
+struct Right5 {
+  int y; // expected-note{{uninitialized field 'this->y'}}
+  Right5() = default;
+  Right5(int) : y(45) {}
+};
+
+class MultipleInheritanceTest5 : public Left5, public Right5 {
+  int z; // expected-note{{uninitialized field 'this->z'}}
+
+public:
+  MultipleInheritanceTest5() // expected-warning{{2 uninitialized fields}}
+      : Left5(int{}) {
+  }
+};
+
+void fMultipleInheritanceTest5() {
+  MultipleInheritanceTest5();
+}
+
+//===----------------------------------------------------------------------===//
+// Non-virtual diamond inheritance tests
+//===----------------------------------------------------------------------===//
+
+/*
+  NonVirtualBase   NonVirtualBase
+        |                |
+        |                |
+        |                |
+     First              Second
+        \                /
+         \              /
+          \            /
+  NonVirtualDiamondInheritanceTest
+*/
+
+struct NonVirtualBase1 {
+  int x;
+  NonVirtualBase1() = default;
+  NonVirtualBase1(int) : x(46) {}
+};
+struct First1 : public NonVirtualBase1 {
+  First1() = default;
+  First1(int) : NonVirtualBase1(int{}) {}
+};
+struct Second1 : public NonVirtualBase1 {
+  Second1() = default;
+  Second1(int) : NonVirtualBase1(int{}) {}
+};
+
+class NonVirtualDiamondInheritanceTest1 : public First1, public Second1 {
+  int z;
+
+public:
+  NonVirtualDiamondInheritanceTest1()
+      : First1(int{}),
+        Second1(int{}) {
+    z = 47;
+    // All good!
+  }
+
+  NonVirtualDiamondInheritanceTest1(int)
+      : First1(int{}) {
+    Second1::x = 48;
+    z = 49;
+    // All good!
+  }
+
+  NonVirtualDiamondInheritanceTest1(int, int)
+      : Second1(int{}) {
+    First1::x = 50;
+    z = 51;
+    // All good!
+  }
+};
+
+void fNonVirtualDiamondInheritanceTest1() {
+  NonVirtualDiamondInheritanceTest1();
+  NonVirtualDiamondInheritanceTest1(int());
+  NonVirtualDiamondInheritanceTest1(int(), int());
+}
+
+struct NonVirtualBase2 {
+  int x; // expected-note{{uninitialized field 'this->x'}}
+  NonVirtualBase2() = default;
+  NonVirtualBase2(int) : x(52) {}
+};
+struct First2 : public NonVirtualBase2 {
+  First2() = default;
+  First2(int) : NonVirtualBase2(int{}) {}
+};
+struct Second2 : public NonVirtualBase2 {
+  Second2() = default;
+  Second2(int) : NonVirtualBase2(int{}) {}
+};
+
+class NonVirtualDiamondInheritanceTest2 : public First2, public Second2 {
+  int z;
+
+public:
+  NonVirtualDiamondInheritanceTest2()
+      : First2(int{}) {
+    z = 53; // expected-warning{{1 uninitialized field}}
+  }
+};
+
+void fNonVirtualDiamondInheritanceTest2() {
+  NonVirtualDiamondInheritanceTest2();
+}
+
+struct NonVirtualBase3 {
+  int x; // expected-note{{uninitialized field 'this->x'}}
+  NonVirtualBase3() = default;
+  NonVirtualBase3(int) : x(54) {}
+};
+struct First3 : public NonVirtualBase3 {
+  First3() = default;
+  First3(int) : NonVirtualBase3(int{}) {}
+};
+struct Second3 : public NonVirtualBase3 {
+  Second3() = default;
+  Second3(int) : NonVirtualBase3(int{}) {}
+};
+
+class NonVirtualDiamondInheritanceTest3 : public First3, public Second3 {
+  int z;
+
+public:
+  NonVirtualDiamondInheritanceTest3()
+      : Second3(int{}) {
+    z = 55; // expected-warning{{1 uninitialized field}}
+  }
+};
+
+void fNonVirtualDiamondInheritanceTest3() {
+  NonVirtualDiamondInheritanceTest3();
+}
+
+struct NonVirtualBase4 {
+  int x; // expected-note{{uninitialized field 'this->x'}}
+  // expected-note@-1{{uninitialized field 'this->x'}}
+  NonVirtualBase4() = default;
+  NonVirtualBase4(int) : x(56) {}
+};
+struct First4 : public NonVirtualBase4 {
+  First4() = default;
+  First4(int) : NonVirtualBase4(int{}) {}
+};
+struct Second4 : public NonVirtualBase4 {
+  Second4() = default;
+  Second4(int) : NonVirtualBase4(int{}) {}
+};
+
+class NonVirtualDiamondInheritanceTest4 : public First4, public Second4 {
+  int z;
+
+public:
+  NonVirtualDiamondInheritanceTest4() {
+    z = 57; // expected-warning{{2 uninitialized fields}}
+  }
+};
+
+void fNonVirtualDiamondInheritanceTest4() {
+  NonVirtualDiamondInheritanceTest4();
+}
+
+struct NonVirtualBase5 {
+  int x;
+  NonVirtualBase5() = default;
+  NonVirtualBase5(int) : x(58) {}
+};
+struct First5 : public NonVirtualBase5 {
+  First5() = default;
+  First5(int) : NonVirtualBase5(int{}) {}
+};
+struct Second5 : public NonVirtualBase5 {
+  Second5() = default;
+  Second5(int) : NonVirtualBase5(int{}) {}
+};
+
+class NonVirtualDiamondInheritanceTest5 : public First5, public Second5 {
+  int z; // expected-note{{uninitialized field 'this->z'}}
+
+public:
+  NonVirtualDiamondInheritanceTest5()
+      : First5(int{}),
+        Second5(int{}) { // expected-warning{{1 uninitialized field}}
+  }
+};
+
+void fNonVirtualDiamondInheritanceTest5() {
+  NonVirtualDiamondInheritanceTest5();
+}
+
+struct NonVirtualBase6 {
+  int x; // expected-note{{uninitialized field 'this->x'}}
+  NonVirtualBase6() = default;
+  NonVirtualBase6(int) : x(59) {}
+};
+struct First6 : public NonVirtualBase6 {
+  First6() = default;
+  First6(int) : NonVirtualBase6(int{}) {}
+};
+struct Second6 : public NonVirtualBase6 {
+  Second6() = default;
+  Second6(int) : NonVirtualBase6(int{}) {}
+};
+
+class NonVirtualDiamondInheritanceTest6 : public First6, public Second6 {
+  int z; // expected-note{{uninitialized field 'this->z'}}
+
+public:
+  NonVirtualDiamondInheritanceTest6() // expected-warning{{2 uninitialized fields}}
+      : First6(int{}) {
+    // 'z' and 'Second::x' unintialized
+  }
+};
+
+void fNonVirtualDiamondInheritanceTest6() {
+  NonVirtualDiamondInheritanceTest6();
+}
+
+//===----------------------------------------------------------------------===//
+// Virtual diamond inheritance tests
+//===----------------------------------------------------------------------===//
+
+/*
+           VirtualBase
+            /       \
+           /         \
+          /           \
+  VirtualFirst     VirtualSecond
+          \           /
+           \         /
+            \       /
+   VirtualDiamondInheritanceTest
+*/
+
+struct VirtualBase1 {
+  int x;
+  VirtualBase1() = default;
+  VirtualBase1(int) : x(60) {}
+};
+struct VirtualFirst1 : virtual public VirtualBase1 {
+  VirtualFirst1() = default;
+  VirtualFirst1(int) : VirtualBase1(int{}) {}
+  VirtualFirst1(int, int) { x = 61; }
+};
+struct VirtualSecond1 : virtual public VirtualBase1 {
+  VirtualSecond1() = default;
+  VirtualSecond1(int) : VirtualBase1(int{}) {}
+  VirtualSecond1(int, int) { x = 62; }
+};
+
+class VirtualDiamondInheritanceTest1 : public VirtualFirst1, public VirtualSecond1 {
+
+public:
+  VirtualDiamondInheritanceTest1() {
+    x = 0;
+    // All good!
+  }
+
+  VirtualDiamondInheritanceTest1(int)
+      : VirtualFirst1(int{}, int{}),
+        VirtualSecond1(int{}, int{}) {
+    // All good!
+  }
+
+  VirtualDiamondInheritanceTest1(int, int)
+      : VirtualFirst1(int{}, int{}) {
+    // All good!
+  }
+};
+
+void fVirtualDiamondInheritanceTest1() {
+  VirtualDiamondInheritanceTest1();
+  VirtualDiamondInheritanceTest1(int());
+  VirtualDiamondInheritanceTest1(int(), int());
+}
+
+struct VirtualBase2 {
+  int x; // expected-note{{uninitialized field 'this->x'}}
+  VirtualBase2() = default;
+  VirtualBase2(int) : x(63) {}
+};
+struct VirtualFirst2 : virtual public VirtualBase2 {
+  VirtualFirst2() = default;
+  VirtualFirst2(int) : VirtualBase2(int{}) {}
+  VirtualFirst2(int, int) { x = 64; }
+};
+struct VirtualSecond2 : virtual public VirtualBase2 {
+  VirtualSecond2() = default;
+  VirtualSecond2(int) : VirtualBase2(int{}) {}
+  VirtualSecond2(int, int) { x = 65; }
+};
+
+class VirtualDiamondInheritanceTest2 : public VirtualFirst2, public VirtualSecond2 {
+
+public:
+  VirtualDiamondInheritanceTest2() // expected-warning{{1 uninitialized field}}
+      : VirtualFirst2(int{}) {
+    // From the N4659 C++ Standard Working Draft:
+    //
+    //   (15.6.2.7)
+    //   [...] A 'mem-initializer' where the 'mem-initializer-id' denotes a
+    //   virtual base class is ignored during execution of a constructor of any
+    //   class that is not the most derived class.
+    //
+    // This means that Left1::x will not be initialized, because in both
+    // VirtualFirst::VirtualFirst(int) and VirtualSecond::VirtualSecond(int)
+    // the constructor delegation to Left1::Left1(int) will be
+    // ignored.
+  }
+};
+
+void fVirtualDiamondInheritanceTest2() {
+  VirtualDiamondInheritanceTest2();
+}
+
+struct VirtualBase3 {
+  int x; // expected-note{{uninitialized field 'this->x'}}
+  VirtualBase3() = default;
+  VirtualBase3(int) : x(66) {}
+};
+struct VirtualFirst3 : virtual public VirtualBase3 {
+  VirtualFirst3() = default;
+  VirtualFirst3(int) : VirtualBase3(int{}) {}
+  VirtualFirst3(int, int) { x = 67; }
+};
+struct VirtualSecond3 : virtual public VirtualBase3 {
+  VirtualSecond3() = default;
+  VirtualSecond3(int) : VirtualBase3(int{}) {}
+  VirtualSecond3(int, int) { x = 68; }
+};
+
+class VirtualDiamondInheritanceTest3 : public VirtualFirst3, public VirtualSecond3 {
+
+public:
+  VirtualDiamondInheritanceTest3() // expected-warning{{1 uninitialized field}}
+      : VirtualFirst3(int{}) {}
+};
+
+void fVirtualDiamondInheritanceTest3() {
+  VirtualDiamondInheritanceTest3();
+}