21#include "llvm/Support/Casting.h"
29class RawPtrRefMemberChecker
30 :
public Checker<check::ASTDecl<TranslationUnitDecl>> {
33 mutable BugReporter *BR;
34 mutable llvm::DenseSet<const ObjCIvarDecl *> IvarDeclsToIgnore;
37 const std::unique_ptr<PtrRefSafetyModel> Model;
40 RawPtrRefMemberChecker(
const char *description,
41 std::unique_ptr<PtrRefSafetyModel> Model)
42 : Bug(this, description,
"WebKit coding guidelines"),
43 Model(std::move(Model)) {}
45 std::optional<bool> isUnsafePtr(QualType QT,
bool IgnoreARC =
false)
const {
49 void checkASTDecl(
const TranslationUnitDecl *TUD, AnalysisManager &MGR,
50 BugReporter &BRArg)
const {
57 const RawPtrRefMemberChecker *Checker;
58 explicit LocalVisitor(
const RawPtrRefMemberChecker *Checker)
61 ShouldVisitTemplateInstantiations =
true;
62 ShouldVisitImplicitCode =
false;
65 bool VisitTypedefDecl(
const TypedefDecl *TD)
override {
66 if (
auto *RTC = Checker->Model->retainTypeChecker())
67 RTC->visitTypedef(TD);
71 bool VisitRecordDecl(
const RecordDecl *RD)
override {
72 Checker->visitRecordDecl(RD);
76 bool VisitObjCContainerDecl(
const ObjCContainerDecl *CD)
override {
77 Checker->visitObjCDecl(CD);
82 LocalVisitor visitor(
this);
83 if (
auto *RTC = Model->retainTypeChecker())
84 RTC->visitTranslationUnitDecl(TUD);
85 visitor.TraverseDecl(TUD);
88 void visitRecordDecl(
const RecordDecl *RD)
const {
89 if (shouldSkipDecl(RD))
96 void visitMember(
const FieldDecl *
Member,
const RecordDecl *RD)
const {
97 auto QT =
Member->getType();
98 const Type *MemberType = QT.getTypePtrOrNull();
101 auto IsUnsafePtr = isUnsafePtr(QT);
102 if (IsUnsafePtr && *IsUnsafePtr)
107 MemberType = QT.getTypePtrOrNull();
114 reportBug(
Member, MemberType, MemberCXXRD, RD);
116 reportBug(
Member, MemberType, ObjCDecl, RD);
119 void visitObjCDecl(
const ObjCContainerDecl *CD)
const {
120 if (BR->getSourceManager().isInSystemHeader(CD->
getLocation()))
123 if (
auto *ID = dyn_cast<ObjCImplementationDecl>(CD)) {
127 visitObjCPropertyDecl(CD, it.second);
131 visitIvarDecl(CD, Ivar);
133 for (
auto *PropImpl :
ID->property_impls())
134 visitPropImpl(CD, PropImpl);
135 for (
auto *Ivar :
ID->ivars())
136 visitIvarDecl(CD, Ivar);
141 void visitIvarDecl(
const ObjCContainerDecl *CD,
142 const ObjCIvarDecl *Ivar)
const {
143 if (BR->getSourceManager().isInSystemHeader(Ivar->
getLocation()))
146 if (IvarDeclsToIgnore.contains(Ivar))
154 auto IsUnsafePtr = isUnsafePtr(QT);
155 if (!IsUnsafePtr || !*IsUnsafePtr)
158 IvarDeclsToIgnore.insert(Ivar);
161 reportBug(Ivar, IvarType, MemberCXXRD, CD);
163 reportBug(Ivar, IvarType, ObjCDecl, CD);
166 void visitObjCPropertyDecl(
const ObjCContainerDecl *CD,
167 const ObjCPropertyDecl *PD)
const {
168 if (BR->getSourceManager().isInSystemHeader(PD->
getLocation()))
171 if (
const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CD)) {
172 auto *RTC = Model->retainTypeChecker();
173 if (!RTC || !RTC->defaultSynthProperties() ||
174 ID->isObjCRequiresPropertyDefs())
178 auto [IsUnsafe, PropType] = isPropImplUnsafePtr(PD);
182 if (
auto *MemberCXXRD = PropType->getPointeeCXXRecordDecl())
183 reportBug(PD, PropType, MemberCXXRD, CD);
185 reportBug(PD, PropType, ObjCDecl, CD);
188 void visitPropImpl(
const ObjCContainerDecl *CD,
189 const ObjCPropertyImplDecl *PID)
const {
190 if (BR->getSourceManager().isInSystemHeader(PID->
getLocation()))
198 if (IvarDeclsToIgnore.contains(IvarDecl))
200 IvarDeclsToIgnore.insert(IvarDecl);
202 auto [IsUnsafe, PropType] = isPropImplUnsafePtr(PropDecl);
206 if (
auto *MemberCXXRD = PropType->getPointeeCXXRecordDecl())
207 reportBug(PropDecl, PropType, MemberCXXRD, CD);
209 reportBug(PropDecl, PropType, ObjCDecl, CD);
212 std::pair<bool, const Type *>
213 isPropImplUnsafePtr(
const ObjCPropertyDecl *PD)
const {
215 return {
false,
nullptr};
220 return {
false,
nullptr};
228 auto IsUnsafePtr = isUnsafePtr(QT, ignoreARC);
229 return {IsUnsafePtr && *IsUnsafePtr && !HasSafeAttr, PropType};
232 bool shouldSkipDecl(
const RecordDecl *RD)
const {
245 if (!RDLocation.isValid())
249 if (Kind != TagTypeKind::Struct && Kind != TagTypeKind::Class &&
250 Kind != TagTypeKind::Union)
254 if (BR->getSourceManager().isInSystemHeader(RDLocation))
259 auto CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(RD);
266 template <
typename DeclType,
typename Po
inteeType,
typename ParentDeclType>
267 void reportBug(
const DeclType *
Member,
const Type *MemberType,
268 const PointeeType *Pointee,
269 const ParentDeclType *ClassCXXRD)
const {
274 SmallString<100> Buf;
275 llvm::raw_svector_ostream Os(Buf);
281 Os <<
"Instance variable ";
283 Os <<
"Member variable ";
288 if (
Member->getType().getTypePtrOrNull() == MemberType)
291 Os <<
" contains a ";
292 if (printPointer(Os, MemberType) == PrintDeclKind::Pointer) {
299 PathDiagnosticLocation BSLoc(
Member->getSourceRange().getBegin(),
300 BR->getSourceManager());
301 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
303 if (
auto *EnclosingCtx =
Member->getDeclContext())
305 BR->emitReport(std::move(
Report));
308 enum class PrintDeclKind { Pointee,
Pointer };
309 PrintDeclKind printPointer(llvm::raw_svector_ostream &Os,
310 const Type *
T)
const {
314 T->
getAs<TypedefType>()) {
315 Os << Model->typeName() <<
" ";
316 return PrintDeclKind::Pointer;
320 Os << (IsPtr ?
"raw pointer" :
"reference") <<
" to " << Model->typeName()
322 return PrintDeclKind::Pointee;
326class NoUncountedMemberChecker final :
public RawPtrRefMemberChecker {
328 NoUncountedMemberChecker()
329 : RawPtrRefMemberChecker(
"Member variable is a raw-pointer/reference to "
330 "reference-countable type",
334class NoUncheckedPtrMemberChecker final :
public RawPtrRefMemberChecker {
336 NoUncheckedPtrMemberChecker()
337 : RawPtrRefMemberChecker(
"Member variable is a raw-pointer/reference to "
338 "checked-pointer capable type",
342class NoUnretainedMemberChecker final :
public RawPtrRefMemberChecker {
344 NoUnretainedMemberChecker()
345 : RawPtrRefMemberChecker(
"Member variable is a raw-pointer/reference to "
356bool ento::shouldRegisterNoUncountedMemberChecker(
const CheckerManager &Mgr) {
360void ento::registerNoUncheckedPtrMemberChecker(
CheckerManager &Mgr) {
364bool ento::shouldRegisterNoUncheckedPtrMemberChecker(
369void ento::registerNoUnretainedMemberChecker(
CheckerManager &Mgr) {
373bool ento::shouldRegisterNoUnretainedMemberChecker(
const CheckerManager &Mgr) {
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the SourceManager interface.
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
static Decl * castFromDeclContext(const DeclContext *)
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.
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
std::unique_ptr< PtrRefSafetyModel > makeCheckedPtrSafetyModel()
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
void printQuotedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
DynamicRecursiveASTVisitorBase< true > ConstDynamicRecursiveASTVisitor
std::optional< bool > isUnsafePtrForStorage(const PtrRefSafetyModel &Model, QualType T, bool IgnoreARC=false)
Applies the memory-management exemptions that hold for a variable, member, or lambda capture (but not...
const FunctionProtoType * T
bool isSmartPtr(const CXXRecordDecl *R)
ObjCInterfaceDecl * getObjCDeclFromObjCPtr(const Type *TypePtr)
std::unique_ptr< PtrRefSafetyModel > makeRefPtrSafetyModel()
@ Interface
The "__interface" keyword introduces the elaborated-type-specifier.
std::unique_ptr< PtrRefSafetyModel > makeRetainPtrSafetyModel()