224 lines
4.6 KiB
C++
224 lines
4.6 KiB
C++
// RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.cplusplus.VirtualCall \
|
|
// RUN: -analyzer-checker=debug.ExprInspection \
|
|
// RUN: -std=c++11 -verify=impure %s
|
|
|
|
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.PureVirtualCall \
|
|
// RUN: -analyzer-checker=debug.ExprInspection \
|
|
// RUN: -std=c++11 -verify=pure -std=c++11 %s
|
|
|
|
// RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.cplusplus.VirtualCall \
|
|
// RUN: -analyzer-config \
|
|
// RUN: optin.cplusplus.VirtualCall:PureOnly=true \
|
|
// RUN: -analyzer-checker=debug.ExprInspection \
|
|
// RUN: -std=c++11 -verify=none %s
|
|
|
|
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.PureVirtualCall \
|
|
// RUN: -analyzer-checker=optin.cplusplus.VirtualCall \
|
|
// RUN: -analyzer-checker=debug.ExprInspection \
|
|
// RUN: -std=c++11 -verify=pure,impure -std=c++11 %s
|
|
|
|
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.PureVirtualCall \
|
|
// RUN: -analyzer-checker=optin.cplusplus.VirtualCall \
|
|
// RUN: -analyzer-config \
|
|
// RUN: optin.cplusplus.VirtualCall:PureOnly=true \
|
|
// RUN: -analyzer-checker=debug.ExprInspection \
|
|
// RUN: -std=c++11 -verify=pure %s
|
|
|
|
|
|
// We expect no diagnostics when all checks are disabled.
|
|
// none-no-diagnostics
|
|
|
|
|
|
#include "virtualcall.h"
|
|
|
|
void clang_analyzer_warnIfReached();
|
|
|
|
class A {
|
|
public:
|
|
A();
|
|
|
|
~A(){};
|
|
|
|
virtual int foo() = 0;
|
|
virtual void bar() = 0;
|
|
void f() {
|
|
foo(); // pure-warning{{Call to pure virtual method 'A::foo' during construction has undefined behavior}}
|
|
clang_analyzer_warnIfReached(); // no-warning
|
|
}
|
|
};
|
|
|
|
A::A() {
|
|
f();
|
|
}
|
|
|
|
class B {
|
|
public:
|
|
B() {
|
|
foo(); // impure-warning {{Call to virtual method 'B::foo' during construction bypasses virtual dispatch}}
|
|
}
|
|
~B();
|
|
|
|
virtual int foo();
|
|
virtual void bar() {
|
|
foo(); // impure-warning {{Call to virtual method 'B::foo' during destruction bypasses virtual dispatch}}
|
|
}
|
|
};
|
|
|
|
B::~B() {
|
|
this->B::foo(); // no-warning
|
|
this->B::bar();
|
|
this->foo(); // impure-warning {{Call to virtual method 'B::foo' during destruction bypasses virtual dispatch}}
|
|
}
|
|
|
|
class C : public B {
|
|
public:
|
|
C();
|
|
~C();
|
|
|
|
virtual int foo();
|
|
void f(int i);
|
|
};
|
|
|
|
C::C() {
|
|
f(foo()); // impure-warning {{Call to virtual method 'C::foo' during construction bypasses virtual dispatch}}
|
|
}
|
|
|
|
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;
|
|
};
|
|
|
|
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(); // impure-warning {{Call to virtual method 'H::f' during construction bypasses virtual dispatch}}
|
|
H &h = *this;
|
|
h.f(); // impure-warning {{Call to virtual method 'H::f' during construction bypasses virtual dispatch}}
|
|
}
|
|
};
|
|
|
|
class X {
|
|
public:
|
|
X() {
|
|
g(); // impure-warning {{Call to virtual method 'X::g' during construction bypasses virtual dispatch}}
|
|
}
|
|
X(int i) {
|
|
if (i > 0) {
|
|
X x(i - 1);
|
|
x.g(); // no warning
|
|
}
|
|
g(); // impure-warning {{Call to virtual method 'X::g' during construction bypasses virtual dispatch}}
|
|
}
|
|
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);
|
|
}
|
|
virtual void foo();
|
|
};
|
|
void N::callFooOfM(M *m) {
|
|
m->foo(); // impure-warning {{Call to virtual method 'M::foo' during construction bypasses virtual dispatch}}
|
|
}
|
|
|
|
class Y {
|
|
public:
|
|
virtual void foobar();
|
|
void fooY() {
|
|
F f1;
|
|
foobar(); // impure-warning {{Call to virtual method 'Y::foobar' during construction bypasses virtual dispatch}}
|
|
}
|
|
Y() { fooY(); }
|
|
};
|
|
|
|
int main() {
|
|
B b;
|
|
C c;
|
|
D d;
|
|
E e;
|
|
F f;
|
|
G g;
|
|
H h;
|
|
H h1(1);
|
|
X x;
|
|
X x1(1);
|
|
M m;
|
|
Y *y = new Y;
|
|
delete y;
|
|
header::Z z;
|
|
}
|
|
|
|
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(); }
|
|
}
|