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) {
72 if (name ==
"ensureOnMainThread" || name ==
"ensureOnMainRunLoop") {
73 for (
unsigned i = 0; i < CE->
getNumArgs(); ++i) {
75 if (VisitLambdaArgument(Arg))
83 bool VisitLambdaArgument(
const Expr *
E) {
85 if (
auto *TempE = dyn_cast<CXXBindTemporaryExpr>(
E))
86 E = TempE->getSubExpr();
88 if (
auto *Ref = dyn_cast<DeclRefExpr>(
E)) {
89 if (
auto *VD = dyn_cast_or_null<VarDecl>(Ref->getDecl()))
90 return VisitLambdaArgument(VD->getInit());
93 if (
auto *Lambda = dyn_cast<LambdaExpr>(
E)) {
94 if (VisitBody(Lambda->getBody()))
97 if (
auto *ConstructE = dyn_cast<CXXConstructExpr>(
E)) {
98 for (
unsigned i = 0; i < ConstructE->getNumArgs(); ++i) {
99 if (VisitLambdaArgument(ConstructE->getArg(i)))
107 auto *Arg =
E->getArgument();
109 if (
auto *
Paren = dyn_cast<ParenExpr>(Arg))
110 Arg =
Paren->getSubExpr();
111 else if (
auto *Cast = dyn_cast<CastExpr>(Arg)) {
112 Arg =
Cast->getSubExpr();
114 if (
auto *PtrType = dyn_cast<PointerType>(
CastType)) {
115 auto PointeeType = PtrType->getPointeeType();
116 while (
auto *ET = dyn_cast<ElaboratedType>(PointeeType)) {
118 PointeeType = ET->desugar();
120 if (
auto *ParmType = dyn_cast<TemplateTypeParmType>(PointeeType)) {
122 auto ParmIndex = ParmType->getIndex();
123 auto Type = ArgList->get(ParmIndex).getAsType();
127 }
else if (
auto *RD = dyn_cast<RecordType>(PointeeType)) {
128 if (RD->getDecl() == ClassDecl)
130 }
else if (
auto *ST =
131 dyn_cast<SubstTemplateTypeParmType>(PointeeType)) {
132 auto Type = ST->getReplacementType();
133 if (
auto *RD = dyn_cast<RecordType>(
Type)) {
134 if (RD->getDecl() == ClassDecl)
145 bool VisitStmt(
const Stmt *S) {
return VisitChildren(S); }
149 bool VisitLambdaExpr(
const LambdaExpr *) {
return false; }
154 llvm::DenseSet<const Stmt *> VisitedBody;
157class RefCntblBaseVirtualDtorChecker
158 :
public Checker<check::ASTDecl<TranslationUnitDecl>> {
164 RefCntblBaseVirtualDtorChecker()
166 "Reference-countable base class doesn't have virtual destructor",
167 "WebKit coding guidelines") {}
177 const RefCntblBaseVirtualDtorChecker *
Checker;
178 explicit LocalVisitor(
const RefCntblBaseVirtualDtorChecker *
Checker)
181 ShouldVisitTemplateInstantiations =
true;
182 ShouldVisitImplicitCode =
false;
192 const auto AccSpec =
Base.getAccessSpecifier();
205 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(
C)) {
206 for (
auto &Arg : CTSD->getTemplateArgs().asArray()) {
209 auto TemplT = Arg.getAsType();
213 bool IsCRTP = TemplT->getAsCXXRecordDecl() == RD;
224 llvm::SetVector<const CXXRecordDecl *> Decls;
225 llvm::DenseSet<const CXXRecordDecl *> CRTPs;
228 LocalVisitor visitor(
this);
230 for (
auto *RD : visitor.Decls) {
231 if (visitor.CRTPs.contains(RD))
233 visitCXXRecordDecl(RD);
238 if (shouldSkipDecl(RD))
242 const auto AccSpec =
Base.getAccessSpecifier();
250 bool hasRef = hasRefInBase && *hasRefInBase !=
nullptr;
251 bool hasDeref = hasDerefInBase && *hasDerefInBase !=
nullptr;
261 bool AnyInconclusiveBase =
false;
262 const auto hasPublicRefInBase =
266 AnyInconclusiveBase =
true;
269 return (*hasRefInBase) !=
nullptr;
271 const auto hasPublicDerefInBase =
274 if (!hasDerefInBase) {
275 AnyInconclusiveBase =
true;
278 return (*hasDerefInBase) !=
nullptr;
282 hasRef = hasRef ||
C->lookupInBases(hasPublicRefInBase, Paths,
284 hasDeref = hasDeref ||
C->lookupInBases(hasPublicDerefInBase, Paths,
286 if (AnyInconclusiveBase || !hasRef || !hasDeref)
289 auto HasSpecializedDelete = isClassWithSpecializedDelete(
C, RD);
290 if (!HasSpecializedDelete || *HasSpecializedDelete)
292 if (
C->lookupInBases(
294 auto *T = Base->getType().getTypePtrOrNull();
297 auto *R = T->getAsCXXRecordDecl();
300 auto Result = isClassWithSpecializedDelete(R, RD);
302 AnyInconclusiveBase = true;
303 return Result && *Result;
307 if (AnyInconclusiveBase)
310 const auto *Dtor =
C->getDestructor();
311 if (!Dtor || !Dtor->isVirtual()) {
312 auto *ProblematicBaseSpecifier = &
Base;
313 auto *ProblematicBaseClass =
C;
314 reportBug(RD, ProblematicBaseSpecifier, ProblematicBaseClass);
332 if (!RDLocation.isValid())
336 if (Kind != TagTypeKind::Struct && Kind != TagTypeKind::Class)
348 if (!
D->getTemplateInstantiationPattern())
350 auto *NsDecl =
D->getParent();
351 if (!NsDecl || !isa<NamespaceDecl>(NsDecl))
355 StringRef ClsName = ClsNameStr;
356 return NamespaceName ==
"WTF" &&
357 (ClsName.ends_with(
"RefCounted") ||
358 ClsName ==
"ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr");
361 static std::optional<bool>
364 if (
auto *ClsTmplSpDecl = dyn_cast<ClassTemplateSpecializationDecl>(
C)) {
365 for (
auto *MethodDecl :
C->methods()) {
367 DerefFuncDeleteExprVisitor Visitor(ClsTmplSpDecl->getTemplateArgs(),
369 auto Result = Visitor.HasSpecializedDelete(MethodDecl);
370 if (!Result || *Result)
376 for (
auto *MethodDecl :
C->methods()) {
378 DerefFuncDeleteExprVisitor Visitor(DerivedClass);
379 auto Result = Visitor.HasSpecializedDelete(MethodDecl);
380 if (!Result || *Result)
390 assert(DerivedClass);
392 assert(ProblematicBaseClass);
395 llvm::raw_svector_ostream Os(Buf);
397 Os << (ProblematicBaseClass->
isClass() ?
"Class" :
"Struct") <<
" ";
400 Os <<
" is used as a base of "
401 << (DerivedClass->
isClass() ?
"class" :
"struct") <<
" ";
404 Os <<
" but doesn't have virtual destructor";
408 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
415void ento::registerRefCntblBaseVirtualDtorChecker(
CheckerManager &Mgr) {
419bool 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]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this 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
Recursive AST visitor that supports extension via dynamic dispatch.
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
A (possibly-)qualified type.
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.
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
std::optional< const clang::CXXRecordDecl * > hasPublicMethodInBase(const CXXBaseSpecifier *Base, StringRef NameToMatch)
const FunctionProtoType * T
std::string safeGetName(const T *ASTNode)