19#include "llvm/ADT/DenseSet.h"
20#include "llvm/ADT/SetVector.h"
28class DerefFuncDeleteExprVisitor
31 bool VisitChildren(
const Stmt *S) {
32 for (
const Stmt *Child : S->children()) {
33 if (Child &&
Visit(Child))
39 bool VisitBody(
const Stmt *Body) {
43 auto [It, IsNew] = VisitedBody.insert(Body);
53 : ArgList(&ArgList), ClassDecl(ClassDecl) {}
56 : ClassDecl(ClassDecl) {}
60 return VisitBody(Body);
61 if (
Decl->getTemplateInstantiationPattern())
66 bool VisitCallExpr(
const CallExpr *CE) {
74 auto *Arg =
E->getArgument();
76 if (
auto *
Paren = dyn_cast<ParenExpr>(Arg))
77 Arg =
Paren->getSubExpr();
78 else if (
auto *Cast = dyn_cast<CastExpr>(Arg)) {
79 Arg =
Cast->getSubExpr();
81 if (
auto *PtrType = dyn_cast<PointerType>(
CastType)) {
82 auto PointeeType = PtrType->getPointeeType();
83 while (
auto *ET = dyn_cast<ElaboratedType>(PointeeType)) {
85 PointeeType = ET->desugar();
87 if (
auto *ParmType = dyn_cast<TemplateTypeParmType>(PointeeType)) {
89 auto ParmIndex = ParmType->getIndex();
90 auto Type = ArgList->get(ParmIndex).getAsType();
94 }
else if (
auto *RD = dyn_cast<RecordType>(PointeeType)) {
95 if (RD->getDecl() == ClassDecl)
98 dyn_cast<SubstTemplateTypeParmType>(PointeeType)) {
99 auto Type = ST->getReplacementType();
100 if (
auto *RD = dyn_cast<RecordType>(
Type)) {
101 if (RD->getDecl() == ClassDecl)
112 bool VisitStmt(
const Stmt *S) {
return VisitChildren(S); }
116 bool VisitLambdaExpr(
const LambdaExpr *) {
return false; }
121 llvm::DenseSet<const Stmt *> VisitedBody;
124class RefCntblBaseVirtualDtorChecker
125 :
public Checker<check::ASTDecl<TranslationUnitDecl>> {
131 RefCntblBaseVirtualDtorChecker()
133 "Reference-countable base class doesn't have virtual destructor",
134 "WebKit coding guidelines") {}
144 const RefCntblBaseVirtualDtorChecker *
Checker;
145 explicit LocalVisitor(
const RefCntblBaseVirtualDtorChecker *
Checker)
150 bool shouldVisitTemplateInstantiations()
const {
return true; }
151 bool shouldVisitImplicitCode()
const {
return false; }
160 const auto AccSpec =
Base.getAccessSpecifier();
173 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(
C)) {
174 for (
auto &Arg : CTSD->getTemplateArgs().asArray()) {
177 auto TemplT = Arg.getAsType();
181 bool IsCRTP = TemplT->getAsCXXRecordDecl() == RD;
192 llvm::SetVector<const CXXRecordDecl *> Decls;
193 llvm::DenseSet<const CXXRecordDecl *> CRTPs;
196 LocalVisitor visitor(
this);
198 for (
auto *RD : visitor.Decls) {
199 if (visitor.CRTPs.contains(RD))
201 visitCXXRecordDecl(RD);
206 if (shouldSkipDecl(RD))
210 const auto AccSpec =
Base.getAccessSpecifier();
218 bool hasRef = hasRefInBase && *hasRefInBase !=
nullptr;
219 bool hasDeref = hasDerefInBase && *hasDerefInBase !=
nullptr;
229 bool AnyInconclusiveBase =
false;
230 const auto hasPublicRefInBase =
234 AnyInconclusiveBase =
true;
237 return (*hasRefInBase) !=
nullptr;
239 const auto hasPublicDerefInBase =
242 if (!hasDerefInBase) {
243 AnyInconclusiveBase =
true;
246 return (*hasDerefInBase) !=
nullptr;
250 hasRef = hasRef ||
C->lookupInBases(hasPublicRefInBase, Paths,
252 hasDeref = hasDeref ||
C->lookupInBases(hasPublicDerefInBase, Paths,
254 if (AnyInconclusiveBase || !hasRef || !hasDeref)
257 auto HasSpecializedDelete = isClassWithSpecializedDelete(
C, RD);
258 if (!HasSpecializedDelete || *HasSpecializedDelete)
260 if (
C->lookupInBases(
262 auto *T = Base->getType().getTypePtrOrNull();
265 auto *R = T->getAsCXXRecordDecl();
268 auto Result = isClassWithSpecializedDelete(R, RD);
270 AnyInconclusiveBase = true;
271 return Result && *Result;
275 if (AnyInconclusiveBase)
278 const auto *Dtor =
C->getDestructor();
279 if (!Dtor || !Dtor->isVirtual()) {
280 auto *ProblematicBaseSpecifier = &
Base;
281 auto *ProblematicBaseClass =
C;
282 reportBug(RD, ProblematicBaseSpecifier, ProblematicBaseClass);
300 if (!RDLocation.isValid())
304 if (Kind != TagTypeKind::Struct && Kind != TagTypeKind::Class)
316 if (!
D->getTemplateInstantiationPattern())
318 auto *NsDecl =
D->getParent();
319 if (!NsDecl || !isa<NamespaceDecl>(NsDecl))
323 StringRef ClsName = ClsNameStr;
324 return NamespaceName ==
"WTF" &&
325 (ClsName.ends_with(
"RefCounted") ||
326 ClsName ==
"ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr");
329 static std::optional<bool>
332 if (
auto *ClsTmplSpDecl = dyn_cast<ClassTemplateSpecializationDecl>(
C)) {
333 for (
auto *MethodDecl :
C->methods()) {
335 DerefFuncDeleteExprVisitor Visitor(ClsTmplSpDecl->getTemplateArgs(),
337 auto Result = Visitor.HasSpecializedDelete(MethodDecl);
338 if (!Result || *Result)
344 for (
auto *MethodDecl :
C->methods()) {
346 DerefFuncDeleteExprVisitor Visitor(DerivedClass);
347 auto Result = Visitor.HasSpecializedDelete(MethodDecl);
348 if (!Result || *Result)
358 assert(DerivedClass);
360 assert(ProblematicBaseClass);
363 llvm::raw_svector_ostream Os(Buf);
365 Os << (ProblematicBaseClass->
isClass() ?
"Class" :
"Struct") <<
" ";
368 Os <<
" is used as a base of "
369 << (DerivedClass->
isClass() ?
"class" :
"struct") <<
" ";
372 Os <<
" but doesn't have virtual destructor";
376 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
383void ento::registerRefCntblBaseVirtualDtorChecker(
CheckerManager &Mgr) {
387bool ento::shouldRegisterRefCntblBaseVirtualDtorChecker(
Represents a path from a specific derived class (which is not represented as part of the path) to a p...
BasePaths - Represents the set of paths from a derived class to one of its (direct or indirect) bases...
Represents a base class of a C++ class.
SourceRange getSourceRange() const LLVM_READONLY
Retrieves the source range that contains the entire base specifier.
Represents a delete expression for memory deallocation and destructor calls, e.g.
Represents a static or instance method of a struct/union/class.
Represents a C++ struct/union/class.
bool isLambda() const
Determine whether this class describes a lambda function object.
bool hasDefinition() const
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
Decl - This represents one declaration (or definition), e.g.
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
SourceLocation getLocation() const
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
A (possibly-)qualified type.
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
SrcMgr::CharacteristicKind getFileCharacteristic(SourceLocation Loc) const
Return the file characteristic of the specified source location, indicating whether this is a normal ...
SourceLocation getBegin() const
RetTy Visit(PTR(Stmt) S, ParamTys... P)
Stmt - This represents one statement.
bool isThisDeclarationADefinition() const
Return true if this declaration is a completion definition of the type.
TagKind getTagKind() const
A template argument list.
@ Type
The template argument is a type.
The top declaration context.
The base class of the type hierarchy.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
BugReporter is a utility class for generating PathDiagnostics for analysis.
const SourceManager & getSourceManager()
virtual void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
bool Cast(InterpState &S, CodePtr OpPC)
The JSON file list parser is used to communicate input to InstallAPI.
std::optional< const clang::CXXRecordDecl * > hasPublicMethodInBase(const CXXBaseSpecifier *Base, const char *NameToMatch)
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
const FunctionProtoType * T
std::string safeGetName(const T *ASTNode)