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") {}
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();
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 auto *ObjCType = dyn_cast<ObjCInterfaceType>(Desugared);
125 return ObjCType->getDecl();
128 void visitObjCDecl(
const ObjCContainerDecl *CD)
const {
129 if (BR->getSourceManager().isInSystemHeader(CD->
getLocation()))
135 visitObjCPropertyDecl(CD, it.second);
137 if (
auto *ID = dyn_cast<ObjCInterfaceDecl>(CD)) {
138 for (
auto *Ivar :
ID->ivars())
139 visitIvarDecl(CD, Ivar);
142 if (
auto *ID = dyn_cast<ObjCImplementationDecl>(CD)) {
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))
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};
235 return {IsUnsafePtr && *IsUnsafePtr, PropType};
238 bool shouldSkipDecl(
const RecordDecl *RD)
const {
251 if (!RDLocation.isValid())
255 if (Kind != TagTypeKind::Struct && Kind != TagTypeKind::Class &&
256 Kind != TagTypeKind::Union)
260 if (BR->getSourceManager().isInSystemHeader(RDLocation))
265 auto CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(RD);
272 template <
typename DeclType,
typename Po
inteeType,
typename ParentDeclType>
273 void reportBug(
const DeclType *
Member,
const Type *MemberType,
274 const PointeeType *Pointee,
275 const ParentDeclType *ClassCXXRD)
const {
280 SmallString<100> Buf;
281 llvm::raw_svector_ostream Os(Buf);
287 Os <<
"Instance variable ";
289 Os <<
"Member variable ";
293 if (
Member->getType().getTypePtrOrNull() == MemberType)
296 Os <<
" contains a ";
297 if (printPointer(Os, MemberType) == PrintDeclKind::Pointer) {
303 Os <<
"; " << invariant() <<
".";
305 PathDiagnosticLocation BSLoc(
Member->getSourceRange().getBegin(),
306 BR->getSourceManager());
307 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
309 BR->emitReport(std::move(
Report));
312 enum class PrintDeclKind { Pointee,
Pointer };
313 virtual PrintDeclKind printPointer(llvm::raw_svector_ostream &Os,
314 const Type *
T)
const {
317 Os << (IsPtr ?
"raw pointer" :
"reference") <<
" to " << typeName() <<
" ";
318 return PrintDeclKind::Pointee;
322class NoUncountedMemberChecker final :
public RawPtrRefMemberChecker {
324 NoUncountedMemberChecker()
325 : RawPtrRefMemberChecker(
"Member variable is a raw-pointer/reference to "
326 "reference-countable type") {}
328 std::optional<bool>
isUnsafePtr(QualType QT,
bool)
const final {
332 const char *typeName() const final {
return "ref-countable type"; }
334 const char *invariant() const final {
335 return "member variables must be Ref, RefPtr, WeakRef, or WeakPtr";
339class NoUncheckedPtrMemberChecker final :
public RawPtrRefMemberChecker {
341 NoUncheckedPtrMemberChecker()
342 : RawPtrRefMemberChecker(
"Member variable is a raw-pointer/reference to "
343 "checked-pointer capable type") {}
345 std::optional<bool>
isUnsafePtr(QualType QT,
bool)
const final {
349 const char *typeName() const final {
return "CheckedPtr capable type"; }
351 const char *invariant() const final {
352 return "member variables must be a CheckedPtr, CheckedRef, WeakRef, or "
357class NoUnretainedMemberChecker final :
public RawPtrRefMemberChecker {
359 NoUnretainedMemberChecker()
360 : RawPtrRefMemberChecker(
"Member variable is a raw-pointer/reference to "
362 RTC = RetainTypeChecker();
365 std::optional<bool>
isUnsafePtr(QualType QT,
bool ignoreARC)
const final {
366 return RTC->isUnretained(QT, ignoreARC);
369 const char *typeName() const final {
return "retainable type"; }
371 const char *invariant() const final {
372 return "member variables must be a RetainPtr";
375 PrintDeclKind printPointer(llvm::raw_svector_ostream &Os,
376 const Type *
T)
const final {
378 Os << typeName() <<
" ";
379 return PrintDeclKind::Pointer;
381 return RawPtrRefMemberChecker::printPointer(Os,
T);
391bool ento::shouldRegisterNoUncountedMemberChecker(
const CheckerManager &Mgr) {
395void ento::registerNoUncheckedPtrMemberChecker(
CheckerManager &Mgr) {
399bool ento::shouldRegisterNoUncheckedPtrMemberChecker(
404void ento::registerNoUnretainedMemberChecker(
CheckerManager &Mgr) {
408bool 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 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.
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
std::optional< bool > isUnsafePtr(const QualType T, bool IsArcEnabled)
const FunctionProtoType * T
@ Type
The name was classified as a type.
bool isSmartPtr(const CXXRecordDecl *R)
std::optional< bool > isUncountedPtr(const QualType T)
std::optional< bool > isUncheckedPtr(const QualType T)