aboutsummaryrefslogtreecommitdiffstats
path: root/test/Analysis/virtualcall.cpp
blob: 311f0a137c6f4ba4d3164a84a9325a524b3e031e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// RUN: %clang_cc1 -analyze -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -verify -std=c++11 %s
// RUN: %clang_cc1 -analyze -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-config optin.cplusplus.VirtualCall:Interprocedural=true -DINTERPROCEDURAL=1 -verify -std=c++11 %s
// RUN: %clang_cc1 -analyze -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-config optin.cplusplus.VirtualCall:PureOnly=true -DPUREONLY=1 -verify -std=c++11 %s

/* When INTERPROCEDURAL is set, we expect diagnostics in all functions reachable
   from a constructor or destructor. If it is not set, we expect diagnostics
   only in the constructor or destructor.

   When PUREONLY is set, we expect diagnostics only for calls to pure virtual
   functions not to non-pure virtual functions.
*/

class A {
public:
  A();
  A(int i);

  ~A() {};
  
  virtual int foo() = 0; // from Sema: expected-note {{'foo' declared here}}
  virtual void bar() = 0;
  void f() {
    foo();
#if INTERPROCEDURAL
        // expected-warning-re@-2 {{{{^}}Call Path : foo <-- fCall to pure virtual function during construction has undefined behavior}}
#endif
  }
};

class B : public A {
public:
  B() {
    foo();
#if !PUREONLY
#if INTERPROCEDURAL
        // expected-warning-re@-3 {{{{^}}Call Path : fooCall to virtual function during construction will not dispatch to derived class}}
#else
        // expected-warning-re@-5 {{{{^}}Call to virtual function during construction will not dispatch to derived class}}
#endif
#endif

  }
  ~B();
  
  virtual int foo();
  virtual void bar() { foo(); }
#if INTERPROCEDURAL
      // expected-warning-re@-2 {{{{^}}Call Path : foo <-- barCall to virtual function during destruction will not dispatch to derived class}}
#endif
};

A::A() {
  f();
}

A::A(int i) {
  foo(); // From Sema: expected-warning {{call to pure virtual member function 'foo' has undefined behavior}}
#if INTERPROCEDURAL
      // expected-warning-re@-2 {{{{^}}Call Path : fooCall to pure virtual function during construction has undefined behavior}}
#else
      // expected-warning-re@-4 {{{{^}}Call to pure virtual function during construction has undefined behavior}}
#endif
}

B::~B() {
  this->B::foo(); // no-warning
  this->B::bar();
  this->foo();
#if !PUREONLY
#if INTERPROCEDURAL
      // expected-warning-re@-3 {{{{^}}Call Path : fooCall to virtual function during destruction will not dispatch to derived class}}
#else
      // expected-warning-re@-5 {{{{^}}Call to virtual function during destruction will not dispatch to derived class}}
#endif
#endif

}

class C : public B {
public:
  C();
  ~C();
  
  virtual int foo();
  void f(int i);
};

C::C() {
  f(foo());
#if !PUREONLY
#if INTERPROCEDURAL
      // expected-warning-re@-3 {{{{^}}Call Path : fooCall to virtual function during construction will not dispatch to derived class}}
#else
      // expected-warning-re@-5 {{{{^}}Call to virtual function during construction will not dispatch to derived class}}
#endif
#endif
}

class D : public B {
public:
  D() {
    foo(); // no-warning
  }
  ~D() { bar(); }
  int foo() final;
  void bar() final { foo(); } // no-warning
};

class E final : public B {
public:
  E() {
    foo(); // no-warning
  }
  ~E() { bar(); }
  int foo() override;
};

// Regression test: don't crash when there's no direct callee.
class F {
public:
  F() {
    void (F::* ptr)() = &F::foo;
    (this->*ptr)();
  }
  void foo();
};

int main() {
  A *a;
  B *b;
  C *c;
  D *d;
  E *e;
  F *f;
}

#include "virtualcall.h"

#define AS_SYSTEM
#include "virtualcall.h"
#undef AS_SYSTEM