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 
6 void clang_analyzer_eval(int);
7 
8 struct S {
9   int field;
10 
11 #if __cplusplus
getThisS12   const struct S *getThis() const { return this; }
operator +S13   const struct S *operator +() const { return this; }
14 
checkS15   bool check() const { return this == this; }
operator !S16   bool operator !() const { return this != this; }
17 
operator *S18   int operator *() const { return field; }
19 #endif
20 };
21 
22 #if __cplusplus
operator -(const struct S & s)23 const struct S *operator -(const struct S &s) { return &s; }
operator ~(const struct S & s)24 bool operator ~(const struct S &s) { return (&s) != &s; }
25 #endif
26 
27 
28 #ifdef INLINE
getS()29 struct S getS() {
30   struct S s = { 42 };
31   return s;
32 }
33 #else
34 struct S getS();
35 #endif
36 
37 
testAssignment()38 void 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 
testImmediateUse()61 void 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 
getConstrainedField(struct S s)78 int getConstrainedField(struct S s) {
79   if (s.field != 42) return 42;
80   return s.field;
81 }
82 
getAssignedField(struct S s)83 int getAssignedField(struct S s) {
84   s.field = 42;
85   return s.field;
86 }
87 
testArgument()88 void testArgument() {
89   clang_analyzer_eval(getConstrainedField(getS()) == 42); // expected-warning{{TRUE}}
90   clang_analyzer_eval(getAssignedField(getS()) == 42); // expected-warning{{TRUE}}
91 }
92 
testImmediateUseParens()93 void 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
testReferenceAssignment()115 void 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 
getConstrainedFieldRef(const S & s)132 int getConstrainedFieldRef(const S &s) {
133   if (s.field != 42) return 42;
134   return s.field;
135 }
136 
checkThis(const S & s)137 bool checkThis(const S &s) {
138   return s.getThis() == &s;
139 }
140 
checkThisOp(const S & s)141 bool checkThisOp(const S &s) {
142   return +s == &s;
143 }
144 
checkThisStaticOp(const S & s)145 bool checkThisStaticOp(const S &s) {
146   return -s == &s;
147 }
148 
testReferenceArgument()149 void 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 
getConstrainedFieldOp(S s)157 int getConstrainedFieldOp(S s) {
158   if (*s != 42) return 42;
159   return *s;
160 }
161 
getConstrainedFieldRefOp(const S & s)162 int getConstrainedFieldRefOp(const S &s) {
163   if (*s != 42) return 42;
164   return *s;
165 }
166 
testImmediateUseOp()167 void 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 
176 namespace EmptyClass {
177   struct Base {
178     int& x;
179 
BaseEmptyClass::Base180     Base(int& x) : x(x) {}
181   };
182 
183   struct Derived : public Base {
DerivedEmptyClass::Derived184     Derived(int& x) : Base(x) {}
185 
operator =EmptyClass::Derived186     void operator=(int a) { x = a; }
187   };
188 
ref(int & a)189   Derived ref(int& a) { return Derived(a); }
190 
191   // There used to be a warning here, because analyzer treated Derived as empty.
test()192   int test() {
193     int a;
194     ref(a) = 42;
195     return a; // no warning
196   }
197 }
198 
199 #endif
200