1 // RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -verify -std=c++11 %s
2 // RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-config optin.cplusplus.VirtualCall:Interprocedural=true -DINTERPROCEDURAL=1 -verify -std=c++11 %s
3 // RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-config optin.cplusplus.VirtualCall:PureOnly=true -DPUREONLY=1 -verify -std=c++11 %s
4 
5 /* When INTERPROCEDURAL is set, we expect diagnostics in all functions reachable
6    from a constructor or destructor. If it is not set, we expect diagnostics
7    only in the constructor or destructor.
8 
9    When PUREONLY is set, we expect diagnostics only for calls to pure virtual
10    functions not to non-pure virtual functions.
11 */
12 
13 class A {
14 public:
15   A();
16   A(int i);
17 
18   ~A() {};
19 
20   virtual int foo() = 0; // from Sema: expected-note {{'foo' declared here}}
21   virtual void bar() = 0;
22   void f() {
23     foo();
24 #if INTERPROCEDURAL
25         // expected-warning-re@-2 {{{{^}}Call Path : foo <-- fCall to pure virtual function during construction has undefined behavior}}
26 #endif
27   }
28 };
29 
30 class B : public A {
31 public:
32   B() {
33     foo();
34 #if !PUREONLY
35 #if INTERPROCEDURAL
36         // expected-warning-re@-3 {{{{^}}Call Path : fooCall to virtual function during construction will not dispatch to derived class}}
37 #else
38         // expected-warning-re@-5 {{{{^}}Call to virtual function during construction will not dispatch to derived class}}
39 #endif
40 #endif
41 
42   }
43   ~B();
44 
45   virtual int foo();
46   virtual void bar() { foo(); }
47 #if INTERPROCEDURAL
48       // expected-warning-re@-2 {{{{^}}Call Path : foo <-- barCall to virtual function during destruction will not dispatch to derived class}}
49 #endif
50 };
51 
52 A::A() {
53   f();
54 }
55 
56 A::A(int i) {
57   foo(); // From Sema: expected-warning {{call to pure virtual member function 'foo' has undefined behavior}}
58 #if INTERPROCEDURAL
59       // expected-warning-re@-2 {{{{^}}Call Path : fooCall to pure virtual function during construction has undefined behavior}}
60 #else
61       // expected-warning-re@-4 {{{{^}}Call to pure virtual function during construction has undefined behavior}}
62 #endif
63 }
64 
65 B::~B() {
66   this->B::foo(); // no-warning
67   this->B::bar();
68   this->foo();
69 #if !PUREONLY
70 #if INTERPROCEDURAL
71       // expected-warning-re@-3 {{{{^}}Call Path : fooCall to virtual function during destruction will not dispatch to derived class}}
72 #else
73       // expected-warning-re@-5 {{{{^}}Call to virtual function during destruction will not dispatch to derived class}}
74 #endif
75 #endif
76 
77 }
78 
79 class C : public B {
80 public:
81   C();
82   ~C();
83 
84   virtual int foo();
85   void f(int i);
86 };
87 
88 C::C() {
89   f(foo());
90 #if !PUREONLY
91 #if INTERPROCEDURAL
92       // expected-warning-re@-3 {{{{^}}Call Path : fooCall to virtual function during construction will not dispatch to derived class}}
93 #else
94       // expected-warning-re@-5 {{{{^}}Call to virtual function during construction will not dispatch to derived class}}
95 #endif
96 #endif
97 }
98 
99 class D : public B {
100 public:
101   D() {
102     foo(); // no-warning
103   }
104   ~D() { bar(); }
105   int foo() final;
106   void bar() final { foo(); } // no-warning
107 };
108 
109 class E final : public B {
110 public:
111   E() {
112     foo(); // no-warning
113   }
114   ~E() { bar(); }
115   int foo() override;
116 };
117 
118 // Regression test: don't crash when there's no direct callee.
119 class F {
120 public:
121   F() {
122     void (F::* ptr)() = &F::foo;
123     (this->*ptr)();
124   }
125   void foo();
126 };
127 
128 int main() {
129   A *a;
130   B *b;
131   C *c;
132   D *d;
133   E *e;
134   F *f;
135 }
136 
137 #include "virtualcall.h"
138 
139 #define AS_SYSTEM
140 #include "virtualcall.h"
141 #undef AS_SYSTEM
142