// RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.cplusplus.UninitializedObject \ // RUN: -analyzer-config optin.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \ // RUN: -analyzer-config optin.cplusplus.UninitializedObject:IgnoreGuardedFields=true \ // RUN: -std=c++11 -verify %s //===----------------------------------------------------------------------===// // Helper functions for tests. //===----------------------------------------------------------------------===// [[noreturn]] void halt(); void assert(int b) { if (!b) halt(); } int rand(); //===----------------------------------------------------------------------===// // Tests for fields properly guarded by asserts. //===----------------------------------------------------------------------===// class NoUnguardedFieldsTest { public: enum Kind { V, A }; private: int Volume, Area; Kind K; public: NoUnguardedFieldsTest(Kind K) : K(K) { switch (K) { case V: Volume = 0; break; case A: Area = 0; break; } } void operator-() { assert(K == Kind::A); (void)Area; } void operator+() { assert(K == Kind::V); (void)Volume; } }; void fNoUnguardedFieldsTest() { NoUnguardedFieldsTest T1(NoUnguardedFieldsTest::Kind::A); NoUnguardedFieldsTest T2(NoUnguardedFieldsTest::Kind::V); } class NoUngardedFieldsNoReturnFuncCalledTest { public: enum Kind { V, A }; private: int Volume, Area; Kind K; public: NoUngardedFieldsNoReturnFuncCalledTest(Kind K) : K(K) { switch (K) { case V: Volume = 0; break; case A: Area = 0; break; } } void operator-() { halt(); (void)Area; } void operator+() { halt(); (void)Volume; } }; void fNoUngardedFieldsNoReturnFuncCalledTest() { NoUngardedFieldsNoReturnFuncCalledTest T1(NoUngardedFieldsNoReturnFuncCalledTest::Kind::A); NoUngardedFieldsNoReturnFuncCalledTest T2(NoUngardedFieldsNoReturnFuncCalledTest::Kind::V); } class NoUnguardedFieldsWithUndefMethodTest { public: enum Kind { V, A }; private: int Volume, Area; Kind K; public: NoUnguardedFieldsWithUndefMethodTest(Kind K) : K(K) { switch (K) { case V: Volume = 0; break; case A: Area = 0; break; } } void operator-() { assert(K == Kind::A); (void)Area; } void operator+() { assert(K == Kind::V); (void)Volume; } // We're checking method definitions for guards, so this is a no-crash test // whether we handle methods without definitions. void methodWithoutDefinition(); }; void fNoUnguardedFieldsWithUndefMethodTest() { NoUnguardedFieldsWithUndefMethodTest T1(NoUnguardedFieldsWithUndefMethodTest::Kind::A); NoUnguardedFieldsWithUndefMethodTest T2(NoUnguardedFieldsWithUndefMethodTest::Kind::V); } class UnguardedFieldThroughMethodTest { public: enum Kind { V, A }; private: int Volume, Area; // expected-note {{uninitialized field 'this->Volume'}} Kind K; public: UnguardedFieldThroughMethodTest(Kind K) : K(K) { switch (K) { case V: Volume = 0; break; case A: Area = 0; // expected-warning {{1 uninitialized field}} break; } } void operator-() { assert(K == Kind::A); (void)Area; } void operator+() { (void)Volume; } }; void fUnguardedFieldThroughMethodTest() { UnguardedFieldThroughMethodTest T1(UnguardedFieldThroughMethodTest::Kind::A); } class UnguardedPublicFieldsTest { public: enum Kind { V, A }; public: // Note that fields are public. int Volume, Area; // expected-note {{uninitialized field 'this->Volume'}} Kind K; public: UnguardedPublicFieldsTest(Kind K) : K(K) { switch (K) { case V: Volume = 0; break; case A: Area = 0; // expected-warning {{1 uninitialized field}} break; } } void operator-() { assert(K == Kind::A); (void)Area; } void operator+() { assert(K == Kind::V); (void)Volume; } }; void fUnguardedPublicFieldsTest() { UnguardedPublicFieldsTest T1(UnguardedPublicFieldsTest::Kind::A); } //===----------------------------------------------------------------------===// // Highlights of some false negatives due to syntactic checking. //===----------------------------------------------------------------------===// class UnguardedFalseNegativeTest1 { public: enum Kind { V, A }; private: int Volume, Area; Kind K; public: UnguardedFalseNegativeTest1(Kind K) : K(K) { switch (K) { case V: Volume = 0; break; case A: Area = 0; break; } } void operator-() { if (rand()) assert(K == Kind::A); (void)Area; } void operator+() { if (rand()) assert(K == Kind::V); (void)Volume; } }; void fUnguardedFalseNegativeTest1() { UnguardedFalseNegativeTest1 T1(UnguardedFalseNegativeTest1::Kind::A); } class UnguardedFalseNegativeTest2 { public: enum Kind { V, A }; private: int Volume, Area; Kind K; public: UnguardedFalseNegativeTest2(Kind K) : K(K) { switch (K) { case V: Volume = 0; break; case A: Area = 0; break; } } void operator-() { assert(rand()); (void)Area; } void operator+() { assert(rand()); (void)Volume; } }; void fUnguardedFalseNegativeTest2() { UnguardedFalseNegativeTest2 T1(UnguardedFalseNegativeTest2::Kind::A); } //===----------------------------------------------------------------------===// // Tests for other guards. These won't be as thorough, as other guards are // matched the same way as asserts, so if they are recognized, they are expected // to work as well as asserts do. // // None of these tests expect warnings, since the flag works correctly if these // fields are regarded properly guarded. //===----------------------------------------------------------------------===// class IfGuardedFieldsTest { public: enum Kind { V, A }; private: int Volume, Area; Kind K; public: IfGuardedFieldsTest(Kind K) : K(K) { switch (K) { case V: Volume = 0; break; case A: Area = 0; break; } } void operator-() { if (K != Kind::A) return; (void)Area; } void operator+() { if (K != Kind::V) return; (void)Volume; } }; void fIfGuardedFieldsTest() { IfGuardedFieldsTest T1(IfGuardedFieldsTest::Kind::A); IfGuardedFieldsTest T2(IfGuardedFieldsTest::Kind::V); } class SwitchGuardedFieldsTest { public: enum Kind { V, A }; private: int Volume, Area; Kind K; public: SwitchGuardedFieldsTest(Kind K) : K(K) { switch (K) { case V: Volume = 0; break; case A: Area = 0; break; } } int operator-() { switch (K) { case Kind::A: return Area; case Kind::V: return -1; } } int operator+() { switch (K) { case Kind::A: return Area; case Kind::V: return -1; } } }; void fSwitchGuardedFieldsTest() { SwitchGuardedFieldsTest T1(SwitchGuardedFieldsTest::Kind::A); SwitchGuardedFieldsTest T2(SwitchGuardedFieldsTest::Kind::V); } class ConditionalOperatorGuardedFieldsTest { public: enum Kind { V, A }; private: int Volume, Area; Kind K; public: ConditionalOperatorGuardedFieldsTest(Kind K) : K(K) { switch (K) { case V: Volume = 0; break; case A: Area = 0; break; } } int operator-() { return K == Kind::A ? Area : -1; } int operator+() { return K == Kind::V ? Volume : -1; } }; void fConditionalOperatorGuardedFieldsTest() { ConditionalOperatorGuardedFieldsTest T1(ConditionalOperatorGuardedFieldsTest::Kind::A); ConditionalOperatorGuardedFieldsTest T2(ConditionalOperatorGuardedFieldsTest::Kind::V); }