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)23const struct S *operator -(const struct S &s) { return &s; } operator ~(const struct S & s)24bool operator ~(const struct S &s) { return (&s) != &s; } 25 #endif 26 27 28 #ifdef INLINE getS()29struct S getS() { 30 struct S s = { 42 }; 31 return s; 32 } 33 #else 34 struct S getS(); 35 #endif 36 37 testAssignment()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 testImmediateUse()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 getConstrainedField(struct S s)78int getConstrainedField(struct S s) { 79 if (s.field != 42) return 42; 80 return s.field; 81 } 82 getAssignedField(struct S s)83int getAssignedField(struct S s) { 84 s.field = 42; 85 return s.field; 86 } 87 testArgument()88void testArgument() { 89 clang_analyzer_eval(getConstrainedField(getS()) == 42); // expected-warning{{TRUE}} 90 clang_analyzer_eval(getAssignedField(getS()) == 42); // expected-warning{{TRUE}} 91 } 92 testImmediateUseParens()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 testReferenceAssignment()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 getConstrainedFieldRef(const S & s)132int getConstrainedFieldRef(const S &s) { 133 if (s.field != 42) return 42; 134 return s.field; 135 } 136 checkThis(const S & s)137bool checkThis(const S &s) { 138 return s.getThis() == &s; 139 } 140 checkThisOp(const S & s)141bool checkThisOp(const S &s) { 142 return +s == &s; 143 } 144 checkThisStaticOp(const S & s)145bool checkThisStaticOp(const S &s) { 146 return -s == &s; 147 } 148 testReferenceArgument()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 getConstrainedFieldOp(S s)157int getConstrainedFieldOp(S s) { 158 if (*s != 42) return 42; 159 return *s; 160 } 161 getConstrainedFieldRefOp(const S & s)162int getConstrainedFieldRefOp(const S &s) { 163 if (*s != 42) return 42; 164 return *s; 165 } 166 testImmediateUseOp()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 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