summaryrefslogtreecommitdiffstats
path: root/clang/test/Analysis/virtualcall.cpp
diff options
context:
space:
mode:
authorArtem Dergachev <artem.dergachev@gmail.com>2019-08-20 21:41:14 +0000
committerArtem Dergachev <artem.dergachev@gmail.com>2019-08-20 21:41:14 +0000
commitd3971fe97b64785c079d64bf4c8c3e2b5e1f85a1 (patch)
tree24db2ed70a09909a251b77ad61768165dfb750a4 /clang/test/Analysis/virtualcall.cpp
parent7fa6865392692e1446376e52f9c2b264d58b2294 (diff)
downloadbcm5719-llvm-d3971fe97b64785c079d64bf4c8c3e2b5e1f85a1.tar.gz
bcm5719-llvm-d3971fe97b64785c079d64bf4c8c3e2b5e1f85a1.zip
[analyzer] Improve VirtualCallChecker and enable parts of it by default.
Calling a pure virtual method during construction or destruction is undefined behavior. It's worth it to warn about it by default. That part is now known as the cplusplus.PureVirtualCall checker. Calling a normal virtual method during construction or destruction may be fine, but does behave unexpectedly, as it skips virtual dispatch. Do not warn about this by default, but let projects opt in into it by enabling the optin.cplusplus.VirtualCall checker manually. Give the two parts differentiated warning text: Before: Call to virtual function during construction or destruction: Call to pure virtual function during construction Call to virtual function during construction or destruction: Call to virtual function during destruction After: Pure virtual method call: Call to pure virtual method 'X::foo' during construction has undefined behavior Unexpected loss of virtual dispatch: Call to virtual method 'Y::bar' during construction bypasses virtual dispatch Also fix checker names in consumers that support them (eg., clang-tidy) because we now have different checker names for pure virtual calls and regular virtual calls. Also fix capitalization in the bug category. Differential Revision: https://reviews.llvm.org/D64274 llvm-svn: 369449
Diffstat (limited to 'clang/test/Analysis/virtualcall.cpp')
-rw-r--r--clang/test/Analysis/virtualcall.cpp176
1 files changed, 50 insertions, 126 deletions
diff --git a/clang/test/Analysis/virtualcall.cpp b/clang/test/Analysis/virtualcall.cpp
index 5847110c093..80f89d14ea9 100644
--- a/clang/test/Analysis/virtualcall.cpp
+++ b/clang/test/Analysis/virtualcall.cpp
@@ -1,9 +1,38 @@
-// 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=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
-// 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"
+void clang_analyzer_warnIfReached();
+
class A {
public:
A();
@@ -13,54 +42,32 @@ public:
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}}
+ foo(); // pure-warning{{Call to pure virtual method 'A::foo' during construction has undefined behavior}}
+ clang_analyzer_warnIfReached(); // no-warning
}
};
-class B : public A {
+A::A() {
+ f();
+}
+
+class B {
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() {
+ foo(); // impure-warning {{Call to virtual method 'B::foo' during construction bypasses virtual dispatch}}
}
~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
- }
+ foo(); // impure-warning {{Call to virtual method 'B::foo' during destruction bypasses virtual dispatch}}
+ }
};
-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
-
+ this->foo(); // impure-warning {{Call to virtual method 'B::foo' during destruction bypasses virtual dispatch}}
}
class C : public B {
@@ -73,12 +80,7 @@ public:
};
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
+ f(foo()); // impure-warning {{Call to virtual method 'C::foo' during construction bypasses virtual dispatch}}
}
class D : public B {
@@ -97,9 +99,6 @@ public:
foo(); // no-warning
}
~E() { bar(); }
-#if !PUREONLY
- // expected-note-re@-2 2{{{{^}}Calling '~B'}}
-#endif
int foo() override;
};
@@ -135,52 +134,23 @@ public:
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
+ f(); // impure-warning {{Call to virtual method 'H::f' during construction bypasses virtual dispatch}}
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
+ h.f(); // impure-warning {{Call to virtual method 'H::f' during construction bypasses virtual dispatch}}
}
};
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
+ g(); // impure-warning {{Call to virtual method 'X::g' during construction bypasses virtual dispatch}}
}
X(int i) {
if (i > 0) {
-#if !PUREONLY
- // expected-note-re@-2 {{{{^}}'i' is > 0}}
- // expected-note-re@-3 {{{{^}}Taking true branch}}
- // expected-note-re@-4 {{{{^}}'i' is <= 0}}
- // expected-note-re@-5 {{{{^}}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
+ g(); // impure-warning {{Call to virtual method 'X::g' during construction bypasses virtual dispatch}}
}
virtual void g();
};
@@ -197,19 +167,11 @@ public:
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
+ m->foo(); // impure-warning {{Call to virtual method 'M::foo' during construction bypasses virtual dispatch}}
}
class Y {
@@ -217,65 +179,27 @@ 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
+ foobar(); // impure-warning {{Call to virtual method 'Y::foobar' during construction bypasses virtual dispatch}}
}
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 {
OpenPOWER on IntegriCloud