Clang Project

clang_source_code/test/Analysis/const-method-call.cpp
1// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify -analyzer-config eagerly-assume=false %s
2
3void clang_analyzer_eval(bool);
4
5struct A {
6  int x;
7  void foo() const;
8  void bar();
9
10  void testImplicitThisSyntax() {
11    x = 3;
12    foo();
13    clang_analyzer_eval(x == 3); // expected-warning{{TRUE}}
14    bar();
15    clang_analyzer_eval(x == 3); // expected-warning{{UNKNOWN}}
16  }
17};
18
19struct B {
20  mutable int mut;
21  void foo() const;
22};
23
24struct C {
25  int *p;
26  void foo() const;
27};
28
29struct MutBase {
30  mutable int b_mut;
31};
32
33struct MutDerived : MutBase {
34  void foo() const;
35};
36
37struct PBase {
38  int *p;
39};
40
41struct PDerived : PBase {
42  void foo() const;
43};
44
45struct Inner {
46  int x;
47  int *p;
48  void bar() const;
49};
50
51struct Outer {
52  int x;
53  Inner in;
54  void foo() const;
55};
56
57void checkThatConstMethodWithoutDefinitionDoesNotInvalidateObject() {
58  A t;
59  t.x = 3;
60  t.foo();
61  clang_analyzer_eval(t.x == 3); // expected-warning{{TRUE}}
62  // Test non-const does invalidate
63  t.bar();
64  clang_analyzer_eval(t.x); // expected-warning{{UNKNOWN}}
65}
66
67void checkThatConstMethodDoesInvalidateMutableFields() {
68  B t;
69  t.mut = 4;
70  t.foo();
71  clang_analyzer_eval(t.mut); // expected-warning{{UNKNOWN}}
72}
73
74void checkThatConstMethodDoesInvalidatePointedAtMemory() {
75  int x = 1;
76  C t;
77  t.p = &x;
78  t.foo();
79  clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}
80  clang_analyzer_eval(t.p == &x); // expected-warning{{TRUE}}
81}
82
83void checkThatConstMethodDoesInvalidateInheritedMutableFields() {
84  MutDerived t;
85  t.b_mut = 4;
86  t.foo();
87  clang_analyzer_eval(t.b_mut); // expected-warning{{UNKNOWN}}
88}
89
90void checkThatConstMethodDoesInvalidateInheritedPointedAtMemory() {
91  int x = 1;
92  PDerived t;
93  t.p = &x;
94  t.foo();
95  clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}
96  clang_analyzer_eval(t.p == &x); // expected-warning{{TRUE}}
97}
98
99void checkThatConstMethodDoesInvalidateContainedPointedAtMemory() {
100  int x = 1;
101  Outer t;
102  t.x = 2;
103  t.in.p = &x;
104  t.foo();
105  clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}
106  clang_analyzer_eval(t.x == 2); // expected-warning{{TRUE}}
107  clang_analyzer_eval(t.in.p == &x); // expected-warning{{TRUE}}
108}
109
110void checkThatContainedConstMethodDoesNotInvalidateObjects() {
111  Outer t;
112  t.x = 1;
113  t.in.x = 2;
114  t.in.bar();
115  clang_analyzer_eval(t.x == 1); // expected-warning{{TRUE}}
116  clang_analyzer_eval(t.in.x == 2); // expected-warning{{TRUE}}
117}
118
119void checkPointerTypedThisExpression(A *a) {
120  a->x = 3;
121  a->foo();
122  clang_analyzer_eval(a->x == 3); // expected-warning{{TRUE}}
123  a->bar();
124  clang_analyzer_eval(a->x == 3); // expected-warning{{UNKNOWN}}
125}
126
127void checkReferenceTypedThisExpression(A &a) {
128  a.x = 3;
129  a.foo();
130  clang_analyzer_eval(a.x == 3); // expected-warning{{TRUE}}
131  a.bar();
132  clang_analyzer_eval(a.x == 3); // expected-warning{{UNKNOWN}}
133}
134
135// --- Versions of the above tests where the const method is inherited --- //
136
137struct B1 {
138  void foo() const;
139};
140
141struct D1 : public B1 {
142  int x;
143};
144
145struct D2 : public B1 {
146  mutable int mut;
147};
148
149struct D3 : public B1 {
150  int *p;
151};
152
153struct DInner : public B1 {
154  int x;
155  int *p;
156};
157
158struct DOuter : public B1 {
159  int x;
160  DInner in;
161};
162
163void checkThatInheritedConstMethodDoesNotInvalidateObject() {
164  D1 t;
165  t.x = 1;
166  t.foo();
167  clang_analyzer_eval(t.x == 1); // expected-warning{{TRUE}}
168}
169
170void checkThatInheritedConstMethodDoesInvalidateMutableFields() {
171  D2 t;
172  t.mut = 1;
173  t.foo();
174  clang_analyzer_eval(t.mut); // expected-warning{{UNKNOWN}}
175}
176
177void checkThatInheritedConstMethodDoesInvalidatePointedAtMemory() {
178  int x = 1;
179  D3 t;
180  t.p = &x;
181  t.foo();
182  clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}
183  clang_analyzer_eval(t.p == &x); // expected-warning{{TRUE}}
184}
185
186void checkThatInheritedConstMethodDoesInvalidateContainedPointedAtMemory() {
187  int x = 1;
188  DOuter t;
189  t.x = 2;
190  t.in.x = 3;
191  t.in.p = &x;
192  t.foo();
193  clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}
194  clang_analyzer_eval(t.x == 2); // expected-warning{{TRUE}}
195  clang_analyzer_eval(t.in.x == 3); // expected-warning{{TRUE}}
196  clang_analyzer_eval(t.in.p == &x); // expected-warning{{TRUE}}
197}
198
199void checkThatInheritedContainedConstMethodDoesNotInvalidateObjects() {
200  DOuter t;
201  t.x = 1;
202  t.in.x = 2;
203  t.in.foo();
204  clang_analyzer_eval(t.x == 1); // expected-warning{{TRUE}}
205  clang_analyzer_eval(t.in.x == 2); // expected-warning{{TRUE}}
206}
207
208// --- PR21606 --- //
209
210struct s1 {
211    void g(const int *i) const;
212};
213
214struct s2 {
215    void f(int *i) {
216        m_i = i;
217        m_s.g(m_i);
218        if (m_i)
219            *i = 42; // no-warning
220    }
221
222    int *m_i;
223    s1 m_s;
224};
225
226void PR21606()
227{
228    s2().f(0);
229}
230
231// --- PR25392 --- //
232
233struct HasConstMemberFunction {
234public:
235  void constMemberFunction() const;
236};
237
238HasConstMemberFunction hasNoReturn() { } // expected-warning {{control reaches end of non-void function}}
239
240void testUnknownWithConstMemberFunction() {
241  hasNoReturn().constMemberFunction();
242}
243
244void testNonRegionLocWithConstMemberFunction() {
245  (*((HasConstMemberFunction *)(&&label))).constMemberFunction();
246
247  label: return;
248}
249
250// FIXME
251// When there is a circular reference to an object and a const method is called
252// the object is not invalidated because TK_PreserveContents has already been
253// set.
254struct Outer2;
255
256struct InnerWithRef {
257  Outer2 *ref;
258};
259
260struct Outer2 {
261  int x;
262  InnerWithRef in;
263  void foo() const;
264};
265
266void checkThatConstMethodCallDoesInvalidateObjectForCircularReferences() {
267  Outer2 t;
268  t.x = 1;
269  t.in.ref = &t;
270  t.foo();
271  // FIXME: Should be UNKNOWN.
272  clang_analyzer_eval(t.x); // expected-warning{{TRUE}}
273}
274