200 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			200 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c %s
 | |
| // RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c++ -analyzer-config c++-inlining=constructors %s
 | |
| // RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c %s
 | |
| // RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c++ -analyzer-config c++-inlining=constructors %s
 | |
| 
 | |
| void clang_analyzer_eval(int);
 | |
| 
 | |
| struct S {
 | |
|   int field;
 | |
| 
 | |
| #if __cplusplus
 | |
|   const struct S *getThis() const { return this; }
 | |
|   const struct S *operator +() const { return this; }
 | |
| 
 | |
|   bool check() const { return this == this; }
 | |
|   bool operator !() const { return this != this; }
 | |
| 
 | |
|   int operator *() const { return field; }
 | |
| #endif
 | |
| };
 | |
| 
 | |
| #if __cplusplus
 | |
| const struct S *operator -(const struct S &s) { return &s; }
 | |
| bool operator ~(const struct S &s) { return (&s) != &s; }
 | |
| #endif
 | |
| 
 | |
| 
 | |
| #ifdef INLINE
 | |
| struct S getS() {
 | |
|   struct S s = { 42 };
 | |
|   return s;
 | |
| }
 | |
| #else
 | |
| struct S getS();
 | |
| #endif
 | |
| 
 | |
| 
 | |
| void testAssignment() {
 | |
|   struct S s = getS();
 | |
| 
 | |
|   if (s.field != 42) return;
 | |
|   clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}}
 | |
| 
 | |
|   s.field = 0;
 | |
|   clang_analyzer_eval(s.field == 0); // expected-warning{{TRUE}}
 | |
| 
 | |
| #if __cplusplus
 | |
|   clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}}
 | |
|   clang_analyzer_eval(+s == &s); // expected-warning{{TRUE}}
 | |
|   clang_analyzer_eval(-s == &s); // expected-warning{{TRUE}}
 | |
| 
 | |
|   clang_analyzer_eval(s.check()); // expected-warning{{TRUE}}
 | |
|   clang_analyzer_eval(!s); // expected-warning{{FALSE}}
 | |
|   clang_analyzer_eval(~s); // expected-warning{{FALSE}}
 | |
| 
 | |
|   clang_analyzer_eval(*s == 0); // expected-warning{{TRUE}}
 | |
| #endif
 | |
| }
 | |
| 
 | |
| 
 | |
| void testImmediateUse() {
 | |
|   int x = getS().field;
 | |
| 
 | |
|   if (x != 42) return;
 | |
|   clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
 | |
| 
 | |
| #if __cplusplus
 | |
|   clang_analyzer_eval((void *)getS().getThis() == (void *)&x); // expected-warning{{FALSE}}
 | |
|   clang_analyzer_eval((void *)+getS() == (void *)&x); // expected-warning{{FALSE}}
 | |
|   clang_analyzer_eval((void *)-getS() == (void *)&x); // expected-warning{{FALSE}}
 | |
| 
 | |
|   clang_analyzer_eval(getS().check()); // expected-warning{{TRUE}}
 | |
|   clang_analyzer_eval(!getS()); // expected-warning{{FALSE}}
 | |
|   clang_analyzer_eval(~getS()); // expected-warning{{FALSE}}
 | |
| #endif
 | |
| }
 | |
| 
 | |
| int getConstrainedField(struct S s) {
 | |
|   if (s.field != 42) return 42;
 | |
|   return s.field;
 | |
| }
 | |
| 
 | |
| int getAssignedField(struct S s) {
 | |
|   s.field = 42;
 | |
|   return s.field;
 | |
| }
 | |
| 
 | |
| void testArgument() {
 | |
|   clang_analyzer_eval(getConstrainedField(getS()) == 42); // expected-warning{{TRUE}}
 | |
|   clang_analyzer_eval(getAssignedField(getS()) == 42); // expected-warning{{TRUE}}
 | |
| }
 | |
| 
 | |
