1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
2 
3 void clang_analyzer_eval(bool);
4 
5 struct A {
6   int x;
7   void foo() const;
8   void bar();
9 };
10 
11 struct B {
12   mutable int mut;
13   void foo() const;
14 };
15 
16 struct C {
17   int *p;
18   void foo() const;
19 };
20 
21 struct MutBase {
22   mutable int b_mut;
23 };
24 
25 struct MutDerived : MutBase {
26   void foo() const;
27 };
28 
29 struct PBase {
30   int *p;
31 };
32 
33 struct PDerived : PBase {
34   void foo() const;
35 };
36 
37 struct Inner {
38   int x;
39   int *p;
40   void bar() const;
41 };
42 
43 struct Outer {
44   int x;
45   Inner in;
46   void foo() const;
47 };
48 
checkThatConstMethodWithoutDefinitionDoesNotInvalidateObject()49 void 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 
checkThatConstMethodDoesInvalidateMutableFields()59 void checkThatConstMethodDoesInvalidateMutableFields() {
60   B t;
61   t.mut = 4;
62   t.foo();
63   clang_analyzer_eval(t.mut); // expected-warning{{UNKNOWN}}
64 }
65 
checkThatConstMethodDoesInvalidatePointedAtMemory()66 void 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 
checkThatConstMethodDoesInvalidateInheritedMutableFields()75 void checkThatConstMethodDoesInvalidateInheritedMutableFields() {
76   MutDerived t;
77   t.b_mut = 4;
78   t.foo();
79   clang_analyzer_eval(t.b_mut); // expected-warning{{UNKNOWN}}
80 }
81 
checkThatConstMethodDoesInvalidateInheritedPointedAtMemory()82 void 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 
checkThatConstMethodDoesInvalidateContainedPointedAtMemory()91 void 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 
checkThatContainedConstMethodDoesNotInvalidateObjects()102 void 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 
113 struct B1 {
114   void foo() const;
115 };
116 
117 struct D1 : public B1 {
118   int x;
119 };
120 
121 struct D2 : public B1 {
122   mutable int mut;
123 };
124 
125 struct D3 : public B1 {
126   int *p;
127 };
128 
129 struct DInner : public B1 {
130   int x;
131   int *p;
132 };
133 
134 struct DOuter : public B1 {
135   int x;
136   DInner in;
137 };
138 
checkThatInheritedConstMethodDoesNotInvalidateObject()139 void checkThatInheritedConstMethodDoesNotInvalidateObject() {
140   D1 t;
141   t.x = 1;
142   t.foo();
143   clang_analyzer_eval(t.x == 1); // expected-warning{{TRUE}}
144 }
145 
checkThatInheritedConstMethodDoesInvalidateMutableFields()146 void checkThatInheritedConstMethodDoesInvalidateMutableFields() {
147   D2 t;
148   t.mut = 1;
149   t.foo();
150   clang_analyzer_eval(t.mut); // expected-warning{{UNKNOWN}}
151 }
152 
checkThatInheritedConstMethodDoesInvalidatePointedAtMemory()153 void 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 
checkThatInheritedConstMethodDoesInvalidateContainedPointedAtMemory()162 void 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 
checkThatInheritedContainedConstMethodDoesNotInvalidateObjects()175 void 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 
186 struct s1 {
187     void g(const int *i) const;
188 };
189 
190 struct s2 {
fs2191     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 
PR21606()202 void PR21606()
203 {
204     s2().f(0);
205 }
206 
207 // --- PR25392 --- //
208 
209 struct HasConstMemberFunction {
210 public:
211   void constMemberFunction() const;
212 };
213 
hasNoReturn()214 HasConstMemberFunction hasNoReturn() { } // expected-warning {{control reaches end of non-void function}}
215 
testUnknownWithConstMemberFunction()216 void testUnknownWithConstMemberFunction() {
217   hasNoReturn().constMemberFunction();
218 }
219 
testNonRegionLocWithConstMemberFunction()220 void 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.
230 struct Outer2;
231 
232 struct InnerWithRef {
233   Outer2 *ref;
234 };
235 
236 struct Outer2 {
237   int x;
238   InnerWithRef in;
239   void foo() const;
240 };
241 
checkThatConstMethodCallDoesInvalidateObjectForCircularReferences()242 void 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