15ffd83dbSDimitry Andric //=======- RefCntblBaseVirtualDtor.cpp ---------------------------*- C++ -*-==// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric 9*0fca6ea1SDimitry Andric #include "ASTUtils.h" 105ffd83dbSDimitry Andric #include "DiagOutputUtils.h" 115ffd83dbSDimitry Andric #include "PtrTypesSemantics.h" 125ffd83dbSDimitry Andric #include "clang/AST/CXXInheritance.h" 135ffd83dbSDimitry Andric #include "clang/AST/RecursiveASTVisitor.h" 14*0fca6ea1SDimitry Andric #include "clang/AST/StmtVisitor.h" 155ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 165ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 175ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 185ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 19*0fca6ea1SDimitry Andric #include "llvm/ADT/DenseSet.h" 20*0fca6ea1SDimitry Andric #include "llvm/ADT/SetVector.h" 21bdd1243dSDimitry Andric #include <optional> 225ffd83dbSDimitry Andric 235ffd83dbSDimitry Andric using namespace clang; 245ffd83dbSDimitry Andric using namespace ento; 255ffd83dbSDimitry Andric 265ffd83dbSDimitry Andric namespace { 27*0fca6ea1SDimitry Andric 28*0fca6ea1SDimitry Andric class DerefFuncDeleteExprVisitor 29*0fca6ea1SDimitry Andric : public ConstStmtVisitor<DerefFuncDeleteExprVisitor, bool> { 30*0fca6ea1SDimitry Andric // Returns true if any of child statements return true. 31*0fca6ea1SDimitry Andric bool VisitChildren(const Stmt *S) { 32*0fca6ea1SDimitry Andric for (const Stmt *Child : S->children()) { 33*0fca6ea1SDimitry Andric if (Child && Visit(Child)) 34*0fca6ea1SDimitry Andric return true; 35*0fca6ea1SDimitry Andric } 36*0fca6ea1SDimitry Andric return false; 37*0fca6ea1SDimitry Andric } 38*0fca6ea1SDimitry Andric 39*0fca6ea1SDimitry Andric bool VisitBody(const Stmt *Body) { 40*0fca6ea1SDimitry Andric if (!Body) 41*0fca6ea1SDimitry Andric return false; 42*0fca6ea1SDimitry Andric 43*0fca6ea1SDimitry Andric auto [It, IsNew] = VisitedBody.insert(Body); 44*0fca6ea1SDimitry Andric if (!IsNew) // This body is recursive 45*0fca6ea1SDimitry Andric return false; 46*0fca6ea1SDimitry Andric 47*0fca6ea1SDimitry Andric return Visit(Body); 48*0fca6ea1SDimitry Andric } 49*0fca6ea1SDimitry Andric 50*0fca6ea1SDimitry Andric public: 51*0fca6ea1SDimitry Andric DerefFuncDeleteExprVisitor(const TemplateArgumentList &ArgList, 52*0fca6ea1SDimitry Andric const CXXRecordDecl *ClassDecl) 53*0fca6ea1SDimitry Andric : ArgList(&ArgList), ClassDecl(ClassDecl) {} 54*0fca6ea1SDimitry Andric 55*0fca6ea1SDimitry Andric DerefFuncDeleteExprVisitor(const CXXRecordDecl *ClassDecl) 56*0fca6ea1SDimitry Andric : ClassDecl(ClassDecl) {} 57*0fca6ea1SDimitry Andric 58*0fca6ea1SDimitry Andric std::optional<bool> HasSpecializedDelete(CXXMethodDecl *Decl) { 59*0fca6ea1SDimitry Andric if (auto *Body = Decl->getBody()) 60*0fca6ea1SDimitry Andric return VisitBody(Body); 61*0fca6ea1SDimitry Andric if (Decl->getTemplateInstantiationPattern()) 62*0fca6ea1SDimitry Andric return std::nullopt; // Indeterminate. There was no concrete instance. 63*0fca6ea1SDimitry Andric return false; 64*0fca6ea1SDimitry Andric } 65*0fca6ea1SDimitry Andric 66*0fca6ea1SDimitry Andric bool VisitCallExpr(const CallExpr *CE) { 67*0fca6ea1SDimitry Andric const Decl *D = CE->getCalleeDecl(); 68*0fca6ea1SDimitry Andric if (D && D->hasBody()) 69*0fca6ea1SDimitry Andric return VisitBody(D->getBody()); 70*0fca6ea1SDimitry Andric return false; 71*0fca6ea1SDimitry Andric } 72*0fca6ea1SDimitry Andric 73*0fca6ea1SDimitry Andric bool VisitCXXDeleteExpr(const CXXDeleteExpr *E) { 74*0fca6ea1SDimitry Andric auto *Arg = E->getArgument(); 75*0fca6ea1SDimitry Andric while (Arg) { 76*0fca6ea1SDimitry Andric if (auto *Paren = dyn_cast<ParenExpr>(Arg)) 77*0fca6ea1SDimitry Andric Arg = Paren->getSubExpr(); 78*0fca6ea1SDimitry Andric else if (auto *Cast = dyn_cast<CastExpr>(Arg)) { 79*0fca6ea1SDimitry Andric Arg = Cast->getSubExpr(); 80*0fca6ea1SDimitry Andric auto CastType = Cast->getType(); 81*0fca6ea1SDimitry Andric if (auto *PtrType = dyn_cast<PointerType>(CastType)) { 82*0fca6ea1SDimitry Andric auto PointeeType = PtrType->getPointeeType(); 83*0fca6ea1SDimitry Andric while (auto *ET = dyn_cast<ElaboratedType>(PointeeType)) { 84*0fca6ea1SDimitry Andric if (ET->isSugared()) 85*0fca6ea1SDimitry Andric PointeeType = ET->desugar(); 86*0fca6ea1SDimitry Andric } 87*0fca6ea1SDimitry Andric if (auto *ParmType = dyn_cast<TemplateTypeParmType>(PointeeType)) { 88*0fca6ea1SDimitry Andric if (ArgList) { 89*0fca6ea1SDimitry Andric auto ParmIndex = ParmType->getIndex(); 90*0fca6ea1SDimitry Andric auto Type = ArgList->get(ParmIndex).getAsType(); 91*0fca6ea1SDimitry Andric if (Type->getAsCXXRecordDecl() == ClassDecl) 92*0fca6ea1SDimitry Andric return true; 93*0fca6ea1SDimitry Andric } 94*0fca6ea1SDimitry Andric } else if (auto *RD = dyn_cast<RecordType>(PointeeType)) { 95*0fca6ea1SDimitry Andric if (RD->getDecl() == ClassDecl) 96*0fca6ea1SDimitry Andric return true; 97*0fca6ea1SDimitry Andric } else if (auto *ST = 98*0fca6ea1SDimitry Andric dyn_cast<SubstTemplateTypeParmType>(PointeeType)) { 99*0fca6ea1SDimitry Andric auto Type = ST->getReplacementType(); 100*0fca6ea1SDimitry Andric if (auto *RD = dyn_cast<RecordType>(Type)) { 101*0fca6ea1SDimitry Andric if (RD->getDecl() == ClassDecl) 102*0fca6ea1SDimitry Andric return true; 103*0fca6ea1SDimitry Andric } 104*0fca6ea1SDimitry Andric } 105*0fca6ea1SDimitry Andric } 106*0fca6ea1SDimitry Andric } else 107*0fca6ea1SDimitry Andric break; 108*0fca6ea1SDimitry Andric } 109*0fca6ea1SDimitry Andric return false; 110*0fca6ea1SDimitry Andric } 111*0fca6ea1SDimitry Andric 112*0fca6ea1SDimitry Andric bool VisitStmt(const Stmt *S) { return VisitChildren(S); } 113*0fca6ea1SDimitry Andric 114*0fca6ea1SDimitry Andric // Return false since the contents of lambda isn't necessarily executed. 115*0fca6ea1SDimitry Andric // If it is executed, VisitCallExpr above will visit its body. 116*0fca6ea1SDimitry Andric bool VisitLambdaExpr(const LambdaExpr *) { return false; } 117*0fca6ea1SDimitry Andric 118*0fca6ea1SDimitry Andric private: 119*0fca6ea1SDimitry Andric const TemplateArgumentList *ArgList{nullptr}; 120*0fca6ea1SDimitry Andric const CXXRecordDecl *ClassDecl; 121*0fca6ea1SDimitry Andric llvm::DenseSet<const Stmt *> VisitedBody; 122*0fca6ea1SDimitry Andric }; 123*0fca6ea1SDimitry Andric 1245ffd83dbSDimitry Andric class RefCntblBaseVirtualDtorChecker 1255ffd83dbSDimitry Andric : public Checker<check::ASTDecl<TranslationUnitDecl>> { 1265ffd83dbSDimitry Andric private: 1275ffd83dbSDimitry Andric BugType Bug; 1285ffd83dbSDimitry Andric mutable BugReporter *BR; 1295ffd83dbSDimitry Andric 1305ffd83dbSDimitry Andric public: 1315ffd83dbSDimitry Andric RefCntblBaseVirtualDtorChecker() 1325ffd83dbSDimitry Andric : Bug(this, 1335ffd83dbSDimitry Andric "Reference-countable base class doesn't have virtual destructor", 1345ffd83dbSDimitry Andric "WebKit coding guidelines") {} 1355ffd83dbSDimitry Andric 1365ffd83dbSDimitry Andric void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR, 1375ffd83dbSDimitry Andric BugReporter &BRArg) const { 1385ffd83dbSDimitry Andric BR = &BRArg; 1395ffd83dbSDimitry Andric 1405ffd83dbSDimitry Andric // The calls to checkAST* from AnalysisConsumer don't 1415ffd83dbSDimitry Andric // visit template instantiations or lambda classes. We 1425ffd83dbSDimitry Andric // want to visit those, so we make our own RecursiveASTVisitor. 1435ffd83dbSDimitry Andric struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> { 1445ffd83dbSDimitry Andric const RefCntblBaseVirtualDtorChecker *Checker; 1455ffd83dbSDimitry Andric explicit LocalVisitor(const RefCntblBaseVirtualDtorChecker *Checker) 1465ffd83dbSDimitry Andric : Checker(Checker) { 1475ffd83dbSDimitry Andric assert(Checker); 1485ffd83dbSDimitry Andric } 1495ffd83dbSDimitry Andric 1505ffd83dbSDimitry Andric bool shouldVisitTemplateInstantiations() const { return true; } 1515ffd83dbSDimitry Andric bool shouldVisitImplicitCode() const { return false; } 1525ffd83dbSDimitry Andric 1535ffd83dbSDimitry Andric bool VisitCXXRecordDecl(const CXXRecordDecl *RD) { 154*0fca6ea1SDimitry Andric if (!RD->hasDefinition()) 155*0fca6ea1SDimitry Andric return true; 156*0fca6ea1SDimitry Andric 157*0fca6ea1SDimitry Andric Decls.insert(RD); 158*0fca6ea1SDimitry Andric 159*0fca6ea1SDimitry Andric for (auto &Base : RD->bases()) { 160*0fca6ea1SDimitry Andric const auto AccSpec = Base.getAccessSpecifier(); 161*0fca6ea1SDimitry Andric if (AccSpec == AS_protected || AccSpec == AS_private || 162*0fca6ea1SDimitry Andric (AccSpec == AS_none && RD->isClass())) 163*0fca6ea1SDimitry Andric continue; 164*0fca6ea1SDimitry Andric 165*0fca6ea1SDimitry Andric QualType T = Base.getType(); 166*0fca6ea1SDimitry Andric if (T.isNull()) 167*0fca6ea1SDimitry Andric continue; 168*0fca6ea1SDimitry Andric 169*0fca6ea1SDimitry Andric const CXXRecordDecl *C = T->getAsCXXRecordDecl(); 170*0fca6ea1SDimitry Andric if (!C) 171*0fca6ea1SDimitry Andric continue; 172*0fca6ea1SDimitry Andric 173*0fca6ea1SDimitry Andric if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(C)) { 174*0fca6ea1SDimitry Andric for (auto &Arg : CTSD->getTemplateArgs().asArray()) { 175*0fca6ea1SDimitry Andric if (Arg.getKind() != TemplateArgument::Type) 176*0fca6ea1SDimitry Andric continue; 177*0fca6ea1SDimitry Andric auto TemplT = Arg.getAsType(); 178*0fca6ea1SDimitry Andric if (TemplT.isNull()) 179*0fca6ea1SDimitry Andric continue; 180*0fca6ea1SDimitry Andric 181*0fca6ea1SDimitry Andric bool IsCRTP = TemplT->getAsCXXRecordDecl() == RD; 182*0fca6ea1SDimitry Andric if (!IsCRTP) 183*0fca6ea1SDimitry Andric continue; 184*0fca6ea1SDimitry Andric CRTPs.insert(C); 185*0fca6ea1SDimitry Andric } 186*0fca6ea1SDimitry Andric } 187*0fca6ea1SDimitry Andric } 188*0fca6ea1SDimitry Andric 1895ffd83dbSDimitry Andric return true; 1905ffd83dbSDimitry Andric } 191*0fca6ea1SDimitry Andric 192*0fca6ea1SDimitry Andric llvm::SetVector<const CXXRecordDecl *> Decls; 193*0fca6ea1SDimitry Andric llvm::DenseSet<const CXXRecordDecl *> CRTPs; 1945ffd83dbSDimitry Andric }; 1955ffd83dbSDimitry Andric 1965ffd83dbSDimitry Andric LocalVisitor visitor(this); 1975ffd83dbSDimitry Andric visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD)); 198*0fca6ea1SDimitry Andric for (auto *RD : visitor.Decls) { 199*0fca6ea1SDimitry Andric if (visitor.CRTPs.contains(RD)) 200*0fca6ea1SDimitry Andric continue; 201*0fca6ea1SDimitry Andric visitCXXRecordDecl(RD); 202*0fca6ea1SDimitry Andric } 2035ffd83dbSDimitry Andric } 2045ffd83dbSDimitry Andric 2055ffd83dbSDimitry Andric void visitCXXRecordDecl(const CXXRecordDecl *RD) const { 2065ffd83dbSDimitry Andric if (shouldSkipDecl(RD)) 2075ffd83dbSDimitry Andric return; 2085ffd83dbSDimitry Andric 209*0fca6ea1SDimitry Andric for (auto &Base : RD->bases()) { 210*0fca6ea1SDimitry Andric const auto AccSpec = Base.getAccessSpecifier(); 2115ffd83dbSDimitry Andric if (AccSpec == AS_protected || AccSpec == AS_private || 2125ffd83dbSDimitry Andric (AccSpec == AS_none && RD->isClass())) 213*0fca6ea1SDimitry Andric continue; 2145ffd83dbSDimitry Andric 215*0fca6ea1SDimitry Andric auto hasRefInBase = clang::hasPublicMethodInBase(&Base, "ref"); 216*0fca6ea1SDimitry Andric auto hasDerefInBase = clang::hasPublicMethodInBase(&Base, "deref"); 2175f757f3fSDimitry Andric 2185f757f3fSDimitry Andric bool hasRef = hasRefInBase && *hasRefInBase != nullptr; 2195f757f3fSDimitry Andric bool hasDeref = hasDerefInBase && *hasDerefInBase != nullptr; 2205f757f3fSDimitry Andric 221*0fca6ea1SDimitry Andric QualType T = Base.getType(); 2225f757f3fSDimitry Andric if (T.isNull()) 223*0fca6ea1SDimitry Andric continue; 2245ffd83dbSDimitry Andric 2255f757f3fSDimitry Andric const CXXRecordDecl *C = T->getAsCXXRecordDecl(); 2265f757f3fSDimitry Andric if (!C) 227*0fca6ea1SDimitry Andric continue; 228*0fca6ea1SDimitry Andric 2295f757f3fSDimitry Andric bool AnyInconclusiveBase = false; 2305f757f3fSDimitry Andric const auto hasPublicRefInBase = 231*0fca6ea1SDimitry Andric [&AnyInconclusiveBase](const CXXBaseSpecifier *Base, CXXBasePath &) { 2325f757f3fSDimitry Andric auto hasRefInBase = clang::hasPublicMethodInBase(Base, "ref"); 2335f757f3fSDimitry Andric if (!hasRefInBase) { 2345f757f3fSDimitry Andric AnyInconclusiveBase = true; 2355f757f3fSDimitry Andric return false; 2365f757f3fSDimitry Andric } 2375f757f3fSDimitry Andric return (*hasRefInBase) != nullptr; 2385f757f3fSDimitry Andric }; 239*0fca6ea1SDimitry Andric const auto hasPublicDerefInBase = 240*0fca6ea1SDimitry Andric [&AnyInconclusiveBase](const CXXBaseSpecifier *Base, CXXBasePath &) { 2415f757f3fSDimitry Andric auto hasDerefInBase = clang::hasPublicMethodInBase(Base, "deref"); 2425f757f3fSDimitry Andric if (!hasDerefInBase) { 2435f757f3fSDimitry Andric AnyInconclusiveBase = true; 2445f757f3fSDimitry Andric return false; 2455f757f3fSDimitry Andric } 2465f757f3fSDimitry Andric return (*hasDerefInBase) != nullptr; 2475f757f3fSDimitry Andric }; 2485f757f3fSDimitry Andric CXXBasePaths Paths; 2495f757f3fSDimitry Andric Paths.setOrigin(C); 2505f757f3fSDimitry Andric hasRef = hasRef || C->lookupInBases(hasPublicRefInBase, Paths, 2515f757f3fSDimitry Andric /*LookupInDependent =*/true); 2525f757f3fSDimitry Andric hasDeref = hasDeref || C->lookupInBases(hasPublicDerefInBase, Paths, 2535f757f3fSDimitry Andric /*LookupInDependent =*/true); 2545f757f3fSDimitry Andric if (AnyInconclusiveBase || !hasRef || !hasDeref) 255*0fca6ea1SDimitry Andric continue; 256*0fca6ea1SDimitry Andric 257*0fca6ea1SDimitry Andric auto HasSpecializedDelete = isClassWithSpecializedDelete(C, RD); 258*0fca6ea1SDimitry Andric if (!HasSpecializedDelete || *HasSpecializedDelete) 259*0fca6ea1SDimitry Andric continue; 260*0fca6ea1SDimitry Andric if (C->lookupInBases( 261*0fca6ea1SDimitry Andric [&](const CXXBaseSpecifier *Base, CXXBasePath &) { 262*0fca6ea1SDimitry Andric auto *T = Base->getType().getTypePtrOrNull(); 263*0fca6ea1SDimitry Andric if (!T) 2645f757f3fSDimitry Andric return false; 265*0fca6ea1SDimitry Andric auto *R = T->getAsCXXRecordDecl(); 266*0fca6ea1SDimitry Andric if (!R) 267*0fca6ea1SDimitry Andric return false; 268*0fca6ea1SDimitry Andric auto Result = isClassWithSpecializedDelete(R, RD); 269*0fca6ea1SDimitry Andric if (!Result) 270*0fca6ea1SDimitry Andric AnyInconclusiveBase = true; 271*0fca6ea1SDimitry Andric return Result && *Result; 272*0fca6ea1SDimitry Andric }, 273*0fca6ea1SDimitry Andric Paths, /*LookupInDependent =*/true)) 274*0fca6ea1SDimitry Andric continue; 275*0fca6ea1SDimitry Andric if (AnyInconclusiveBase) 276*0fca6ea1SDimitry Andric continue; 2775f757f3fSDimitry Andric 2785f757f3fSDimitry Andric const auto *Dtor = C->getDestructor(); 2795ffd83dbSDimitry Andric if (!Dtor || !Dtor->isVirtual()) { 280*0fca6ea1SDimitry Andric auto *ProblematicBaseSpecifier = &Base; 281*0fca6ea1SDimitry Andric auto *ProblematicBaseClass = C; 2825ffd83dbSDimitry Andric reportBug(RD, ProblematicBaseSpecifier, ProblematicBaseClass); 2835ffd83dbSDimitry Andric } 2845ffd83dbSDimitry Andric } 285*0fca6ea1SDimitry Andric } 2865ffd83dbSDimitry Andric 2875ffd83dbSDimitry Andric bool shouldSkipDecl(const CXXRecordDecl *RD) const { 2885ffd83dbSDimitry Andric if (!RD->isThisDeclarationADefinition()) 2895ffd83dbSDimitry Andric return true; 2905ffd83dbSDimitry Andric 2915ffd83dbSDimitry Andric if (RD->isImplicit()) 2925ffd83dbSDimitry Andric return true; 2935ffd83dbSDimitry Andric 2945ffd83dbSDimitry Andric if (RD->isLambda()) 2955ffd83dbSDimitry Andric return true; 2965ffd83dbSDimitry Andric 2975ffd83dbSDimitry Andric // If the construct doesn't have a source file, then it's not something 2985ffd83dbSDimitry Andric // we want to diagnose. 2995ffd83dbSDimitry Andric const auto RDLocation = RD->getLocation(); 3005ffd83dbSDimitry Andric if (!RDLocation.isValid()) 3015ffd83dbSDimitry Andric return true; 3025ffd83dbSDimitry Andric 3035ffd83dbSDimitry Andric const auto Kind = RD->getTagKind(); 3045f757f3fSDimitry Andric if (Kind != TagTypeKind::Struct && Kind != TagTypeKind::Class) 3055ffd83dbSDimitry Andric return true; 3065ffd83dbSDimitry Andric 3075ffd83dbSDimitry Andric // Ignore CXXRecords that come from system headers. 3085ffd83dbSDimitry Andric if (BR->getSourceManager().getFileCharacteristic(RDLocation) != 3095ffd83dbSDimitry Andric SrcMgr::C_User) 3105ffd83dbSDimitry Andric return true; 3115ffd83dbSDimitry Andric 3125ffd83dbSDimitry Andric return false; 3135ffd83dbSDimitry Andric } 3145ffd83dbSDimitry Andric 315*0fca6ea1SDimitry Andric static bool isRefCountedClass(const CXXRecordDecl *D) { 316*0fca6ea1SDimitry Andric if (!D->getTemplateInstantiationPattern()) 317*0fca6ea1SDimitry Andric return false; 318*0fca6ea1SDimitry Andric auto *NsDecl = D->getParent(); 319*0fca6ea1SDimitry Andric if (!NsDecl || !isa<NamespaceDecl>(NsDecl)) 320*0fca6ea1SDimitry Andric return false; 321*0fca6ea1SDimitry Andric auto NamespaceName = safeGetName(NsDecl); 322*0fca6ea1SDimitry Andric auto ClsNameStr = safeGetName(D); 323*0fca6ea1SDimitry Andric StringRef ClsName = ClsNameStr; // FIXME: Make safeGetName return StringRef. 324*0fca6ea1SDimitry Andric return NamespaceName == "WTF" && 325*0fca6ea1SDimitry Andric (ClsName.ends_with("RefCounted") || 326*0fca6ea1SDimitry Andric ClsName == "ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr"); 327*0fca6ea1SDimitry Andric } 328*0fca6ea1SDimitry Andric 329*0fca6ea1SDimitry Andric static std::optional<bool> 330*0fca6ea1SDimitry Andric isClassWithSpecializedDelete(const CXXRecordDecl *C, 331*0fca6ea1SDimitry Andric const CXXRecordDecl *DerivedClass) { 332*0fca6ea1SDimitry Andric if (auto *ClsTmplSpDecl = dyn_cast<ClassTemplateSpecializationDecl>(C)) { 333*0fca6ea1SDimitry Andric for (auto *MethodDecl : C->methods()) { 334*0fca6ea1SDimitry Andric if (safeGetName(MethodDecl) == "deref") { 335*0fca6ea1SDimitry Andric DerefFuncDeleteExprVisitor Visitor(ClsTmplSpDecl->getTemplateArgs(), 336*0fca6ea1SDimitry Andric DerivedClass); 337*0fca6ea1SDimitry Andric auto Result = Visitor.HasSpecializedDelete(MethodDecl); 338*0fca6ea1SDimitry Andric if (!Result || *Result) 339*0fca6ea1SDimitry Andric return Result; 340*0fca6ea1SDimitry Andric } 341*0fca6ea1SDimitry Andric } 342*0fca6ea1SDimitry Andric return false; 343*0fca6ea1SDimitry Andric } 344*0fca6ea1SDimitry Andric for (auto *MethodDecl : C->methods()) { 345*0fca6ea1SDimitry Andric if (safeGetName(MethodDecl) == "deref") { 346*0fca6ea1SDimitry Andric DerefFuncDeleteExprVisitor Visitor(DerivedClass); 347*0fca6ea1SDimitry Andric auto Result = Visitor.HasSpecializedDelete(MethodDecl); 348*0fca6ea1SDimitry Andric if (!Result || *Result) 349*0fca6ea1SDimitry Andric return Result; 350*0fca6ea1SDimitry Andric } 351*0fca6ea1SDimitry Andric } 352*0fca6ea1SDimitry Andric return false; 353*0fca6ea1SDimitry Andric } 354*0fca6ea1SDimitry Andric 3555ffd83dbSDimitry Andric void reportBug(const CXXRecordDecl *DerivedClass, 3565ffd83dbSDimitry Andric const CXXBaseSpecifier *BaseSpec, 3575ffd83dbSDimitry Andric const CXXRecordDecl *ProblematicBaseClass) const { 3585ffd83dbSDimitry Andric assert(DerivedClass); 3595ffd83dbSDimitry Andric assert(BaseSpec); 3605ffd83dbSDimitry Andric assert(ProblematicBaseClass); 3615ffd83dbSDimitry Andric 3625ffd83dbSDimitry Andric SmallString<100> Buf; 3635ffd83dbSDimitry Andric llvm::raw_svector_ostream Os(Buf); 3645ffd83dbSDimitry Andric 3655ffd83dbSDimitry Andric Os << (ProblematicBaseClass->isClass() ? "Class" : "Struct") << " "; 3665ffd83dbSDimitry Andric printQuotedQualifiedName(Os, ProblematicBaseClass); 3675ffd83dbSDimitry Andric 3685ffd83dbSDimitry Andric Os << " is used as a base of " 3695ffd83dbSDimitry Andric << (DerivedClass->isClass() ? "class" : "struct") << " "; 3705ffd83dbSDimitry Andric printQuotedQualifiedName(Os, DerivedClass); 3715ffd83dbSDimitry Andric 3725ffd83dbSDimitry Andric Os << " but doesn't have virtual destructor"; 3735ffd83dbSDimitry Andric 3745ffd83dbSDimitry Andric PathDiagnosticLocation BSLoc(BaseSpec->getSourceRange().getBegin(), 3755ffd83dbSDimitry Andric BR->getSourceManager()); 3765ffd83dbSDimitry Andric auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc); 3775ffd83dbSDimitry Andric Report->addRange(BaseSpec->getSourceRange()); 3785ffd83dbSDimitry Andric BR->emitReport(std::move(Report)); 3795ffd83dbSDimitry Andric } 3805ffd83dbSDimitry Andric }; 3815ffd83dbSDimitry Andric } // namespace 3825ffd83dbSDimitry Andric 3835ffd83dbSDimitry Andric void ento::registerRefCntblBaseVirtualDtorChecker(CheckerManager &Mgr) { 3845ffd83dbSDimitry Andric Mgr.registerChecker<RefCntblBaseVirtualDtorChecker>(); 3855ffd83dbSDimitry Andric } 3865ffd83dbSDimitry Andric 3875ffd83dbSDimitry Andric bool ento::shouldRegisterRefCntblBaseVirtualDtorChecker( 3885ffd83dbSDimitry Andric const CheckerManager &mgr) { 3895ffd83dbSDimitry Andric return true; 3905ffd83dbSDimitry Andric } 391