| // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify %s |
| |
| void clang_analyzer_eval(bool); |
| void clang_analyzer_checkInlined(bool); |
| |
| // A simplified version of std::move. |
| template <typename T> |
| T &&move(T &obj) { |
| return static_cast<T &&>(obj); |
| } |
| |
| |
| struct Wrapper { |
| __strong id obj; |
| }; |
| |
| void test() { |
| Wrapper w; |
| // force a diagnostic |
| *(char *)0 = 1; // expected-warning{{Dereference of null pointer}} |
| } |
| |
| |
| struct IntWrapper { |
| int x; |
| }; |
| |
| void testCopyConstructor() { |
| IntWrapper a; |
| a.x = 42; |
| |
| IntWrapper b(a); |
| clang_analyzer_eval(b.x == 42); // expected-warning{{TRUE}} |
| } |
| |
| struct NonPODIntWrapper { |
| int x; |
| |
| virtual int get(); |
| }; |
| |
| void testNonPODCopyConstructor() { |
| NonPODIntWrapper a; |
| a.x = 42; |
| |
| NonPODIntWrapper b(a); |
| clang_analyzer_eval(b.x == 42); // expected-warning{{TRUE}} |
| } |
| |
| |
| namespace ConstructorVirtualCalls { |
| class A { |
| public: |
| int *out1, *out2, *out3; |
| |
| virtual int get() { return 1; } |
| |
| A(int *out1) { |
| *out1 = get(); |
| } |
| }; |
| |
| class B : public A { |
| public: |
| virtual int get() { return 2; } |
| |
| B(int *out1, int *out2) : A(out1) { |
| *out2 = get(); |
| } |
| }; |
| |
| class C : public B { |
| public: |
| virtual int get() { return 3; } |
| |
| C(int *out1, int *out2, int *out3) : B(out1, out2) { |
| *out3 = get(); |
| } |
| }; |
| |
| void test() { |
| int a, b, c; |
| |
| C obj(&a, &b, &c); |
| clang_analyzer_eval(a == 1); // expected-warning{{TRUE}} |
| clang_analyzer_eval(b == 2); // expected-warning{{TRUE}} |
| clang_analyzer_eval(c == 3); // expected-warning{{TRUE}} |
| |
| clang_analyzer_eval(obj.get() == 3); // expected-warning{{TRUE}} |
| |
| // Sanity check for devirtualization. |
| A *base = &obj; |
| clang_analyzer_eval(base->get() == 3); // expected-warning{{TRUE}} |
| } |
| } |
| |
| namespace TemporaryConstructor { |
| class BoolWrapper { |
| public: |
| BoolWrapper() { |
| clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} |
| value = true; |
| } |
| bool value; |
| }; |
| |
| void test() { |
| // PR13717 - Don't crash when a CXXTemporaryObjectExpr is inlined. |
| if (BoolWrapper().value) |
| return; |
| } |
| } |
| |
| |
| namespace ConstructorUsedAsRValue { |
| using TemporaryConstructor::BoolWrapper; |
| |
| bool extractValue(BoolWrapper b) { |
| return b.value; |
| } |
| |
| void test() { |
| bool result = extractValue(BoolWrapper()); |
| clang_analyzer_eval(result); // expected-warning{{TRUE}} |
| } |
| } |
| |
| namespace PODUninitialized { |
| class POD { |
| public: |
| int x, y; |
| }; |
| |
| class PODWrapper { |
| public: |
| POD p; |
| }; |
| |
| class NonPOD { |
| public: |
| int x, y; |
| |
| NonPOD() {} |
| NonPOD(const NonPOD &Other) |
| : x(Other.x), y(Other.y) // expected-warning {{undefined}} |
| { |
| } |
| NonPOD(NonPOD &&Other) |
| : x(Other.x), y(Other.y) // expected-warning {{undefined}} |
| { |
| } |
| |
| NonPOD &operator=(const NonPOD &Other) |
| { |
| x = Other.x; |
| y = Other.y; // expected-warning {{undefined}} |
| return *this; |
| } |
| NonPOD &operator=(NonPOD &&Other) |
| { |
| x = Other.x; |
| y = Other.y; // expected-warning {{undefined}} |
| return *this; |
| } |
| }; |
| |
| class NonPODWrapper { |
| public: |
| class Inner { |
| public: |
| int x, y; |
| |
| Inner() {} |
| Inner(const Inner &Other) |
| : x(Other.x), y(Other.y) // expected-warning {{undefined}} |
| { |
| } |
| Inner(Inner &&Other) |
| : x(Other.x), y(Other.y) // expected-warning {{undefined}} |
| { |
| } |
| |
| Inner &operator=(const Inner &Other) |
| { |
| x = Other.x; // expected-warning {{undefined}} |
| y = Other.y; |
| return *this; |
| } |
| Inner &operator=(Inner &&Other) |
| { |
| x = Other.x; // expected-warning {{undefined}} |
| y = Other.y; |
| return *this; |
| } |
| }; |
| |
| Inner p; |
| }; |
| |
| void testPOD() { |
| POD p; |
| p.x = 1; |
| POD p2 = p; // no-warning |
| clang_analyzer_eval(p2.x == 1); // expected-warning{{TRUE}} |
| POD p3 = move(p); // no-warning |
| clang_analyzer_eval(p3.x == 1); // expected-warning{{TRUE}} |
| |
| // Use rvalues as well. |
| clang_analyzer_eval(POD(p3).x == 1); // expected-warning{{TRUE}} |
| |
| PODWrapper w; |
| w.p.y = 1; |
| PODWrapper w2 = w; // no-warning |
| clang_analyzer_eval(w2.p.y == 1); // expected-warning{{TRUE}} |
| PODWrapper w3 = move(w); // no-warning |
| clang_analyzer_eval(w3.p.y == 1); // expected-warning{{TRUE}} |
| |
| // Use rvalues as well. |
| clang_analyzer_eval(PODWrapper(w3).p.y == 1); // expected-warning{{TRUE}} |
| } |
| |
| void testNonPOD() { |
| NonPOD p; |
| p.x = 1; |
| NonPOD p2 = p; |
| } |
| |
| void testNonPODMove() { |
| NonPOD p; |
| p.x = 1; |
| NonPOD p2 = move(p); |
| } |
| |
| void testNonPODWrapper() { |
| NonPODWrapper w; |
| w.p.y = 1; |
| NonPODWrapper w2 = w; |
| } |
| |
| void testNonPODWrapperMove() { |
| NonPODWrapper w; |
| w.p.y = 1; |
| NonPODWrapper w2 = move(w); |
| } |
| |
| // Not strictly about constructors, but trivial assignment operators should |
| // essentially work the same way. |
| namespace AssignmentOperator { |
| void testPOD() { |
| POD p; |
| p.x = 1; |
| POD p2; |
| p2 = p; // no-warning |
| clang_analyzer_eval(p2.x == 1); // expected-warning{{TRUE}} |
| POD p3; |
| p3 = move(p); // no-warning |
| clang_analyzer_eval(p3.x == 1); // expected-warning{{TRUE}} |
| |
| PODWrapper w; |
| w.p.y = 1; |
| PODWrapper w2; |
| w2 = w; // no-warning |
| clang_analyzer_eval(w2.p.y == 1); // expected-warning{{TRUE}} |
| PODWrapper w3; |
| w3 = move(w); // no-warning |
| clang_analyzer_eval(w3.p.y == 1); // expected-warning{{TRUE}} |
| } |
| |
| void testReturnValue() { |
| POD p; |
| p.x = 1; |
| POD p2; |
| clang_analyzer_eval(&(p2 = p) == &p2); // expected-warning{{TRUE}} |
| |
| PODWrapper w; |
| w.p.y = 1; |
| PODWrapper w2; |
| clang_analyzer_eval(&(w2 = w) == &w2); // expected-warning{{TRUE}} |
| } |
| |
| void testNonPOD() { |
| NonPOD p; |
| p.x = 1; |
| NonPOD p2; |
| p2 = p; |
| } |
| |
| void testNonPODMove() { |
| NonPOD p; |
| p.x = 1; |
| NonPOD p2; |
| p2 = move(p); |
| } |
| |
| void testNonPODWrapper() { |
| NonPODWrapper w; |
| w.p.y = 1; |
| NonPODWrapper w2; |
| w2 = w; |
| } |
| |
| void testNonPODWrapperMove() { |
| NonPODWrapper w; |
| w.p.y = 1; |
| NonPODWrapper w2; |
| w2 = move(w); |
| } |
| } |
| } |