18#include "llvm/Support/Casting.h"
26class RawPtrRefMemberChecker
27 :
public Checker<check::ASTDecl<TranslationUnitDecl>> {
30 mutable BugReporter *BR;
31 mutable llvm::DenseSet<const ObjCIvarDecl *> IvarDeclsToIgnore;
34 mutable std::optional<RetainTypeChecker> RTC;
37 RawPtrRefMemberChecker(
const char *description)
38 : Bug(this, description,
"WebKit coding guidelines") {}
40 virtual std::optional<bool> isUnsafePtr(QualType,
41 bool ignoreARC =
false)
const = 0;
42 virtual const char *typeName()
const = 0;
43 virtual const char *invariant()
const = 0;
45 void checkASTDecl(
const TranslationUnitDecl *TUD, AnalysisManager &MGR,
46 BugReporter &BRArg)
const {
53 const RawPtrRefMemberChecker *Checker;
54 explicit LocalVisitor(
const RawPtrRefMemberChecker *Checker)
57 ShouldVisitTemplateInstantiations =
true;
58 ShouldVisitImplicitCode =
false;
61 bool VisitTypedefDecl(
const TypedefDecl *TD)
override {
63 Checker->RTC->visitTypedef(TD);
67 bool VisitRecordDecl(
const RecordDecl *RD)
override {
68 Checker->visitRecordDecl(RD);
72 bool VisitObjCContainerDecl(
const ObjCContainerDecl *CD)
override {
73 Checker->visitObjCDecl(CD);
78 LocalVisitor visitor(
this);
80 RTC->visitTranslationUnitDecl(TUD);
81 visitor.TraverseDecl(TUD);
84 void visitRecordDecl(
const RecordDecl *RD)
const {
85 if (shouldSkipDecl(RD))
92 void visitMember(
const FieldDecl *
Member,
const RecordDecl *RD)
const {
93 auto QT =
Member->getType();
94 const Type *MemberType = QT.getTypePtrOrNull();
97 auto IsUnsafePtr = isUnsafePtr(QT);
98 if (IsUnsafePtr && *IsUnsafePtr)
103 MemberType = QT.getTypePtrOrNull();
110 reportBug(
Member, MemberType, MemberCXXRD, RD);
111 else if (
auto *ObjCDecl = getObjCDecl(MemberType))
112 reportBug(
Member, MemberType, ObjCDecl, RD);
115 ObjCInterfaceDecl *getObjCDecl(
const Type *TypePtr)
const {
122 if (
auto *ObjCType = dyn_cast<ObjCInterfaceType>(Desugared))
123 return ObjCType->getDecl();
124 if (
auto *ObjCType = dyn_cast<ObjCObjectType>(Desugared))
125 return ObjCType->getInterface();
129 void visitObjCDecl(
const ObjCContainerDecl *CD)
const {
130 if (BR->getSourceManager().isInSystemHeader(CD->
getLocation()))
133 if (
auto *ID = dyn_cast<ObjCImplementationDecl>(CD)) {
137 visitObjCPropertyDecl(CD, it.second);
141 visitIvarDecl(CD, Ivar);
143 for (
auto *PropImpl :
ID->property_impls())
144 visitPropImpl(CD, PropImpl);
145 for (
auto *Ivar :
ID->ivars())
146 visitIvarDecl(CD, Ivar);
151 void visitIvarDecl(
const ObjCContainerDecl *CD,
152 const ObjCIvarDecl *Ivar)
const {
153 if (BR->getSourceManager().isInSystemHeader(Ivar->
getLocation()))
156 if (IvarDeclsToIgnore.contains(Ivar))
164 auto IsUnsafePtr = isUnsafePtr(QT);
165 if (!IsUnsafePtr || !*IsUnsafePtr)
168 IvarDeclsToIgnore.insert(Ivar);
171 reportBug(Ivar, IvarType, MemberCXXRD, CD);
172 else if (
auto *ObjCDecl = getObjCDecl(IvarType))
173 reportBug(Ivar, IvarType, ObjCDecl, CD);
176 void visitObjCPropertyDecl(
const ObjCContainerDecl *CD,
177 const ObjCPropertyDecl *PD)
const {
178 if (BR->getSourceManager().isInSystemHeader(PD->
getLocation()))
181 if (
const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CD)) {
182 if (!RTC || !RTC->defaultSynthProperties() ||
183 ID->isObjCRequiresPropertyDefs())
187 auto [IsUnsafe, PropType] = isPropImplUnsafePtr(PD);
191 if (
auto *MemberCXXRD = PropType->getPointeeCXXRecordDecl())
192 reportBug(PD, PropType, MemberCXXRD, CD);
193 else if (
auto *ObjCDecl = getObjCDecl(PropType))
194 reportBug(PD, PropType, ObjCDecl, CD);
197 void visitPropImpl(
const ObjCContainerDecl *CD,
198 const ObjCPropertyImplDecl *PID)
const {
199 if (BR->getSourceManager().isInSystemHeader(PID->
getLocation()))
207 if (IvarDeclsToIgnore.contains(IvarDecl))
209 IvarDeclsToIgnore.insert(IvarDecl);
211 auto [IsUnsafe, PropType] = isPropImplUnsafePtr(PropDecl);
215 if (
auto *MemberCXXRD = PropType->getPointeeCXXRecordDecl())
216 reportBug(PropDecl, PropType, MemberCXXRD, CD);
217 else if (
auto *ObjCDecl = getObjCDecl(PropType))
218 reportBug(PropDecl, PropType, ObjCDecl, CD);
221 std::pair<bool, const Type *>
222 isPropImplUnsafePtr(
const ObjCPropertyDecl *PD)
const {
224 return {
false,
nullptr};
229 return {
false,
nullptr};
237 auto IsUnsafePtr = isUnsafePtr(QT, ignoreARC);
238 return {IsUnsafePtr && *IsUnsafePtr && !HasSafeAttr, PropType};
241 bool shouldSkipDecl(
const RecordDecl *RD)
const {
254 if (!RDLocation.isValid())
258 if (Kind != TagTypeKind::Struct && Kind != TagTypeKind::Class &&
259 Kind != TagTypeKind::Union)
263 if (BR->getSourceManager().isInSystemHeader(RDLocation))
268 auto CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(RD);
275 template <
typename DeclType,
typename Po
inteeType,
typename ParentDeclType>
276 void reportBug(
const DeclType *
Member,
const Type *MemberType,
277 const PointeeType *Pointee,
278 const ParentDeclType *ClassCXXRD)
const {
283 SmallString<100> Buf;
284 llvm::raw_svector_ostream Os(Buf);
290 Os <<
"Instance variable ";
292 Os <<
"Member variable ";
296 if (
Member->getType().getTypePtrOrNull() == MemberType)
299 Os <<
" contains a ";
300 if (printPointer(Os, MemberType) == PrintDeclKind::Pointer) {
306 Os <<
"; " << invariant() <<
".";
308 PathDiagnosticLocation BSLoc(
Member->getSourceRange().getBegin(),
309 BR->getSourceManager());
310 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
312 BR->emitReport(std::move(
Report));
315 enum class PrintDeclKind { Pointee,
Pointer };
316 virtual PrintDeclKind printPointer(llvm::raw_svector_ostream &Os,
317 const Type *
T)
const {
320 Os << (IsPtr ?
"raw pointer" :
"reference") <<
" to " << typeName() <<
" ";
321 return PrintDeclKind::Pointee;
325class NoUncountedMemberChecker final :
public RawPtrRefMemberChecker {
327 NoUncountedMemberChecker()
328 : RawPtrRefMemberChecker(
"Member variable is a raw-pointer/reference to "
329 "reference-countable type") {}
331 std::optional<bool> isUnsafePtr(QualType QT,
bool)
const final {
335 const char *typeName() const final {
return "ref-countable type"; }
337 const char *invariant() const final {
338 return "member variables must be Ref, RefPtr, WeakRef, or WeakPtr";
342class NoUncheckedPtrMemberChecker final :
public RawPtrRefMemberChecker {
344 NoUncheckedPtrMemberChecker()
345 : RawPtrRefMemberChecker(
"Member variable is a raw-pointer/reference to "
346 "checked-pointer capable type") {}
348 std::optional<bool> isUnsafePtr(QualType QT,
bool)
const final {
352 const char *typeName() const final {
return "CheckedPtr capable type"; }
354 const char *invariant() const final {
355 return "member variables must be a CheckedPtr, CheckedRef, WeakRef, or "
360class NoUnretainedMemberChecker final :
public RawPtrRefMemberChecker {
362 NoUnretainedMemberChecker()
363 : RawPtrRefMemberChecker(
"Member variable is a raw-pointer/reference to "
365 RTC = RetainTypeChecker();
368 std::optional<bool> isUnsafePtr(QualType QT,
bool ignoreARC)
const final {
369 if (QT.hasStrongOrWeakObjCLifetime())
371 return RTC->isUnretained(QT, ignoreARC);
374 const char *typeName() const final {
return "retainable type"; }
376 const char *invariant() const final {
377 return "member variables must be a RetainPtr or OSObjectPtr";
380 PrintDeclKind printPointer(llvm::raw_svector_ostream &Os,
381 const Type *
T)
const final {
383 Os << typeName() <<
" ";
384 return PrintDeclKind::Pointer;
386 return RawPtrRefMemberChecker::printPointer(Os,
T);
396bool ento::shouldRegisterNoUncountedMemberChecker(
const CheckerManager &Mgr) {
400void ento::registerNoUncheckedPtrMemberChecker(
CheckerManager &Mgr) {
404bool ento::shouldRegisterNoUncheckedPtrMemberChecker(
409void ento::registerNoUnretainedMemberChecker(
CheckerManager &Mgr) {
413bool ento::shouldRegisterNoUnretainedMemberChecker(
const CheckerManager &Mgr) {
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
SourceLocation getLocation() const
llvm::MapVector< std::pair< IdentifierInfo *, unsigned >, ObjCPropertyDecl * > PropertyMap
virtual void collectPropertiesToImplement(PropertyMap &PM) const
This routine collects list of properties to be implemented in the class.
bool isRetaining() const
isRetaining - Return true if the property retains its value.
bool isReadOnly() const
isReadOnly - Return true iff the property has a setter.
SetterKind getSetterKind() const
getSetterKind - Return the method used for doing assignment in the property setter.
ObjCPropertyAttribute::Kind getPropertyAttributes() const
ObjCIvarDecl * getPropertyIvarDecl() const
Kind getPropertyImplementation() const
ObjCPropertyDecl * getPropertyDecl() const
const Type * getTypePtrOrNull() const
bool isLambda() const
Determine whether this record is a class describing a lambda function object.
field_range fields() const
bool isThisDeclarationADefinition() const
Return true if this declaration is a completion definition of the type.
TagKind getTagKind() const
bool isPointerType() const
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const T * getAs() const
Member-template getAs<specific type>'.
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
void printQuotedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
DynamicRecursiveASTVisitorBase< true > ConstDynamicRecursiveASTVisitor
const FunctionProtoType * T
@ Type
The name was classified as a type.
bool isSmartPtr(const CXXRecordDecl *R)
std::optional< bool > isUncountedPtr(const QualType T)
@ Interface
The "__interface" keyword introduces the elaborated-type-specifier.
std::optional< bool > isUncheckedPtr(const QualType T)