summaryrefslogtreecommitdiffstats
path: root/clang/test/Analysis/pointer-to-member.cpp
diff options
context:
space:
mode:
authorDevin Coughlin <dcoughlin@apple.com>2016-12-15 21:27:06 +0000
committerDevin Coughlin <dcoughlin@apple.com>2016-12-15 21:27:06 +0000
commit64c01f7bef8d65716f12e7556238ea8f8c2c010e (patch)
tree41fb79676ba342a7cfb2638af738338f2b0d25ec /clang/test/Analysis/pointer-to-member.cpp
parent6698c15cb64c5a6b27521466ab8565a906b2323f (diff)
downloadbcm5719-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.cpp154
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
OpenPOWER on IntegriCloud