Home | History | Annotate | Download | only in Analysis
      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 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
    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 
    132 int getConstrainedFieldRef(const S &s) {
    133   if (s.field != 42) return 42;
    134   return s.field;
    135 }
    136 
    137 bool checkThis(const S &s) {
    138   return s.getThis() == &s;
    139 }
    140 
    141 bool checkThisOp(const S &s) {
    142   return +s == &s;
    143 }
    144 
    145 bool checkThisStaticOp(const S &s) {
    146   return -s == &s;
    147 }
    148 
    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 
    157 int getConstrainedFieldOp(S s) {
    158   if (*s != 42) return 42;
    159   return *s;
    160 }
    161 
    162 int getConstrainedFieldRefOp(const S &s) {
    163   if (*s != 42) return 42;
    164   return *s;
    165 }
    166 
    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 
    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