21 #include "llvm/ADT/SmallString.h"
22 #include "llvm/Support/SaveAndRestore.h"
23 #include "llvm/Support/raw_ostream.h"
25 using namespace clang;
45 enum Kind { NotVisited,
54 llvm::DenseMap<const FunctionDecl *, Kind> VisitedFunctions;
64 :
Checker(checker), BR(br), AC(ac), visitingCallExpr(nullptr) {}
66 bool hasWork()
const {
return !WList.empty(); }
74 Kind &K = VisitedFunctions[FD];
78 WList.push_back(WLUnit);
83 assert(!WList.empty());
93 if (VisitedFunctions[FD] == PreVisited) {
101 VisitedFunctions[FD] = PostVisited;
107 assert(VisitedFunctions[FD] == PostVisited);
114 void VisitCXXMemberCallExpr(
CallExpr *CE);
115 void VisitStmt(
Stmt *
S) { VisitChildren(S); }
116 void VisitChildren(
Stmt *
S);
118 void ReportVirtualCall(
const CallExpr *CE,
bool isPure);
127 void WalkAST::VisitChildren(
Stmt *
S) {
128 for (
Stmt *Child : S->children())
133 void WalkAST::VisitCallExpr(
CallExpr *CE) {
138 void WalkAST::VisitCXXMemberCallExpr(
CallExpr *CE) {
140 bool callIsNonVirtual =
false;
146 if (CME->getQualifier())
147 callIsNonVirtual =
true;
151 if (!isa<CXXThisExpr>(base))
156 if (base->getBestDynamicClassType()->hasAttr<FinalAttr>())
157 callIsNonVirtual =
true;
163 if (MD && MD->
isVirtual() && !callIsNonVirtual && !MD->
hasAttr<FinalAttr>() &&
165 ReportVirtualCall(CE, MD->
isPure());
170 void WalkAST::ReportVirtualCall(
const CallExpr *CE,
bool isPure) {
172 llvm::raw_svector_ostream os(buf);
174 os <<
"Call Path : ";
179 if (visitingCallExpr)
180 os <<
" <-- " << *visitingCallExpr->getDirectCallee();
183 E = WList.begin(); I != E; --I) {
186 if (VisitedFunctions[FD] == PostVisited)
187 os <<
" <-- " << *FD;
195 os <<
"\n" <<
"Call pure virtual functions during construction or "
196 <<
"destruction may leads undefined behaviour";
197 BR.EmitBasicReport(AC->getDecl(),
Checker,
198 "Call pure virtual function during construction or "
200 "Cplusplus", os.str(), CELoc, R);
204 os <<
"\n" <<
"Call virtual functions during construction or "
205 <<
"destruction will never go to a more derived class";
206 BR.EmitBasicReport(AC->getDecl(),
Checker,
207 "Call virtual function during construction or "
209 "Cplusplus", os.str(), CELoc, R);
219 class VirtualCallChecker :
public Checker<check::ASTDecl<CXXRecordDecl> > {
226 for (
const auto *I : RD->
ctors()) {
227 if (!I->isCopyOrMoveConstructor())
228 if (
Stmt *Body = I->getBody()) {
236 if (
Stmt *Body = DD->getBody()) {
const Expr * getCallee() const
Expr * IgnoreImpCasts() LLVM_READONLY
const CXXRecordDecl * getParent() const
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
Represents a C++ destructor within a class.
Stmt * getBody(const FunctionDecl *&Definition) const
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
CHECKER * registerChecker()
Used to register checkers.
Represents a static or instance method of a struct/union/class.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return 0.
CXXDestructorDecl * getDestructor() const
Returns the destructor decl for this class.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
Represents a C++ struct/union/class.
A trivial tuple used to represent a source range.