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