| // 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); |
| } |