1// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c %s
2// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c++ -analyzer-config c++-inlining=constructors %s
3// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c %s
4// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c++ -analyzer-config c++-inlining=constructors %s
5
6void clang_analyzer_eval(int);
7
8struct S {
9  int field;
10
11#if __cplusplus
12  const struct S *getThis() const { return this; }
13  const struct S *operator +() const { return this; }
14
15  bool check() const { return this == this; }
16  bool operator !() const { return this != this; }
17
18  int operator *() const { return field; }
19#endif
20};
21
22#if __cplusplus
23const struct S *operator -(const struct S &s) { return &s; }
24bool operator ~(const struct S &s) { return (&s) != &s; }
25#endif
26
27
28#ifdef INLINE
29struct S getS() {
30  struct S s = { 42 };
31  return s;
32}
33#else
34struct S getS();
35#endif
36
37
38void testAssignment() {
39  struct S s = getS();
40
41  if (s.field != 42) return;
42  clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}}
43
44  s.field = 0;
45  clang_analyzer_eval(s.field == 0); // expected-warning{{TRUE}}
46
47#if __cplusplus
48  clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}}
49  clang_analyzer_eval(+s == &s); // expected-warning{{TRUE}}
50  clang_analyzer_eval(-s == &s); // expected-warning{{TRUE}}
51
52  clang_analyzer_eval(s.check()); // expected-warning{{TRUE}}
53  clang_analyzer_eval(!s); // expected-warning{{FALSE}}
54  clang_analyzer_eval(~s); // expected-warning{{FALSE}}
55
56  clang_analyzer_eval(*s == 0); // expected-warning{{TRUE}}
57#endif
58}
59
60
61void testImmediateUse() {
62  int x = getS().field;
63
64  if (x != 42) return;
65  clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
66
67#if __cplusplus
68  clang_analyzer_eval((void *)getS().getThis() == (void *)&x); // expected-warning{{FALSE}}
69  clang_analyzer_eval((void *)+getS() == (void *)&x); // expected-warning{{FALSE}}
70  clang_analyzer_eval((void *)-getS() == (void *)&x); // expected-warning{{FALSE}}
71
72  clang_analyzer_eval(getS().check()); // expected-warning{{TRUE}}
73  clang_analyzer_eval(!getS()); // expected-warning{{FALSE}}
74  clang_analyzer_eval(~getS()); // expected-warning{{FALSE}}
75#endif
76}
77
78int getConstrainedField(struct S s) {
79  if (s.field != 42) return 42;
80  return s.field;
81}
82
83int getAssignedField(struct S s) {
84  s.field = 42;
85  return s.field;
86}
87
88void testArgument() {
89  clang_analyzer_eval(getConstrainedField(getS()) == 42); // expected-warning{{TRUE}}
90  clang_analyzer_eval(getAssignedField(getS()) == 42); // expected-warning{{TRUE}}
91}
92
93void testImmediateUseParens() {
94  int x = ((getS())).field;
95
96  if (x != 42) return;
97  clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
98
99  clang_analyzer_eval(getConstrainedField(((getS()))) == 42); // expected-warning{{TRUE}}
100  clang_analyzer_eval(getAssignedField(((getS()))) == 42); // expected-warning{{TRUE}}
101
102#if __cplusplus
103  clang_analyzer_eval(((getS())).check()); // expected-warning{{TRUE}}
104  clang_analyzer_eval(!((getS()))); // expected-warning{{FALSE}}
105  clang_analyzer_eval(~((getS()))); // expected-warning{{FALSE}}
106#endif
107}
108
109
110//--------------------
111// C++-only tests
112//--------------------
113
114#if __cplusplus
115void testReferenceAssignment() {
116  const S &s = getS();
117
118  if (s.field != 42) return;
119  clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}}
120
121  clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}}
122  clang_analyzer_eval(+s == &s); // expected-warning{{TRUE}}
123
124  clang_analyzer_eval(s.check()); // expected-warning{{TRUE}}
125  clang_analyzer_eval(!s); // expected-warning{{FALSE}}
126  clang_analyzer_eval(~s); // expected-warning{{FALSE}}
127
128  clang_analyzer_eval(*s == 42); // expected-warning{{TRUE}}
129}
130
131
132int getConstrainedFieldRef(const S &s) {
133  if (s.field != 42) return 42;
134  return s.field;
135}
136
137bool checkThis(const S &s) {
138  return s.getThis() == &s;
139}
140
141bool checkThisOp(const S &s) {
142  return +s == &s;
143}
144
145bool checkThisStaticOp(const S &s) {
146  return -s == &s;
147}
148
149void testReferenceArgument() {
150  clang_analyzer_eval(getConstrainedFieldRef(getS()) == 42); // expected-warning{{TRUE}}
151  clang_analyzer_eval(checkThis(getS())); // expected-warning{{TRUE}}
152  clang_analyzer_eval(checkThisOp(getS())); // expected-warning{{TRUE}}
153  clang_analyzer_eval(checkThisStaticOp(getS())); // expected-warning{{TRUE}}
154}
155
156
157int getConstrainedFieldOp(S s) {
158  if (*s != 42) return 42;
159  return *s;
160}
161
162int getConstrainedFieldRefOp(const S &s) {
163  if (*s != 42) return 42;
164  return *s;
165}
166
167void testImmediateUseOp() {
168  int x = *getS();
169  if (x != 42) return;
170  clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
171
172  clang_analyzer_eval(getConstrainedFieldOp(getS()) == 42); // expected-warning{{TRUE}}
173  clang_analyzer_eval(getConstrainedFieldRefOp(getS()) == 42); // expected-warning{{TRUE}}
174}
175
176namespace EmptyClass {
177  struct Base {
178    int& x;
179
180    Base(int& x) : x(x) {}
181  };
182
183  struct Derived : public Base {
184    Derived(int& x) : Base(x) {}
185
186    void operator=(int a) { x = a; }
187  };
188
189  Derived ref(int& a) { return Derived(a); }
190
191  // There used to be a warning here, because analyzer treated Derived as empty.
192  int test() {
193    int a;
194    ref(a) = 42;
195    return a; // no warning
196  }
197}
198
199#endif
200