| void testImmediateUseParens() {
 | |
|   int x = ((getS())).field;
 | |
| 
 | |
|   if (x != 42) return;
 | |
|   clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
 | |
| 
 | |
|   clang_analyzer_eval(getConstrainedField(((getS()))) == 42); // expected-warning{{TRUE}}
 | |
|   clang_analyzer_eval(getAssignedField(((getS()))) == 42); // expected-warning{{TRUE}}
 | |
| 
 | |
| #if __cplusplus
 | |
|   clang_analyzer_eval(((getS())).check()); // expected-warning{{TRUE}}
 | |
|   clang_analyzer_eval(!((getS()))); // expected-warning{{FALSE}}
 | |
|   clang_analyzer_eval(~((getS()))); // expected-warning{{FALSE}}
 | |
| #endif
 | |
| }
 | |
| 
 | |
| 
 | |
| //--------------------
 | |
| // C++-only tests
 | |
| //--------------------
 | |
| 
 | |
| #if __cplusplus
 | |
| void testReferenceAssignment() {
 | |
|   const S &s = getS();
 | |
| 
 | |
|   if (s.field != 42) return;
 | |
|   clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}}
 | |
| 
 | |
|   clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}}
 | |
|   clang_analyzer_eval(+s == &s); // expected-warning{{TRUE}}
 | |
| 
 | |
|   clang_analyzer_eval(s.check()); // expected-warning{{TRUE}}
 | |
|   clang_analyzer_eval(!s); // expected-warning{{FALSE}}
 | |
|   clang_analyzer_eval(~s); // expected-warning{{FALSE}}
 | |
| 
 | |
|   clang_analyzer_eval(*s == 42); // expected-warning{{TRUE}}
 | |
| }
 | |
| 
 | |
| 
 | |
| int getConstrainedFieldRef(const S &s) {
 | |
|   if (s.field != 42) return 42;
 | |
|   return s.field;
 | |
| }
 | |
| 
 | |
| bool checkThis(const S &s) {
 | |
|   return s.getThis() == &s;
 | |
| }
 | |
| 
 | |
| bool checkThisOp(const S &s) {
 | |
|   return +s == &s;
 | |
| }
 | |
| 
 | |
| bool checkThisStaticOp(const S &s) {
 | |
|   return -s == &s;
 | |
| }
 | |
| 
 | |
| void testReferenceArgument() {
 | |
|   clang_analyzer_eval(getConstrainedFieldRef(getS()) == 42); // expected-warning{{TRUE}}
 | |
|   clang_analyzer_eval(checkThis(getS())); // expected-warning{{TRUE}}
 | |
|   clang_analyzer_eval(checkThisOp(getS())); // expected-warning{{TRUE}}
 | |
|   clang_analyzer_eval(checkThisStaticOp(getS())); // expected-warning{{TRUE}}
 | |
| }
 | |
| 
 | |
| 
 | |
| int getConstrainedFieldOp(S s) {
 | |
|   if (*s != 42) return 42;
 | |
|   return *s;
 | |
| }
 | |
| 
 | |
| int getConstrainedFieldRefOp(const S &s) {
 | |
|   if (*s != 42) return 42;
 | |
|   return *s;
 | |
| }
 | |
| 
 | |
| void testImmediateUseOp() {
 | |
|   int x = *getS();
 | |
|   if (x != 42) return;
 | |
|   clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
 | |
| 
 | |
|   clang_analyzer_eval(getConstrainedFieldOp(getS()) == 42); // expected-warning{{TRUE}}
 | |
|   clang_analyzer_eval(getConstrainedFieldRefOp(getS()) == 42); // expected-warning{{TRUE}}
 | |
| }
 | |
| 
 | |
| namespace EmptyClass {
 | |
|   struct Base {
 | |
|     int& x;
 | |
| 
 | |
|     Base(int& x) : x(x) {}
 | |
|   };
 | |
| 
 | |
|   struct Derived : public Base {
 | |
|     Derived(int& x) : Base(x) {}
 | |
| 
 | |
|     void operator=(int a) { x = a; }
 | |
|   };
 | |
| 
 | |
|   Derived ref(int& a) { return Derived(a); }
 | |
| 
 | |
|   // There used to be a warning here, because analyzer treated Derived as empty.
 | |
|   int test() {
 | |
|     int a;
 | |
|     ref(a) = 42;
 | |
|     return a; // no warning
 | |
|   }
 | |
| }
 | |
| 
 | |
| #endif
 | 
