NoQ updated this revision to Diff 211399.
NoQ added a comment.
- Hmm, also i'd rather say "method" than "function".
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D65180/new/
https://reviews.llvm.org/D65180
Files:
clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
clang/test/Analysis/virtualcall.cpp
clang/test/Analysis/virtualcall.h
Index: clang/test/Analysis/virtualcall.h
===================================================================
--- clang/test/Analysis/virtualcall.h
+++ clang/test/Analysis/virtualcall.h
@@ -2,7 +2,7 @@
class Z {
public:
Z() {
- foo(); // impure-warning {{Call to virtual function during construction}}
+ foo(); // impure-warning {{Call to virtual method 'Z::foo' during construction}}
}
virtual int foo();
};
Index: clang/test/Analysis/virtualcall.cpp
===================================================================
--- clang/test/Analysis/virtualcall.cpp
+++ clang/test/Analysis/virtualcall.cpp
@@ -1,26 +1,33 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.cplusplus.VirtualCall \
+// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -std=c++11 -verify=expected,impure %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.PureVirtualCall \
+// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -std=c++11 -verify=expected -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=expected %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=expected,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=expected %s
#include "virtualcall.h"
+void clang_analyzer_warnIfReached();
+
class A {
public:
A();
@@ -30,31 +37,32 @@
virtual int foo() = 0;
virtual void bar() = 0;
void f() {
- foo(); // expected-warning{{Call to pure virtual function during construction}}
+ foo(); // expected-warning{{Call to pure virtual method 'A::foo' during construction}}
+ clang_analyzer_warnIfReached(); // no-warning
}
};
-class B : public A {
+A::A() {
+ f();
+}
+
+class B {
public:
B() {
- foo(); // impure-warning {{Call to virtual function during construction}}
+ foo(); // impure-warning {{Call to virtual method 'B::foo' during construction}}
}
~B();
virtual int foo();
virtual void bar() {
- foo(); // impure-warning{{Call to virtual function during destruction}}
+ foo(); // impure-warning {{Call to virtual method 'B::foo' during destruction}}
}
};
-A::A() {
- f();
-}
-
B::~B() {
this->B::foo(); // no-warning
this->B::bar();
- this->foo(); // impure-warning {{Call to virtual function during destruction}}
+ this->foo(); // impure-warning {{Call to virtual method 'B::foo' during destruction}}
}
class C : public B {
@@ -67,7 +75,7 @@
};
C::C() {
- f(foo()); // impure-warning {{Call to virtual function during construction}}
+ f(foo()); // impure-warning {{Call to virtual method 'C::foo' during construction}}
}
class D : public B {
@@ -121,23 +129,23 @@
G g;
g.foo();
g.bar(); // no warning
- f(); // impure-warning {{Call to virtual function during construction}}
+ f(); // impure-warning {{Call to virtual method 'H::f' during construction}}
H &h = *this;
- h.f(); // impure-warning {{Call to virtual function during construction}}
+ h.f(); // impure-warning {{Call to virtual method 'H::f' during construction}}
}
};
class X {
public:
X() {
- g(); // impure-warning {{Call to virtual function during construction}}
+ g(); // impure-warning {{Call to virtual method 'X::g' during construction}}
}
X(int i) {
if (i > 0) {
X x(i - 1);
x.g(); // no warning
}
- g(); // impure-warning {{Call to virtual function during construction}}
+ g(); // impure-warning {{Call to virtual method 'X::g' during construction}}
}
virtual void g();
};
@@ -158,7 +166,7 @@
virtual void foo();
};
void N::callFooOfM(M *m) {
- m->foo(); // impure-warning {{Call to virtual function during construction}}
+ m->foo(); // impure-warning {{Call to virtual method 'M::foo' during construction}}
}
class Y {
@@ -166,7 +174,7 @@
virtual void foobar();
void fooY() {
F f1;
- foobar(); // impure-warning {{Call to virtual function during construction}}
+ foobar(); // impure-warning {{Call to virtual method 'Y::foobar' during construction}}
}
Y() { fooY(); }
};
Index: clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines a checker that checks virtual function calls during
+// This file defines a checker that checks virtual method calls during
// construction or destruction of C++ objects.
//
//===----------------------------------------------------------------------===//
@@ -40,10 +40,12 @@
namespace {
class VirtualCallChecker
: public Checker<check::BeginFunction, check::EndFunction, check::PreCall> {
- mutable std::unique_ptr<BugType> BT;
+ BugType BT{this,
+ "Call to virtual method during construction or destruction",
+ "C++ Object Lifecycle"};
public:
- // The flag to determine if pure virtual functions should be issued only.
+ // The flag to determine if pure virtual methods should be issued only.
bool IsPureOnly = true;
void checkBeginFunction(CheckerContext &C) const;
@@ -53,15 +55,13 @@
private:
void registerCtorDtorCallInState(bool IsBeginFunction,
CheckerContext &C) const;
- void reportBug(StringRef Msg, bool PureError, const MemRegion *Reg,
- CheckerContext &C) const;
};
} // end namespace
// GDM (generic data map) to the memregion of this for the ctor and dtor.
REGISTER_MAP_WITH_PROGRAMSTATE(CtorDtorMap, const MemRegion *, ObjectState)
-// The function to check if a callexpr is a virtual function.
+// The function to check if a callexpr is a virtual method call.
static bool isVirtualCall(const CallExpr *CE) {
bool CallIsNonVirtual = false;
@@ -109,8 +109,10 @@
ProgramStateRef State = C.getState();
const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
- if (IsPureOnly && !MD->isPure())
+ bool IsPure = MD->isPure();
+ if (IsPureOnly && !IsPure)
return;
+
if (!isVirtualCall(CE))
return;
@@ -118,29 +120,28 @@
const ObjectState *ObState = State->get<CtorDtorMap>(Reg);
if (!ObState)
return;
- // Check if a virtual method is called.
- // The GDM of constructor and destructor should be true.
- if (*ObState == ObjectState::CtorCalled) {
- if (IsPureOnly && MD->isPure())
- reportBug("Call to pure virtual function during construction", true, Reg,
- C);
- else if (!MD->isPure())
- reportBug("Call to virtual function during construction", false, Reg, C);
- else
- reportBug("Call to pure virtual function during construction", false, Reg,
- C);
- }
- if (*ObState == ObjectState::DtorCalled) {
- if (IsPureOnly && MD->isPure())
- reportBug("Call to pure virtual function during destruction", true, Reg,
- C);
- else if (!MD->isPure())
- reportBug("Call to virtual function during destruction", false, Reg, C);
- else
- reportBug("Call to pure virtual function during construction", false, Reg,
- C);
- }
+ // At this point we're sure that we're calling a virtual method
+ // during construction or destruction, so we'll emit a report.
+ SmallString<128> Msg;
+ llvm::raw_svector_ostream OS(Msg);
+ OS << "Call to ";
+ if (IsPure)
+ OS << "pure ";
+ OS << "virtual method '" << MD->getParent()->getNameAsString()
+ << "::" << MD->getNameAsString() << "' during ";
+ if (*ObState == ObjectState::CtorCalled)
+ OS << "construction";
+ else
+ OS << "destruction";
+
+ ExplodedNode *N =
+ IsPure ? C.generateErrorNode() : C.generateNonFatalErrorNode();
+ if (!N)
+ return;
+
+ auto Report = llvm::make_unique<BugReport>(BT, OS.str(), N);
+ C.emitReport(std::move(Report));
}
void VirtualCallChecker::registerCtorDtorCallInState(bool IsBeginFunction,
@@ -182,26 +183,6 @@
}
}
-void VirtualCallChecker::reportBug(StringRef Msg, bool IsSink,
- const MemRegion *Reg,
- CheckerContext &C) const {
- ExplodedNode *N;
- if (IsSink)
- N = C.generateErrorNode();
- else
- N = C.generateNonFatalErrorNode();
-
- if (!N)
- return;
- if (!BT)
- BT.reset(new BugType(
- this, "Call to virtual function during construction or destruction",
- "C++ Object Lifecycle"));
-
- auto Reporter = llvm::make_unique<BugReport>(*BT, Msg, N);
- C.emitReport(std::move(Reporter));
-}
-
void ento::registerPureVirtualCallChecker(CheckerManager &Mgr) {
Mgr.registerChecker<VirtualCallChecker>();
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits