Clang Project

clang_source_code/test/Analysis/pointer-to-member.cpp
1// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
2
3void clang_analyzer_eval(bool);
4
5struct A {
6  // This conversion operator allows implicit conversion to bool but not to other integer types.
7  typedef A * (A::*MemberPointer);
8  operator MemberPointer() const { return m_ptr ? &A::m_ptr : 0; }
9
10  A *m_ptr;
11
12  A *getPtr();
13  typedef A * (A::*MemberFnPointer)(void);
14};
15
16void testConditionalUse() {
17  A obj;
18
19  obj.m_ptr = &obj;
20  clang_analyzer_eval(obj.m_ptr); // expected-warning{{TRUE}}
21  clang_analyzer_eval(&A::m_ptr); // expected-warning{{TRUE}}
22  clang_analyzer_eval(obj); // expected-warning{{TRUE}}
23
24  obj.m_ptr = 0;
25  clang_analyzer_eval(obj.m_ptr); // expected-warning{{FALSE}}
26  clang_analyzer_eval(A::MemberPointer(0)); // expected-warning{{FALSE}}
27  clang_analyzer_eval(obj); // expected-warning{{FALSE}}
28
29  clang_analyzer_eval(&A::getPtr); // expected-warning{{TRUE}}
30  clang_analyzer_eval(A::MemberFnPointer(0)); // expected-warning{{FALSE}}
31}
32
33
34void testComparison() {
35  clang_analyzer_eval(&A::getPtr == &A::getPtr); // expected-warning{{TRUE}}
36  clang_analyzer_eval(&A::getPtr == 0); // expected-warning{{FALSE}}
37
38  clang_analyzer_eval(&A::m_ptr == &A::m_ptr); // expected-warning{{TRUE}}
39}
40
41namespace PR15742 {
42  template <class _T1, class _T2> struct A {
43    A (const _T1 &, const _T2 &);
44  };
45  
46  typedef void *NPIdentifier;
47
48  template <class T> class B {
49  public:
50    typedef A<NPIdentifier, bool (T::*) (const NPIdentifier *, unsigned,
51                                         NPIdentifier *)> MethodMapMember;
52  };
53
54  class C : public B<C> {
55  public:
56    bool Find(const NPIdentifier *, unsigned, NPIdentifier *);
57  };
58
59  void InitStaticData () {
60    C::MethodMapMember(0, &C::Find); // don't crash
61  }
62}
63
64bool testDereferencing() {
65  A obj;
66  obj.m_ptr = 0;
67
68  A::MemberPointer member = &A::m_ptr;
69
70  clang_analyzer_eval(obj.*member == 0); // expected-warning{{TRUE}}
71
72  member = 0;
73
74  return obj.*member; // expected-warning{{The result of the '.*' expression is undefined}}
75}
76
77namespace testPointerToMemberFunction {
78  struct A {
79    virtual int foo() { return 1; }
80    int bar() { return 2; }
81    int static staticMemberFunction(int p) { return p + 1; };
82  };
83
84  struct B : public A {
85    virtual int foo() { return 3; }
86  };
87
88  typedef int (A::*AFnPointer)();
89  typedef int (B::*BFnPointer)();
90
91  void testPointerToMemberCasts() {
92    AFnPointer AFP = &A::bar;
93    BFnPointer StaticCastedBase2Derived = static_cast<BFnPointer>(&A::bar),
94               CCastedBase2Derived = (BFnPointer) (&A::bar);
95    A a;
96    B b;
97
98    clang_analyzer_eval((a.*AFP)() == 2); // expected-warning{{TRUE}}
99    clang_analyzer_eval((b.*StaticCastedBase2Derived)() == 2); // expected-warning{{TRUE}}
100    clang_analyzer_eval(((b.*CCastedBase2Derived)() == 2)); // expected-warning{{TRUE}}
101  }
102
103  void testPointerToMemberVirtualCall() {
104    A a;
105    B b;
106    A *APtr = &a;
107    AFnPointer AFP = &A::foo;
108
109    clang_analyzer_eval((APtr->*AFP)() == 1); // expected-warning{{TRUE}}
110
111    APtr = &b;
112
113    clang_analyzer_eval((APtr->*AFP)() == 3); // expected-warning{{TRUE}}
114  }
115
116  void testPointerToStaticMemberCall() {
117    int (*fPtr)(int) = &A::staticMemberFunction;
118    if (fPtr != 0) { // no-crash
119      clang_analyzer_eval(fPtr(2) == 3); // expected-warning{{TRUE}}
120    }
121  }
122} // end of testPointerToMemberFunction namespace
123
124namespace testPointerToMemberData {
125  struct A {
126    int i;
127    static int j;
128  };
129
130  void testPointerToMemberData() {
131    int A::*AMdPointer = &A::i;
132    A a;
133
134    a.i = 42;
135    a.*AMdPointer += 1;
136
137    clang_analyzer_eval(a.i == 43); // expected-warning{{TRUE}}
138
139    int *ptrToStaticField = &A::j;
140    if (ptrToStaticField != 0) {
141      *ptrToStaticField = 7;
142      clang_analyzer_eval(*ptrToStaticField == 7); // expected-warning{{TRUE}}
143      clang_analyzer_eval(A::j == 7); // expected-warning{{TRUE}}
144    }
145  }
146} // end of testPointerToMemberData namespace
147
148namespace testPointerToMemberMiscCasts {
149struct B {
150  int f;
151};
152
153struct D : public B {
154  int g;
155};
156
157void foo() {
158  D d;
159  d.f = 7;
160
161  int B::* pfb = &B::f;
162  int D::* pfd = pfb;
163  int v = d.*pfd;
164
165  clang_analyzer_eval(v == 7); // expected-warning{{TRUE}}
166}
167} // end of testPointerToMemberMiscCasts namespace
168
169namespace testPointerToMemberMiscCasts2 {
170struct B {
171  int f;
172};
173struct L : public B { };
174struct R : public B { };
175struct D : public L, R { };
176
177void foo() {
178  D d;
179
180  int B::* pb = &B::f;
181  int L::* pl = pb;
182  int R::* pr = pb;
183
184  int D::* pdl = pl;
185  int D::* pdr = pr;
186
187  clang_analyzer_eval(pdl == pdr); // expected-warning{{FALSE}}
188  clang_analyzer_eval(pb == pl); // expected-warning{{TRUE}}
189}
190} // end of testPointerToMemberMiscCasts2 namespace
191
192namespace testPointerToMemberDiamond {
193struct B {
194  int f;
195};
196struct L1 : public B { };
197struct R1 : public B { };
198struct M : public L1, R1 { };
199struct L2 : public M { };
200struct R2 : public M { };
201struct D2 : public L2, R2 { };
202
203void diamond() {
204  M m;
205
206  static_cast<L1 *>(&m)->f = 7;
207  static_cast<R1 *>(&m)->f = 16;
208
209  int L1::* pl1 = &B::f;
210  int M::* pm_via_l1 = pl1;
211
212  int R1::* pr1 = &B::f;
213  int M::* pm_via_r1 = pr1;
214
215  clang_analyzer_eval(m.*(pm_via_l1) == 7); // expected-warning {{TRUE}}
216  clang_analyzer_eval(m.*(pm_via_r1) == 16); // expected-warning {{TRUE}}
217}
218
219void double_diamond() {
220  D2 d2;
221
222  static_cast<L1 *>(static_cast<L2 *>(&d2))->f = 1;
223  static_cast<L1 *>(static_cast<R2 *>(&d2))->f = 2;
224  static_cast<R1 *>(static_cast<L2 *>(&d2))->f = 3;
225  static_cast<R1 *>(static_cast<R2 *>(&d2))->f = 4;
226
227  clang_analyzer_eval(d2.*(static_cast<int D2::*>(static_cast<int L2::*>(static_cast<int L1::*>(&B::f)))) == 1); // expected-warning {{TRUE}}
228  clang_analyzer_eval(d2.*(static_cast<int D2::*>(static_cast<int R2::*>(static_cast<int L1::*>(&B::f)))) == 2); // expected-warning {{TRUE}}
229  clang_analyzer_eval(d2.*(static_cast<int D2::*>(static_cast<int L2::*>(static_cast<int R1::*>(&B::f)))) == 3); // expected-warning {{TRUE}}
230  clang_analyzer_eval(d2.*(static_cast<int D2::*>(static_cast<int R2::*>(static_cast<int R1::*>(&B::f)))) == 4); // expected-warning {{TRUE}}
231}
232} // end of testPointerToMemberDiamond namespace
233
234namespace testAnonymousMember {
235struct A {
236  struct {
237    int x;
238  };
239  struct {
240    struct {
241      int y;
242    };
243  };
244  struct {
245    union {
246      int z;
247    };
248  };
249};
250
251void test() {
252  clang_analyzer_eval(&A::x); // expected-warning{{TRUE}}
253  clang_analyzer_eval(&A::y); // expected-warning{{TRUE}}
254  clang_analyzer_eval(&A::z); // expected-warning{{TRUE}}
255
256  // FIXME: These should be true.
257  int A::*l = &A::x, A::*m = &A::y, A::*n = &A::z;
258  clang_analyzer_eval(l); // expected-warning{{UNKNOWN}}
259  clang_analyzer_eval(m); // expected-warning{{UNKNOWN}}
260  clang_analyzer_eval(n); // expected-warning{{UNKNOWN}}
261
262  // FIXME: These should be true as well.
263  A a;
264  a.x = 1;
265  clang_analyzer_eval(a.*l == 1); // expected-warning{{UNKNOWN}}
266  a.y = 2;
267  clang_analyzer_eval(a.*m == 2); // expected-warning{{UNKNOWN}}
268  a.z = 3;
269  clang_analyzer_eval(a.*n == 3); // expected-warning{{UNKNOWN}}
270}
271} // end of testAnonymousMember namespace
272