diff options
author | Devin Coughlin <dcoughlin@apple.com> | 2016-12-15 21:27:06 +0000 |
---|---|---|
committer | Devin Coughlin <dcoughlin@apple.com> | 2016-12-15 21:27:06 +0000 |
commit | 64c01f7bef8d65716f12e7556238ea8f8c2c010e (patch) | |
tree | 41fb79676ba342a7cfb2638af738338f2b0d25ec /clang/test/Analysis/pointer-to-member.cpp | |
parent | 6698c15cb64c5a6b27521466ab8565a906b2323f (diff) | |
download | bcm5719-llvm-64c01f7bef8d65716f12e7556238ea8f8c2c010e.tar.gz bcm5719-llvm-64c01f7bef8d65716f12e7556238ea8f8c2c010e.zip |
[analyzer] Add a new SVal to support pointer-to-member operations.
Add a new type of NonLoc SVal for C++ pointer-to-member operations. This SVal
supports both pointers to member functions and pointers to member data.
A patch by Kirill Romanenkov!
Differential Revision: https://reviews.llvm.org/D25475
llvm-svn: 289873
Diffstat (limited to 'clang/test/Analysis/pointer-to-member.cpp')
-rw-r--r-- | clang/test/Analysis/pointer-to-member.cpp | 154 |
1 files changed, 144 insertions, 10 deletions
diff --git a/clang/test/Analysis/pointer-to-member.cpp b/clang/test/Analysis/pointer-to-member.cpp index 37d04399b7b..eef20627a13 100644 --- a/clang/test/Analysis/pointer-to-member.cpp +++ b/clang/test/Analysis/pointer-to-member.cpp @@ -35,8 +35,7 @@ void testComparison() { clang_analyzer_eval(&A::getPtr == &A::getPtr); // expected-warning{{TRUE}} clang_analyzer_eval(&A::getPtr == 0); // expected-warning{{FALSE}} - // FIXME: Should be TRUE. - clang_analyzer_eval(&A::m_ptr == &A::m_ptr); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(&A::m_ptr == &A::m_ptr); // expected-warning{{TRUE}} } namespace PR15742 { @@ -62,21 +61,156 @@ namespace PR15742 { } } -// --------------- -// FALSE NEGATIVES -// --------------- - bool testDereferencing() { A obj; obj.m_ptr = 0; A::MemberPointer member = &A::m_ptr; - // FIXME: Should be TRUE. - clang_analyzer_eval(obj.*member == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(obj.*member == 0); // expected-warning{{TRUE}} member = 0; - // FIXME: Should emit a null dereference. - return obj.*member; // no-warning + return obj.*member; // expected-warning{{The result of the '.*' expression is undefined}} +} + +namespace testPointerToMemberFunction { + struct A { + virtual int foo() { return 1; } + int bar() { return 2; } + }; + + struct B : public A { + virtual int foo() { return 3; } + }; + + typedef int (A::*AFnPointer)(); + typedef int (B::*BFnPointer)(); + + void testPointerToMemberCasts() { + AFnPointer AFP = &A::bar; + BFnPointer StaticCastedBase2Derived = static_cast<BFnPointer>(&A::bar), + CCastedBase2Derived = (BFnPointer) (&A::bar); + A a; + B b; + + clang_analyzer_eval((a.*AFP)() == 2); // expected-warning{{TRUE}} + clang_analyzer_eval((b.*StaticCastedBase2Derived)() == 2); // expected-warning{{TRUE}} + clang_analyzer_eval(((b.*CCastedBase2Derived)() == 2)); // expected-warning{{TRUE}} + } + + void testPointerToMemberVirtualCall() { + A a; + B b; + A *APtr = &a; + AFnPointer AFP = &A::foo; + + clang_analyzer_eval((APtr->*AFP)() == 1); // expected-warning{{TRUE}} + + APtr = &b; + + clang_analyzer_eval((APtr->*AFP)() == 3); // expected-warning{{TRUE}} + } +} // end of testPointerToMemberFunction namespace + +namespace testPointerToMemberData { + struct A { + int i; + }; + + void testPointerToMemberData() { + int A::*AMdPointer = &A::i; + A a; + + a.i = 42; + a.*AMdPointer += 1; + + clang_analyzer_eval(a.i == 43); // expected-warning{{TRUE}} + } +} // end of testPointerToMemberData namespace + +namespace testPointerToMemberMiscCasts { +struct B { + int f; +}; + +struct D : public B { + int g; +}; + +void foo() { + D d; + d.f = 7; + + int B::* pfb = &B::f; + int D::* pfd = pfb; + int v = d.*pfd; + + clang_analyzer_eval(v == 7); // expected-warning{{TRUE}} +} +} // end of testPointerToMemberMiscCasts namespace + +namespace testPointerToMemberMiscCasts2 { +struct B { + int f; +}; +struct L : public B { }; +struct R : public B { }; +struct D : public L, R { }; + +void foo() { + D d; + + int B::* pb = &B::f; + int L::* pl = pb; + int R::* pr = pb; + + int D::* pdl = pl; + int D::* pdr = pr; + + clang_analyzer_eval(pdl == pdr); // expected-warning{{FALSE}} + clang_analyzer_eval(pb == pl); // expected-warning{{TRUE}} +} +} // end of testPointerToMemberMiscCasts2 namespace + +namespace testPointerToMemberDiamond { +struct B { + int f; +}; +struct L1 : public B { }; +struct R1 : public B { }; +struct M : public L1, R1 { }; +struct L2 : public M { }; +struct R2 : public M { }; +struct D2 : public L2, R2 { }; + +void diamond() { + M m; + + static_cast<L1 *>(&m)->f = 7; + static_cast<R1 *>(&m)->f = 16; + + int L1::* pl1 = &B::f; + int M::* pm_via_l1 = pl1; + + int R1::* pr1 = &B::f; + int M::* pm_via_r1 = pr1; + + clang_analyzer_eval(m.*(pm_via_l1) == 7); // expected-warning {{TRUE}} + clang_analyzer_eval(m.*(pm_via_r1) == 16); // expected-warning {{TRUE}} +} + +void double_diamond() { + D2 d2; + + static_cast<L1 *>(static_cast<L2 *>(&d2))->f = 1; + static_cast<L1 *>(static_cast<R2 *>(&d2))->f = 2; + static_cast<R1 *>(static_cast<L2 *>(&d2))->f = 3; + static_cast<R1 *>(static_cast<R2 *>(&d2))->f = 4; + + clang_analyzer_eval(d2.*(static_cast<int D2::*>(static_cast<int L2::*>(static_cast<int L1::*>(&B::f)))) == 1); // expected-warning {{TRUE}} + clang_analyzer_eval(d2.*(static_cast<int D2::*>(static_cast<int R2::*>(static_cast<int L1::*>(&B::f)))) == 2); // expected-warning {{TRUE}} + clang_analyzer_eval(d2.*(static_cast<int D2::*>(static_cast<int L2::*>(static_cast<int R1::*>(&B::f)))) == 3); // expected-warning {{TRUE}} + clang_analyzer_eval(d2.*(static_cast<int D2::*>(static_cast<int R2::*>(static_cast<int R1::*>(&B::f)))) == 4); // expected-warning {{TRUE}} } +} // end of testPointerToMemberDiamond namespace |