Home | History | Annotate | Download | only in Analysis
      1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
      2 
      3 void clang_analyzer_eval(bool);
      4 
      5 struct A {
      6   int x;
      7   void foo() const;
      8   void bar();
      9 };
     10 
     11 struct B {
     12   mutable int mut;
     13   void foo() const;
     14 };
     15 
     16 struct C {
     17   int *p;
     18   void foo() const;
     19 };
     20 
     21 struct MutBase {
     22   mutable int b_mut;
     23 };
     24 
     25 struct MutDerived : MutBase {
     26   void foo() const;
     27 };
     28 
     29 struct PBase {
     30   int *p;
     31 };
     32 
     33 struct PDerived : PBase {
     34   void foo() const;
     35 };
     36 
     37 struct Inner {
     38   int x;
     39   int *p;
     40   void bar() const;
     41 };
     42 
     43 struct Outer {
     44   int x;
     45   Inner in;
     46   void foo() const;
     47 };
     48 
     49 void checkThatConstMethodWithoutDefinitionDoesNotInvalidateObject() {
     50   A t;
     51   t.x = 3;
     52   t.foo();
     53   clang_analyzer_eval(t.x == 3); // expected-warning{{TRUE}}
     54   // Test non-const does invalidate
     55   t.bar();
     56   clang_analyzer_eval(t.x); // expected-warning{{UNKNOWN}}
     57 }
     58 
     59 void checkThatConstMethodDoesInvalidateMutableFields() {
     60   B t;
     61   t.mut = 4;
     62   t.foo();
     63   clang_analyzer_eval(t.mut); // expected-warning{{UNKNOWN}}
     64 }
     65 
     66 void checkThatConstMethodDoesInvalidatePointedAtMemory() {
     67   int x = 1;
     68   C t;
     69   t.p = &x;
     70   t.foo();
     71   clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}
     72   clang_analyzer_eval(t.p == &x); // expected-warning{{TRUE}}
     73 }
     74 
     75 void checkThatConstMethodDoesInvalidateInheritedMutableFields() {
     76   MutDerived t;
     77   t.b_mut = 4;
     78   t.foo();
     79   clang_analyzer_eval(t.b_mut); // expected-warning{{UNKNOWN}}
     80 }
     81 
     82 void checkThatConstMethodDoesInvalidateInheritedPointedAtMemory() {
     83   int x = 1;
     84   PDerived t;
     85   t.p = &x;
     86   t.foo();
     87   clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}
     88   clang_analyzer_eval(t.p == &x); // expected-warning{{TRUE}}
     89 }
     90 
     91 void checkThatConstMethodDoesInvalidateContainedPointedAtMemory() {
     92   int x = 1;
     93   Outer t;
     94   t.x = 2;
     95   t.in.p = &x;
     96   t.foo();
     97   clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}
     98   clang_analyzer_eval(t.x == 2); // expected-warning{{TRUE}}
     99   clang_analyzer_eval(t.in.p == &x); // expected-warning{{TRUE}}
    100 }
    101 
    102 void checkThatContainedConstMethodDoesNotInvalidateObjects() {
    103   Outer t;
    104   t.x = 1;
    105   t.in.x = 2;
    106   t.in.bar();
    107   clang_analyzer_eval(t.x == 1); // expected-warning{{TRUE}}
    108   clang_analyzer_eval(t.in.x == 2); // expected-warning{{TRUE}}
    109 }
    110 
    111 // --- Versions of the above tests where the const method is inherited --- //
    112 
    113 struct B1 {
    114   void foo() const;
    115 };
    116 
    117 struct D1 : public B1 {
    118   int x;
    119 };
    120 
    121 struct D2 : public B1 {
    122   mutable int mut;
    123 };
    124 
    125 struct D3 : public B1 {
    126   int *p;
    127 };
    128 
    129 struct DInner : public B1 {
    130   int x;
    131   int *p;
    132 };
    133 
    134 struct DOuter : public B1 {
    135   int x;
    136   DInner in;
    137 };
    138 
    139 void checkThatInheritedConstMethodDoesNotInvalidateObject() {
    140   D1 t;
    141   t.x = 1;
    142   t.foo();
    143   clang_analyzer_eval(t.x == 1); // expected-warning{{TRUE}}
    144 }
    145 
    146 void checkThatInheritedConstMethodDoesInvalidateMutableFields() {
    147   D2 t;
    148   t.mut = 1;
    149   t.foo();
    150   clang_analyzer_eval(t.mut); // expected-warning{{UNKNOWN}}
    151 }
    152 
    153 void checkThatInheritedConstMethodDoesInvalidatePointedAtMemory() {
    154   int x = 1;
    155   D3 t;
    156   t.p = &x;
    157   t.foo();
    158   clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}
    159   clang_analyzer_eval(t.p == &x); // expected-warning{{TRUE}}
    160 }
    161 
    162 void checkThatInheritedConstMethodDoesInvalidateContainedPointedAtMemory() {
    163   int x = 1;
    164   DOuter t;
    165   t.x = 2;
    166   t.in.x = 3;
    167   t.in.p = &x;
    168   t.foo();
    169   clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}
    170   clang_analyzer_eval(t.x == 2); // expected-warning{{TRUE}}
    171   clang_analyzer_eval(t.in.x == 3); // expected-warning{{TRUE}}
    172   clang_analyzer_eval(t.in.p == &x); // expected-warning{{TRUE}}
    173 }
    174 
    175 void checkThatInheritedContainedConstMethodDoesNotInvalidateObjects() {
    176   DOuter t;
    177   t.x = 1;
    178   t.in.x = 2;
    179   t.in.foo();
    180   clang_analyzer_eval(t.x == 1); // expected-warning{{TRUE}}
    181   clang_analyzer_eval(t.in.x == 2); // expected-warning{{TRUE}}
    182 }
    183 
    184 // --- PR21606 --- //
    185 
    186 struct s1 {
    187     void g(const int *i) const;
    188 };
    189 
    190 struct s2 {
    191     void f(int *i) {
    192         m_i = i;
    193         m_s.g(m_i);
    194         if (m_i)
    195             *i = 42; // no-warning
    196     }
    197 
    198     int *m_i;
    199     s1 m_s;
    200 };
    201 
    202 void PR21606()
    203 {
    204     s2().f(0);
    205 }
    206 
    207 // --- PR25392 --- //
    208 
    209 struct HasConstMemberFunction {
    210 public:
    211   void constMemberFunction() const;
    212 };
    213 
    214 HasConstMemberFunction hasNoReturn() { } // expected-warning {{control reaches end of non-void function}}
    215 
    216 void testUnknownWithConstMemberFunction() {
    217   hasNoReturn().constMemberFunction();
    218 }
    219 
    220 void testNonRegionLocWithConstMemberFunction() {
    221   (*((HasConstMemberFunction *)(&&label))).constMemberFunction();
    222 
    223   label: return;
    224 }
    225 
    226 // FIXME
    227 // When there is a circular reference to an object and a const method is called
    228 // the object is not invalidated because TK_PreserveContents has already been
    229 // set.
    230 struct Outer2;
    231 
    232 struct InnerWithRef {
    233   Outer2 *ref;
    234 };
    235 
    236 struct Outer2 {
    237   int x;
    238   InnerWithRef in;
    239   void foo() const;
    240 };
    241 
    242 void checkThatConstMethodCallDoesInvalidateObjectForCircularReferences() {
    243   Outer2 t;
    244   t.x = 1;
    245   t.in.ref = &t;
    246   t.foo();
    247   // FIXME: Should be UNKNOWN.
    248   clang_analyzer_eval(t.x); // expected-warning{{TRUE}}
    249 }
    250