xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //=======- RawPtrRefMemberChecker.cpp ----------------------------*- C++ -*-==//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric 
9*700637cbSDimitry Andric #include "DiagOutputUtils.h"
10*700637cbSDimitry Andric #include "PtrTypesSemantics.h"
11*700637cbSDimitry Andric #include "clang/AST/Decl.h"
12*700637cbSDimitry Andric #include "clang/AST/DeclCXX.h"
13*700637cbSDimitry Andric #include "clang/AST/DynamicRecursiveASTVisitor.h"
14*700637cbSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15*700637cbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
16*700637cbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17*700637cbSDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
18*700637cbSDimitry Andric #include "llvm/Support/Casting.h"
19*700637cbSDimitry Andric #include <optional>
20*700637cbSDimitry Andric 
21*700637cbSDimitry Andric using namespace clang;
22*700637cbSDimitry Andric using namespace ento;
23*700637cbSDimitry Andric 
24*700637cbSDimitry Andric namespace {
25*700637cbSDimitry Andric 
26*700637cbSDimitry Andric class RawPtrRefMemberChecker
27*700637cbSDimitry Andric     : public Checker<check::ASTDecl<TranslationUnitDecl>> {
28*700637cbSDimitry Andric private:
29*700637cbSDimitry Andric   BugType Bug;
30*700637cbSDimitry Andric   mutable BugReporter *BR;
31*700637cbSDimitry Andric   mutable llvm::DenseSet<const ObjCIvarDecl *> IvarDeclsToIgnore;
32*700637cbSDimitry Andric 
33*700637cbSDimitry Andric protected:
34*700637cbSDimitry Andric   mutable std::optional<RetainTypeChecker> RTC;
35*700637cbSDimitry Andric 
36*700637cbSDimitry Andric public:
RawPtrRefMemberChecker(const char * description)37*700637cbSDimitry Andric   RawPtrRefMemberChecker(const char *description)
38*700637cbSDimitry Andric       : Bug(this, description, "WebKit coding guidelines") {}
39*700637cbSDimitry Andric 
40*700637cbSDimitry Andric   virtual std::optional<bool> isUnsafePtr(QualType,
41*700637cbSDimitry Andric                                           bool ignoreARC = false) const = 0;
42*700637cbSDimitry Andric   virtual const char *typeName() const = 0;
43*700637cbSDimitry Andric   virtual const char *invariant() const = 0;
44*700637cbSDimitry Andric 
checkASTDecl(const TranslationUnitDecl * TUD,AnalysisManager & MGR,BugReporter & BRArg) const45*700637cbSDimitry Andric   void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
46*700637cbSDimitry Andric                     BugReporter &BRArg) const {
47*700637cbSDimitry Andric     BR = &BRArg;
48*700637cbSDimitry Andric 
49*700637cbSDimitry Andric     // The calls to checkAST* from AnalysisConsumer don't
50*700637cbSDimitry Andric     // visit template instantiations or lambda classes. We
51*700637cbSDimitry Andric     // want to visit those, so we make our own RecursiveASTVisitor.
52*700637cbSDimitry Andric     struct LocalVisitor : ConstDynamicRecursiveASTVisitor {
53*700637cbSDimitry Andric       const RawPtrRefMemberChecker *Checker;
54*700637cbSDimitry Andric       explicit LocalVisitor(const RawPtrRefMemberChecker *Checker)
55*700637cbSDimitry Andric           : Checker(Checker) {
56*700637cbSDimitry Andric         assert(Checker);
57*700637cbSDimitry Andric         ShouldVisitTemplateInstantiations = true;
58*700637cbSDimitry Andric         ShouldVisitImplicitCode = false;
59*700637cbSDimitry Andric       }
60*700637cbSDimitry Andric 
61*700637cbSDimitry Andric       bool VisitTypedefDecl(const TypedefDecl *TD) override {
62*700637cbSDimitry Andric         if (Checker->RTC)
63*700637cbSDimitry Andric           Checker->RTC->visitTypedef(TD);
64*700637cbSDimitry Andric         return true;
65*700637cbSDimitry Andric       }
66*700637cbSDimitry Andric 
67*700637cbSDimitry Andric       bool VisitRecordDecl(const RecordDecl *RD) override {
68*700637cbSDimitry Andric         Checker->visitRecordDecl(RD);
69*700637cbSDimitry Andric         return true;
70*700637cbSDimitry Andric       }
71*700637cbSDimitry Andric 
72*700637cbSDimitry Andric       bool VisitObjCContainerDecl(const ObjCContainerDecl *CD) override {
73*700637cbSDimitry Andric         Checker->visitObjCDecl(CD);
74*700637cbSDimitry Andric         return true;
75*700637cbSDimitry Andric       }
76*700637cbSDimitry Andric     };
77*700637cbSDimitry Andric 
78*700637cbSDimitry Andric     LocalVisitor visitor(this);
79*700637cbSDimitry Andric     if (RTC)
80*700637cbSDimitry Andric       RTC->visitTranslationUnitDecl(TUD);
81*700637cbSDimitry Andric     visitor.TraverseDecl(TUD);
82*700637cbSDimitry Andric   }
83*700637cbSDimitry Andric 
visitRecordDecl(const RecordDecl * RD) const84*700637cbSDimitry Andric   void visitRecordDecl(const RecordDecl *RD) const {
85*700637cbSDimitry Andric     if (shouldSkipDecl(RD))
86*700637cbSDimitry Andric       return;
87*700637cbSDimitry Andric 
88*700637cbSDimitry Andric     for (auto *Member : RD->fields())
89*700637cbSDimitry Andric       visitMember(Member, RD);
90*700637cbSDimitry Andric   }
91*700637cbSDimitry Andric 
visitMember(const FieldDecl * Member,const RecordDecl * RD) const92*700637cbSDimitry Andric   void visitMember(const FieldDecl *Member, const RecordDecl *RD) const {
93*700637cbSDimitry Andric     auto QT = Member->getType();
94*700637cbSDimitry Andric     const Type *MemberType = QT.getTypePtrOrNull();
95*700637cbSDimitry Andric 
96*700637cbSDimitry Andric     while (MemberType) {
97*700637cbSDimitry Andric       auto IsUnsafePtr = isUnsafePtr(QT);
98*700637cbSDimitry Andric       if (IsUnsafePtr && *IsUnsafePtr)
99*700637cbSDimitry Andric         break;
100*700637cbSDimitry Andric       if (!MemberType->isPointerType())
101*700637cbSDimitry Andric         return;
102*700637cbSDimitry Andric       QT = MemberType->getPointeeType();
103*700637cbSDimitry Andric       MemberType = QT.getTypePtrOrNull();
104*700637cbSDimitry Andric     }
105*700637cbSDimitry Andric 
106*700637cbSDimitry Andric     if (!MemberType)
107*700637cbSDimitry Andric       return;
108*700637cbSDimitry Andric 
109*700637cbSDimitry Andric     if (auto *MemberCXXRD = MemberType->getPointeeCXXRecordDecl())
110*700637cbSDimitry Andric       reportBug(Member, MemberType, MemberCXXRD, RD);
111*700637cbSDimitry Andric     else if (auto *ObjCDecl = getObjCDecl(MemberType))
112*700637cbSDimitry Andric       reportBug(Member, MemberType, ObjCDecl, RD);
113*700637cbSDimitry Andric   }
114*700637cbSDimitry Andric 
getObjCDecl(const Type * TypePtr) const115*700637cbSDimitry Andric   ObjCInterfaceDecl *getObjCDecl(const Type *TypePtr) const {
116*700637cbSDimitry Andric     auto *PointeeType = TypePtr->getPointeeType().getTypePtrOrNull();
117*700637cbSDimitry Andric     if (!PointeeType)
118*700637cbSDimitry Andric       return nullptr;
119*700637cbSDimitry Andric     auto *Desugared = PointeeType->getUnqualifiedDesugaredType();
120*700637cbSDimitry Andric     if (!Desugared)
121*700637cbSDimitry Andric       return nullptr;
122*700637cbSDimitry Andric     auto *ObjCType = dyn_cast<ObjCInterfaceType>(Desugared);
123*700637cbSDimitry Andric     if (!ObjCType)
124*700637cbSDimitry Andric       return nullptr;
125*700637cbSDimitry Andric     return ObjCType->getDecl();
126*700637cbSDimitry Andric   }
127*700637cbSDimitry Andric 
visitObjCDecl(const ObjCContainerDecl * CD) const128*700637cbSDimitry Andric   void visitObjCDecl(const ObjCContainerDecl *CD) const {
129*700637cbSDimitry Andric     if (BR->getSourceManager().isInSystemHeader(CD->getLocation()))
130*700637cbSDimitry Andric       return;
131*700637cbSDimitry Andric 
132*700637cbSDimitry Andric     ObjCContainerDecl::PropertyMap map;
133*700637cbSDimitry Andric     CD->collectPropertiesToImplement(map);
134*700637cbSDimitry Andric     for (auto it : map)
135*700637cbSDimitry Andric       visitObjCPropertyDecl(CD, it.second);
136*700637cbSDimitry Andric 
137*700637cbSDimitry Andric     if (auto *ID = dyn_cast<ObjCInterfaceDecl>(CD)) {
138*700637cbSDimitry Andric       for (auto *Ivar : ID->ivars())
139*700637cbSDimitry Andric         visitIvarDecl(CD, Ivar);
140*700637cbSDimitry Andric       return;
141*700637cbSDimitry Andric     }
142*700637cbSDimitry Andric     if (auto *ID = dyn_cast<ObjCImplementationDecl>(CD)) {
143*700637cbSDimitry Andric       for (auto *PropImpl : ID->property_impls())
144*700637cbSDimitry Andric         visitPropImpl(CD, PropImpl);
145*700637cbSDimitry Andric       for (auto *Ivar : ID->ivars())
146*700637cbSDimitry Andric         visitIvarDecl(CD, Ivar);
147*700637cbSDimitry Andric       return;
148*700637cbSDimitry Andric     }
149*700637cbSDimitry Andric   }
150*700637cbSDimitry Andric 
visitIvarDecl(const ObjCContainerDecl * CD,const ObjCIvarDecl * Ivar) const151*700637cbSDimitry Andric   void visitIvarDecl(const ObjCContainerDecl *CD,
152*700637cbSDimitry Andric                      const ObjCIvarDecl *Ivar) const {
153*700637cbSDimitry Andric     if (BR->getSourceManager().isInSystemHeader(Ivar->getLocation()))
154*700637cbSDimitry Andric       return;
155*700637cbSDimitry Andric 
156*700637cbSDimitry Andric     if (IvarDeclsToIgnore.contains(Ivar))
157*700637cbSDimitry Andric       return;
158*700637cbSDimitry Andric 
159*700637cbSDimitry Andric     auto QT = Ivar->getType();
160*700637cbSDimitry Andric     const Type *IvarType = QT.getTypePtrOrNull();
161*700637cbSDimitry Andric     if (!IvarType)
162*700637cbSDimitry Andric       return;
163*700637cbSDimitry Andric 
164*700637cbSDimitry Andric     auto IsUnsafePtr = isUnsafePtr(QT);
165*700637cbSDimitry Andric     if (!IsUnsafePtr || !*IsUnsafePtr)
166*700637cbSDimitry Andric       return;
167*700637cbSDimitry Andric 
168*700637cbSDimitry Andric     IvarDeclsToIgnore.insert(Ivar);
169*700637cbSDimitry Andric 
170*700637cbSDimitry Andric     if (auto *MemberCXXRD = IvarType->getPointeeCXXRecordDecl())
171*700637cbSDimitry Andric       reportBug(Ivar, IvarType, MemberCXXRD, CD);
172*700637cbSDimitry Andric     else if (auto *ObjCDecl = getObjCDecl(IvarType))
173*700637cbSDimitry Andric       reportBug(Ivar, IvarType, ObjCDecl, CD);
174*700637cbSDimitry Andric   }
175*700637cbSDimitry Andric 
visitObjCPropertyDecl(const ObjCContainerDecl * CD,const ObjCPropertyDecl * PD) const176*700637cbSDimitry Andric   void visitObjCPropertyDecl(const ObjCContainerDecl *CD,
177*700637cbSDimitry Andric                              const ObjCPropertyDecl *PD) const {
178*700637cbSDimitry Andric     if (BR->getSourceManager().isInSystemHeader(PD->getLocation()))
179*700637cbSDimitry Andric       return;
180*700637cbSDimitry Andric 
181*700637cbSDimitry Andric     if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CD)) {
182*700637cbSDimitry Andric       if (!RTC || !RTC->defaultSynthProperties() ||
183*700637cbSDimitry Andric           ID->isObjCRequiresPropertyDefs())
184*700637cbSDimitry Andric         return;
185*700637cbSDimitry Andric     }
186*700637cbSDimitry Andric 
187*700637cbSDimitry Andric     auto [IsUnsafe, PropType] = isPropImplUnsafePtr(PD);
188*700637cbSDimitry Andric     if (!IsUnsafe)
189*700637cbSDimitry Andric       return;
190*700637cbSDimitry Andric 
191*700637cbSDimitry Andric     if (auto *MemberCXXRD = PropType->getPointeeCXXRecordDecl())
192*700637cbSDimitry Andric       reportBug(PD, PropType, MemberCXXRD, CD);
193*700637cbSDimitry Andric     else if (auto *ObjCDecl = getObjCDecl(PropType))
194*700637cbSDimitry Andric       reportBug(PD, PropType, ObjCDecl, CD);
195*700637cbSDimitry Andric   }
196*700637cbSDimitry Andric 
visitPropImpl(const ObjCContainerDecl * CD,const ObjCPropertyImplDecl * PID) const197*700637cbSDimitry Andric   void visitPropImpl(const ObjCContainerDecl *CD,
198*700637cbSDimitry Andric                      const ObjCPropertyImplDecl *PID) const {
199*700637cbSDimitry Andric     if (BR->getSourceManager().isInSystemHeader(PID->getLocation()))
200*700637cbSDimitry Andric       return;
201*700637cbSDimitry Andric 
202*700637cbSDimitry Andric     if (PID->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
203*700637cbSDimitry Andric       return;
204*700637cbSDimitry Andric 
205*700637cbSDimitry Andric     auto *PropDecl = PID->getPropertyDecl();
206*700637cbSDimitry Andric     if (auto *IvarDecl = PID->getPropertyIvarDecl()) {
207*700637cbSDimitry Andric       if (IvarDeclsToIgnore.contains(IvarDecl))
208*700637cbSDimitry Andric         return;
209*700637cbSDimitry Andric       IvarDeclsToIgnore.insert(IvarDecl);
210*700637cbSDimitry Andric     }
211*700637cbSDimitry Andric     auto [IsUnsafe, PropType] = isPropImplUnsafePtr(PropDecl);
212*700637cbSDimitry Andric     if (!IsUnsafe)
213*700637cbSDimitry Andric       return;
214*700637cbSDimitry Andric 
215*700637cbSDimitry Andric     if (auto *MemberCXXRD = PropType->getPointeeCXXRecordDecl())
216*700637cbSDimitry Andric       reportBug(PropDecl, PropType, MemberCXXRD, CD);
217*700637cbSDimitry Andric     else if (auto *ObjCDecl = getObjCDecl(PropType))
218*700637cbSDimitry Andric       reportBug(PropDecl, PropType, ObjCDecl, CD);
219*700637cbSDimitry Andric   }
220*700637cbSDimitry Andric 
221*700637cbSDimitry Andric   std::pair<bool, const Type *>
isPropImplUnsafePtr(const ObjCPropertyDecl * PD) const222*700637cbSDimitry Andric   isPropImplUnsafePtr(const ObjCPropertyDecl *PD) const {
223*700637cbSDimitry Andric     if (!PD)
224*700637cbSDimitry Andric       return {false, nullptr};
225*700637cbSDimitry Andric 
226*700637cbSDimitry Andric     auto QT = PD->getType();
227*700637cbSDimitry Andric     const Type *PropType = QT.getTypePtrOrNull();
228*700637cbSDimitry Andric     if (!PropType)
229*700637cbSDimitry Andric       return {false, nullptr};
230*700637cbSDimitry Andric 
231*700637cbSDimitry Andric     // "assign" property doesn't retain even under ARC so treat it as unsafe.
232*700637cbSDimitry Andric     bool ignoreARC =
233*700637cbSDimitry Andric         !PD->isReadOnly() && PD->getSetterKind() == ObjCPropertyDecl::Assign;
234*700637cbSDimitry Andric     auto IsUnsafePtr = isUnsafePtr(QT, ignoreARC);
235*700637cbSDimitry Andric     return {IsUnsafePtr && *IsUnsafePtr, PropType};
236*700637cbSDimitry Andric   }
237*700637cbSDimitry Andric 
shouldSkipDecl(const RecordDecl * RD) const238*700637cbSDimitry Andric   bool shouldSkipDecl(const RecordDecl *RD) const {
239*700637cbSDimitry Andric     if (!RD->isThisDeclarationADefinition())
240*700637cbSDimitry Andric       return true;
241*700637cbSDimitry Andric 
242*700637cbSDimitry Andric     if (RD->isImplicit())
243*700637cbSDimitry Andric       return true;
244*700637cbSDimitry Andric 
245*700637cbSDimitry Andric     if (RD->isLambda())
246*700637cbSDimitry Andric       return true;
247*700637cbSDimitry Andric 
248*700637cbSDimitry Andric     // If the construct doesn't have a source file, then it's not something
249*700637cbSDimitry Andric     // we want to diagnose.
250*700637cbSDimitry Andric     const auto RDLocation = RD->getLocation();
251*700637cbSDimitry Andric     if (!RDLocation.isValid())
252*700637cbSDimitry Andric       return true;
253*700637cbSDimitry Andric 
254*700637cbSDimitry Andric     const auto Kind = RD->getTagKind();
255*700637cbSDimitry Andric     if (Kind != TagTypeKind::Struct && Kind != TagTypeKind::Class &&
256*700637cbSDimitry Andric         Kind != TagTypeKind::Union)
257*700637cbSDimitry Andric       return true;
258*700637cbSDimitry Andric 
259*700637cbSDimitry Andric     // Ignore CXXRecords that come from system headers.
260*700637cbSDimitry Andric     if (BR->getSourceManager().isInSystemHeader(RDLocation))
261*700637cbSDimitry Andric       return true;
262*700637cbSDimitry Andric 
263*700637cbSDimitry Andric     // Ref-counted smartpointers actually have raw-pointer to uncounted type as
264*700637cbSDimitry Andric     // a member but we trust them to handle it correctly.
265*700637cbSDimitry Andric     auto CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(RD);
266*700637cbSDimitry Andric     if (CXXRD && isSmartPtr(CXXRD))
267*700637cbSDimitry Andric       return true;
268*700637cbSDimitry Andric 
269*700637cbSDimitry Andric     return false;
270*700637cbSDimitry Andric   }
271*700637cbSDimitry Andric 
272*700637cbSDimitry Andric   template <typename DeclType, typename PointeeType, typename ParentDeclType>
reportBug(const DeclType * Member,const Type * MemberType,const PointeeType * Pointee,const ParentDeclType * ClassCXXRD) const273*700637cbSDimitry Andric   void reportBug(const DeclType *Member, const Type *MemberType,
274*700637cbSDimitry Andric                  const PointeeType *Pointee,
275*700637cbSDimitry Andric                  const ParentDeclType *ClassCXXRD) const {
276*700637cbSDimitry Andric     assert(Member);
277*700637cbSDimitry Andric     assert(MemberType);
278*700637cbSDimitry Andric     assert(Pointee);
279*700637cbSDimitry Andric 
280*700637cbSDimitry Andric     SmallString<100> Buf;
281*700637cbSDimitry Andric     llvm::raw_svector_ostream Os(Buf);
282*700637cbSDimitry Andric 
283*700637cbSDimitry Andric     if (isa<ObjCContainerDecl>(ClassCXXRD)) {
284*700637cbSDimitry Andric       if (isa<ObjCPropertyDecl>(Member))
285*700637cbSDimitry Andric         Os << "Property ";
286*700637cbSDimitry Andric       else
287*700637cbSDimitry Andric         Os << "Instance variable ";
288*700637cbSDimitry Andric     } else
289*700637cbSDimitry Andric       Os << "Member variable ";
290*700637cbSDimitry Andric     printQuotedName(Os, Member);
291*700637cbSDimitry Andric     Os << " in ";
292*700637cbSDimitry Andric     printQuotedQualifiedName(Os, ClassCXXRD);
293*700637cbSDimitry Andric     if (Member->getType().getTypePtrOrNull() == MemberType)
294*700637cbSDimitry Andric       Os << " is a ";
295*700637cbSDimitry Andric     else
296*700637cbSDimitry Andric       Os << " contains a ";
297*700637cbSDimitry Andric     if (printPointer(Os, MemberType) == PrintDeclKind::Pointer) {
298*700637cbSDimitry Andric       auto Typedef = MemberType->getAs<TypedefType>();
299*700637cbSDimitry Andric       assert(Typedef);
300*700637cbSDimitry Andric       printQuotedQualifiedName(Os, Typedef->getDecl());
301*700637cbSDimitry Andric     } else
302*700637cbSDimitry Andric       printQuotedQualifiedName(Os, Pointee);
303*700637cbSDimitry Andric     Os << "; " << invariant() << ".";
304*700637cbSDimitry Andric 
305*700637cbSDimitry Andric     PathDiagnosticLocation BSLoc(Member->getSourceRange().getBegin(),
306*700637cbSDimitry Andric                                  BR->getSourceManager());
307*700637cbSDimitry Andric     auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
308*700637cbSDimitry Andric     Report->addRange(Member->getSourceRange());
309*700637cbSDimitry Andric     BR->emitReport(std::move(Report));
310*700637cbSDimitry Andric   }
311*700637cbSDimitry Andric 
312*700637cbSDimitry Andric   enum class PrintDeclKind { Pointee, Pointer };
printPointer(llvm::raw_svector_ostream & Os,const Type * T) const313*700637cbSDimitry Andric   virtual PrintDeclKind printPointer(llvm::raw_svector_ostream &Os,
314*700637cbSDimitry Andric                                      const Type *T) const {
315*700637cbSDimitry Andric     T = T->getUnqualifiedDesugaredType();
316*700637cbSDimitry Andric     bool IsPtr = isa<PointerType>(T) || isa<ObjCObjectPointerType>(T);
317*700637cbSDimitry Andric     Os << (IsPtr ? "raw pointer" : "reference") << " to " << typeName() << " ";
318*700637cbSDimitry Andric     return PrintDeclKind::Pointee;
319*700637cbSDimitry Andric   }
320*700637cbSDimitry Andric };
321*700637cbSDimitry Andric 
322*700637cbSDimitry Andric class NoUncountedMemberChecker final : public RawPtrRefMemberChecker {
323*700637cbSDimitry Andric public:
NoUncountedMemberChecker()324*700637cbSDimitry Andric   NoUncountedMemberChecker()
325*700637cbSDimitry Andric       : RawPtrRefMemberChecker("Member variable is a raw-pointer/reference to "
326*700637cbSDimitry Andric                                "reference-countable type") {}
327*700637cbSDimitry Andric 
isUnsafePtr(QualType QT,bool) const328*700637cbSDimitry Andric   std::optional<bool> isUnsafePtr(QualType QT, bool) const final {
329*700637cbSDimitry Andric     return isUncountedPtr(QT.getCanonicalType());
330*700637cbSDimitry Andric   }
331*700637cbSDimitry Andric 
typeName() const332*700637cbSDimitry Andric   const char *typeName() const final { return "ref-countable type"; }
333*700637cbSDimitry Andric 
invariant() const334*700637cbSDimitry Andric   const char *invariant() const final {
335*700637cbSDimitry Andric     return "member variables must be Ref, RefPtr, WeakRef, or WeakPtr";
336*700637cbSDimitry Andric   }
337*700637cbSDimitry Andric };
338*700637cbSDimitry Andric 
339*700637cbSDimitry Andric class NoUncheckedPtrMemberChecker final : public RawPtrRefMemberChecker {
340*700637cbSDimitry Andric public:
NoUncheckedPtrMemberChecker()341*700637cbSDimitry Andric   NoUncheckedPtrMemberChecker()
342*700637cbSDimitry Andric       : RawPtrRefMemberChecker("Member variable is a raw-pointer/reference to "
343*700637cbSDimitry Andric                                "checked-pointer capable type") {}
344*700637cbSDimitry Andric 
isUnsafePtr(QualType QT,bool) const345*700637cbSDimitry Andric   std::optional<bool> isUnsafePtr(QualType QT, bool) const final {
346*700637cbSDimitry Andric     return isUncheckedPtr(QT.getCanonicalType());
347*700637cbSDimitry Andric   }
348*700637cbSDimitry Andric 
typeName() const349*700637cbSDimitry Andric   const char *typeName() const final { return "CheckedPtr capable type"; }
350*700637cbSDimitry Andric 
invariant() const351*700637cbSDimitry Andric   const char *invariant() const final {
352*700637cbSDimitry Andric     return "member variables must be a CheckedPtr, CheckedRef, WeakRef, or "
353*700637cbSDimitry Andric            "WeakPtr";
354*700637cbSDimitry Andric   }
355*700637cbSDimitry Andric };
356*700637cbSDimitry Andric 
357*700637cbSDimitry Andric class NoUnretainedMemberChecker final : public RawPtrRefMemberChecker {
358*700637cbSDimitry Andric public:
NoUnretainedMemberChecker()359*700637cbSDimitry Andric   NoUnretainedMemberChecker()
360*700637cbSDimitry Andric       : RawPtrRefMemberChecker("Member variable is a raw-pointer/reference to "
361*700637cbSDimitry Andric                                "retainable type") {
362*700637cbSDimitry Andric     RTC = RetainTypeChecker();
363*700637cbSDimitry Andric   }
364*700637cbSDimitry Andric 
isUnsafePtr(QualType QT,bool ignoreARC) const365*700637cbSDimitry Andric   std::optional<bool> isUnsafePtr(QualType QT, bool ignoreARC) const final {
366*700637cbSDimitry Andric     return RTC->isUnretained(QT, ignoreARC);
367*700637cbSDimitry Andric   }
368*700637cbSDimitry Andric 
typeName() const369*700637cbSDimitry Andric   const char *typeName() const final { return "retainable type"; }
370*700637cbSDimitry Andric 
invariant() const371*700637cbSDimitry Andric   const char *invariant() const final {
372*700637cbSDimitry Andric     return "member variables must be a RetainPtr";
373*700637cbSDimitry Andric   }
374*700637cbSDimitry Andric 
printPointer(llvm::raw_svector_ostream & Os,const Type * T) const375*700637cbSDimitry Andric   PrintDeclKind printPointer(llvm::raw_svector_ostream &Os,
376*700637cbSDimitry Andric                              const Type *T) const final {
377*700637cbSDimitry Andric     if (!isa<ObjCObjectPointerType>(T) && T->getAs<TypedefType>()) {
378*700637cbSDimitry Andric       Os << typeName() << " ";
379*700637cbSDimitry Andric       return PrintDeclKind::Pointer;
380*700637cbSDimitry Andric     }
381*700637cbSDimitry Andric     return RawPtrRefMemberChecker::printPointer(Os, T);
382*700637cbSDimitry Andric   }
383*700637cbSDimitry Andric };
384*700637cbSDimitry Andric 
385*700637cbSDimitry Andric } // namespace
386*700637cbSDimitry Andric 
registerNoUncountedMemberChecker(CheckerManager & Mgr)387*700637cbSDimitry Andric void ento::registerNoUncountedMemberChecker(CheckerManager &Mgr) {
388*700637cbSDimitry Andric   Mgr.registerChecker<NoUncountedMemberChecker>();
389*700637cbSDimitry Andric }
390*700637cbSDimitry Andric 
shouldRegisterNoUncountedMemberChecker(const CheckerManager & Mgr)391*700637cbSDimitry Andric bool ento::shouldRegisterNoUncountedMemberChecker(const CheckerManager &Mgr) {
392*700637cbSDimitry Andric   return true;
393*700637cbSDimitry Andric }
394*700637cbSDimitry Andric 
registerNoUncheckedPtrMemberChecker(CheckerManager & Mgr)395*700637cbSDimitry Andric void ento::registerNoUncheckedPtrMemberChecker(CheckerManager &Mgr) {
396*700637cbSDimitry Andric   Mgr.registerChecker<NoUncheckedPtrMemberChecker>();
397*700637cbSDimitry Andric }
398*700637cbSDimitry Andric 
shouldRegisterNoUncheckedPtrMemberChecker(const CheckerManager & Mgr)399*700637cbSDimitry Andric bool ento::shouldRegisterNoUncheckedPtrMemberChecker(
400*700637cbSDimitry Andric     const CheckerManager &Mgr) {
401*700637cbSDimitry Andric   return true;
402*700637cbSDimitry Andric }
403*700637cbSDimitry Andric 
registerNoUnretainedMemberChecker(CheckerManager & Mgr)404*700637cbSDimitry Andric void ento::registerNoUnretainedMemberChecker(CheckerManager &Mgr) {
405*700637cbSDimitry Andric   Mgr.registerChecker<NoUnretainedMemberChecker>();
406*700637cbSDimitry Andric }
407*700637cbSDimitry Andric 
shouldRegisterNoUnretainedMemberChecker(const CheckerManager & Mgr)408*700637cbSDimitry Andric bool ento::shouldRegisterNoUnretainedMemberChecker(const CheckerManager &Mgr) {
409*700637cbSDimitry Andric   return true;
410*700637cbSDimitry Andric }
411