
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
298 lines
7.2 KiB
C++
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(); }
|
|
}
|