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
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
23 const struct S *operator -(const struct S &s) { return &s; }
24 bool operator ~(const struct S &s) { return &s != &s; }
25 #endif
26 
27 
28 #ifdef INLINE
29 struct S getS() {
30   struct S s = { 42 };
31   return s;
32 }
33 #else
34 struct S getS();
35 #endif
36 
37 
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 
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 
78 int getConstrainedField(struct S s) {
79   if (s.field != 42) return 42;
80   return s.field;
81 }
82 
83 int getAssignedField(struct S s) {
84   s.field = 42;
85   return s.field;
86 }
87 
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 
93 
94 //--------------------
95 // C++-only tests
96 //--------------------
97 
98 #if __cplusplus
99 void testReferenceAssignment() {
100   const S &s = getS();
101 
102   if (s.field != 42) return;
103   clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}}
104 
105   clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}}
106   clang_analyzer_eval(+s == &s); // expected-warning{{TRUE}}
107 
108   clang_analyzer_eval(s.check()); // expected-warning{{TRUE}}
109   clang_analyzer_eval(!s); // expected-warning{{FALSE}}
110   clang_analyzer_eval(~s); // expected-warning{{FALSE}}
111 
112   clang_analyzer_eval(*s == 42); // expected-warning{{TRUE}}
113 }
114 
115 
116 int getConstrainedFieldRef(const S &s) {
117   if (s.field != 42) return 42;
118   return s.field;
119 }
120 
121 bool checkThis(const S &s) {
122   return s.getThis() == &s;
123 }
124 
125 bool checkThisOp(const S &s) {
126   return +s == &s;
127 }
128 
129 bool checkThisStaticOp(const S &s) {
130   return -s == &s;
131 }
132 
133 void testReferenceArgument() {
134   clang_analyzer_eval(getConstrainedFieldRef(getS()) == 42); // expected-warning{{TRUE}}
135   clang_analyzer_eval(checkThis(getS())); // expected-warning{{TRUE}}
136   clang_analyzer_eval(checkThisOp(getS())); // expected-warning{{TRUE}}
137   clang_analyzer_eval(checkThisStaticOp(getS())); // expected-warning{{TRUE}}
138 }
139 
140 
141 int getConstrainedFieldOp(S s) {
142   if (*s != 42) return 42;
143   return *s;
144 }
145 
146 int getConstrainedFieldRefOp(const S &s) {
147   if (*s != 42) return 42;
148   return *s;
149 }
150 
151 void testImmediateUseOp() {
152   int x = *getS();
153   if (x != 42) return;
154   clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
155 
156   clang_analyzer_eval(getConstrainedFieldOp(getS()) == 42); // expected-warning{{TRUE}}
157   clang_analyzer_eval(getConstrainedFieldRefOp(getS()) == 42); // expected-warning{{TRUE}}
158 }
159 
160 #endif
161