inline.cpp revision b66529d04727dc686b97ea3d937fc9785792f505
1// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=inlining -verify %s
2
3void clang_analyzer_eval(bool);
4void clang_analyzer_checkInlined(bool);
5
6class A {
7public:
8  int getZero() { return 0; }
9  virtual int getNum() { return 0; }
10};
11
12void test(A &a) {
13  clang_analyzer_eval(a.getZero() == 0); // expected-warning{{TRUE}}
14  clang_analyzer_eval(a.getNum() == 0); // expected-warning{{UNKNOWN}}
15
16  A copy(a);
17  clang_analyzer_eval(copy.getZero() == 0); // expected-warning{{TRUE}}
18  clang_analyzer_eval(copy.getNum() == 0); // expected-warning{{TRUE}}
19}
20
21
22class One : public A {
23public:
24  virtual int getNum() { return 1; }
25};
26
27void testPathSensitivity(int x) {
28  A a;
29  One b;
30
31  A *ptr;
32  switch (x) {
33  case 0:
34    ptr = &a;
35    break;
36  case 1:
37    ptr = &b;
38    break;
39  default:
40    return;
41  }
42
43  // This should be true on both branches.
44  clang_analyzer_eval(ptr->getNum() == x); // expected-warning {{TRUE}}
45}
46
47
48namespace PureVirtualParent {
49  class Parent {
50  public:
51    virtual int pureVirtual() const = 0;
52    int callVirtual() const {
53      return pureVirtual();
54    }
55  };
56
57  class Child : public Parent {
58  public:
59    virtual int pureVirtual() const {
60      clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
61      return 42;
62    }
63  };
64
65  void testVirtual() {
66    Child x;
67
68    clang_analyzer_eval(x.pureVirtual() == 42); // expected-warning{{TRUE}}
69    clang_analyzer_eval(x.callVirtual() == 42); // expected-warning{{TRUE}}
70  }
71}
72
73
74namespace PR13569 {
75  class Parent {
76  protected:
77    int m_parent;
78    virtual int impl() const = 0;
79
80    Parent() : m_parent(0) {}
81
82  public:
83    int interface() const {
84      clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
85      return impl();
86    }
87  };
88
89  class Child : public Parent {
90  protected:
91    virtual int impl() const {
92      clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
93      return m_parent + m_child;
94    }
95
96  public:
97    Child() : m_child(0) {}
98
99    int m_child;
100  };
101
102  void testVirtual() {
103    Child x;
104    x.m_child = 42;
105
106    // Don't crash when inlining and devirtualizing.
107    x.interface();
108  }
109
110
111  class Grandchild : public Child {};
112
113  void testDevirtualizeToMiddle() {
114    Grandchild x;
115    x.m_child = 42;
116
117    // Don't crash when inlining and devirtualizing.
118    x.interface();
119  }
120}
121
122namespace PR13569_virtual {
123  class Parent {
124  protected:
125    int m_parent;
126    virtual int impl() const = 0;
127
128    Parent() : m_parent(0) {}
129
130  public:
131    int interface() const {
132      clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
133      return impl();
134    }
135  };
136
137  class Child : virtual public Parent {
138  protected:
139    virtual int impl() const {
140      clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
141      return m_parent + m_child;
142    }
143
144  public:
145    Child() : m_child(0) {}
146
147    int m_child;
148  };
149
150  void testVirtual() {
151    Child x;
152    x.m_child = 42;
153
154    // Don't crash when inlining and devirtualizing.
155    x.interface();
156  }
157
158
159  class Grandchild : virtual public Child {};
160
161  void testDevirtualizeToMiddle() {
162    Grandchild x;
163    x.m_child = 42;
164
165    // Don't crash when inlining and devirtualizing.
166    x.interface();
167  }
168}
169
170namespace Invalidation {
171  struct X {
172    void touch(int &x) const {
173      x = 0;
174    }
175
176    void touch2(int &x) const;
177
178    virtual void touchV(int &x) const {
179      x = 0;
180    }
181
182    virtual void touchV2(int &x) const;
183
184    int test() const {
185      // We were accidentally not invalidating under -analyzer-ipa=inlining
186      // at one point for virtual methods with visible definitions.
187      int a, b, c, d;
188      touch(a);
189      touch2(b);
190      touchV(c);
191      touchV2(d);
192      return a + b + c + d; // no-warning
193    }
194  };
195}
196
197namespace DefaultArgs {
198  int takesDefaultArgs(int i = 42) {
199    return -i;
200  }
201
202  void testFunction() {
203    clang_analyzer_eval(takesDefaultArgs(1) == -1); // expected-warning{{TRUE}}
204    clang_analyzer_eval(takesDefaultArgs() == -42); // expected-warning{{TRUE}}
205  }
206
207  class Secret {
208  public:
209    static const int value = 42;
210    int get(int i = value) {
211      return i;
212    }
213  };
214
215  void testMethod() {
216    Secret obj;
217    clang_analyzer_eval(obj.get(1) == 1); // expected-warning{{TRUE}}
218
219    // FIXME: Should be 'TRUE'. See PR13673 or <rdar://problem/11720796>.
220    clang_analyzer_eval(obj.get() == 42); // expected-warning{{UNKNOWN}}
221
222    // FIXME: Even if we constrain the variable, we still have a problem.
223    // See PR13385 or <rdar://problem/12156507>.
224    if (Secret::value != 42)
225      return;
226    clang_analyzer_eval(Secret::value == 42); // expected-warning{{TRUE}}
227    clang_analyzer_eval(obj.get() == 42); // expected-warning{{UNKNOWN}}
228  }
229}
230