llvm-project/clang/test/Analysis/virtualcall.cpp
Artem Dergachev a396df3472 [analyzer] Enable c++-allocator-inlining by default.
This allows the analyzer to analyze ("inline") custom operator new() calls and,
even more importantly, inline constructors of objects that were allocated
by any operator new() - not necessarily a custom one.

All changes in the tests in the current commit are intended improvements,
even if they didn't carry any explicit FIXME flag.

It is possible to restore the old behavior via

  -analyzer-config c++-allocator-inlining=false

(this flag is supported by scan-build as well, and it can be into a clang
--analyze invocation via -Xclang .. -Xclang ..). There is no intention to
remove the old behavior for now.

Differential Revision: https://reviews.llvm.org/D42219
rdar://problem/12180598

llvm-svn: 323373
2018-01-24 20:59:40 +00:00

298 lines
7.2 KiB
C++

// RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-output=text -verify -std=c++11 %s
// RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-config optin.cplusplus.VirtualCall:PureOnly=true -DPUREONLY=1 -analyzer-output=text -verify -std=c++11 %s
#include "virtualcall.h"
class A {
public:
A();
~A(){};
virtual int foo() = 0;
virtual void bar() = 0;
void f() {
foo();
// expected-warning-re@-1 {{{{^}}Call to pure virtual function during construction}}
// expected-note-re@-2 {{{{^}}Call to pure virtual function during construction}}
}
};
class B : public A {
public:
B() { // expected-note {{Calling default constructor for 'A'}}
foo();
#if !PUREONLY
// expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
// expected-note-re@-3 {{{{^}}This constructor of an object of type 'B' has not returned when the virtual method was called}}
// expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
#endif
}
~B();
virtual int foo();
virtual void bar() {
foo();
#if !PUREONLY
// expected-warning-re@-2 {{{{^}}Call to virtual function during destruction}}
// expected-note-re@-3 {{{{^}}Call to virtual function during destruction}}
#endif
}
};
A::A() {
f();
// expected-note-re@-1 {{{{^}}This constructor of an object of type 'A' has not returned when the virtual method was called}}
// expected-note-re@-2 {{{{^}}Calling 'A::f'}}
}
B::~B() {
this->B::foo(); // no-warning
this->B::bar();
#if !PUREONLY
// expected-note-re@-2 {{{{^}}This destructor of an object of type '~B' has not returned when the virtual method was called}}
// expected-note-re@-3 {{{{^}}Calling 'B::bar'}}
#endif
this->foo();
#if !PUREONLY
// expected-warning-re@-2 {{{{^}}Call to virtual function during destruction}}
// expected-note-re@-3 {{{{^}}This destructor of an object of type '~B' has not returned when the virtual method was called}}
// expected-note-re@-4 {{{{^}}Call to virtual function during destruction}}
#endif
}
class C : public B {
public:
C();
~C();
virtual int foo();
void f(int i);
};
C::C() {
f(foo());
#if !PUREONLY
// expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
// expected-note-re@-3 {{{{^}}This constructor of an object of type 'C' has not returned when the virtual method was called}}
// expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
#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(); }
#if !PUREONLY
// expected-note-re@-2 2{{{{^}}Calling '~B'}}
#endif
int foo() override;
};
class F {
public:
F() {
void (F::*ptr)() = &F::foo;
(this->*ptr)();
}
void foo();
};
class G {
public:
G() {}
virtual void bar();
void foo() {
bar(); // no warning
}
};
class H {
public:
H() : initState(0) { init(); }
int initState;
virtual void f() const;
void init() {
if (initState)
f(); // no warning
}
H(int i) {
G g;
g.foo();
g.bar(); // no warning
f();
#if !PUREONLY
// expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
// expected-note-re@-3 {{{{^}}This constructor of an object of type 'H' has not returned when the virtual method was called}}
// expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
#endif
H &h = *this;
h.f();
#if !PUREONLY
// expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
// expected-note-re@-3 {{{{^}}This constructor of an object of type 'H' has not returned when the virtual method was called}}
// expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
#endif
}
};
class X {
public:
X() {
g();
#if !PUREONLY
// expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
// expected-note-re@-3 {{{{^}}This constructor of an object of type 'X' has not returned when the virtual method was called}}
// expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
#endif
}
X(int i) {
if (i > 0) {
#if !PUREONLY
// expected-note-re@-2 {{{{^}}Taking true branch}}
// expected-note-re@-3 {{{{^}}Taking false branch}}
#endif
X x(i - 1);
#if !PUREONLY
// expected-note-re@-2 {{{{^}}Calling constructor for 'X'}}
#endif
x.g(); // no warning
}
g();
#if !PUREONLY
// expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
// expected-note-re@-3 {{{{^}}This constructor of an object of type 'X' has not returned when the virtual method was called}}
// expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
#endif
}
virtual void g();
};
class M;
class N {
public:
virtual void virtualMethod();
void callFooOfM(M *);
};
class M {
public:
M() {
N n;
n.virtualMethod(); // no warning
n.callFooOfM(this);
#if !PUREONLY
// expected-note-re@-2 {{{{^}}This constructor of an object of type 'M' has not returned when the virtual method was called}}
// expected-note-re@-3 {{{{^}}Calling 'N::callFooOfM'}}
#endif
}
virtual void foo();
};
void N::callFooOfM(M *m) {
m->foo();
#if !PUREONLY
// expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
// expected-note-re@-3 {{{{^}}Call to virtual function during construction}}
#endif
}
class Y {
public:
virtual void foobar();
void fooY() {
F f1;
foobar();
#if !PUREONLY
// expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
// expected-note-re@-3 {{{{^}}Call to virtual function during construction}}
#endif
}
Y() { fooY(); }
#if !PUREONLY
// expected-note-re@-2 {{{{^}}This constructor of an object of type 'Y' has not returned when the virtual method was called}}
// expected-note-re@-3 {{{{^}}Calling 'Y::fooY'}}
#endif
};
int main() {
B b;
#if PUREONLY
//expected-note-re@-2 {{{{^}}Calling default constructor for 'B'}}
#else
//expected-note-re@-4 2{{{{^}}Calling default constructor for 'B'}}
#endif
C c;
#if !PUREONLY
//expected-note-re@-2 {{{{^}}Calling default constructor for 'C'}}
#endif
D d;
E e;
F f;
G g;
H h;
H h1(1);
#if !PUREONLY
//expected-note-re@-2 {{{{^}}Calling constructor for 'H'}}
//expected-note-re@-3 {{{{^}}Calling constructor for 'H'}}
#endif
X x;
#if !PUREONLY
//expected-note-re@-2 {{{{^}}Calling default constructor for 'X'}}
#endif
X x1(1);
#if !PUREONLY
//expected-note-re@-2 {{{{^}}Calling constructor for 'X'}}
#endif
M m;
#if !PUREONLY
//expected-note-re@-2 {{{{^}}Calling default constructor for 'M'}}
#endif
Y *y = new Y;
#if !PUREONLY
//expected-note-re@-2 {{{{^}}Calling default constructor for 'Y'}}
#endif
delete y;
header::Z z;
#if !PUREONLY
// expected-note-re@-2 {{{{^}}Calling default constructor for 'Z'}}
#endif
}
#if !PUREONLY
//expected-note-re@-2 2{{{{^}}Calling '~E'}}
#endif
namespace PR34451 {
struct a {
void b() {
a c[1];
c->b();
}
};
class e {
public:
void b() const;
};
class c {
void m_fn2() const;
e d[];
};
void c::m_fn2() const { d->b(); }
}