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