@@ -31,12 +31,16 @@ class RawPtrRefMemberChecker
3131 BugType Bug;
3232 mutable BugReporter *BR;
3333
34+ protected:
35+ mutable std::optional<RetainTypeChecker> RTC;
36+
3437public:
3538 RawPtrRefMemberChecker (const char *description)
3639 : Bug(this , description, " WebKit coding guidelines" ) {}
3740
3841 virtual std::optional<bool >
39- isPtrCompatible (const clang::CXXRecordDecl *) const = 0 ;
42+ isPtrCompatible (const clang::QualType,
43+ const clang::CXXRecordDecl *R) const = 0 ;
4044 virtual bool isPtrCls (const clang::CXXRecordDecl *) const = 0;
4145 virtual const char *typeName () const = 0;
4246 virtual const char *invariant () const = 0;
@@ -57,6 +61,12 @@ class RawPtrRefMemberChecker
5761 ShouldVisitImplicitCode = false ;
5862 }
5963
64+ bool VisitTypedefDecl (const TypedefDecl *TD) override {
65+ if (Checker->RTC )
66+ Checker->RTC ->visitTypedef (TD);
67+ return true ;
68+ }
69+
6070 bool VisitRecordDecl (const RecordDecl *RD) override {
6171 Checker->visitRecordDecl (RD);
6272 return true ;
@@ -69,6 +79,8 @@ class RawPtrRefMemberChecker
6979 };
7080
7181 LocalVisitor visitor (this );
82+ if (RTC)
83+ RTC->visitTranslationUnitDecl (TUD);
7284 visitor.TraverseDecl (TUD);
7385 }
7486
@@ -77,16 +89,22 @@ class RawPtrRefMemberChecker
7789 return ;
7890
7991 for (auto *Member : RD->fields ()) {
80- const Type *MemberType = Member->getType ().getTypePtrOrNull ();
92+ auto QT = Member->getType ();
93+ const Type *MemberType = QT.getTypePtrOrNull ();
8194 if (!MemberType)
8295 continue ;
8396
8497 if (auto *MemberCXXRD = MemberType->getPointeeCXXRecordDecl ()) {
85- // If we don't see the definition we just don't know.
86- if (MemberCXXRD->hasDefinition ()) {
87- std::optional<bool > isRCAble = isPtrCompatible (MemberCXXRD);
88- if (isRCAble && *isRCAble)
89- reportBug (Member, MemberType, MemberCXXRD, RD);
98+ std::optional<bool > IsCompatible = isPtrCompatible (QT, MemberCXXRD);
99+ if (IsCompatible && *IsCompatible)
100+ reportBug (Member, MemberType, MemberCXXRD, RD);
101+ } else {
102+ std::optional<bool > IsCompatible = isPtrCompatible (QT, nullptr );
103+ auto *PointeeType = MemberType->getPointeeType ().getTypePtrOrNull ();
104+ if (IsCompatible && *IsCompatible) {
105+ auto *Desugared = PointeeType->getUnqualifiedDesugaredType ();
106+ if (auto *ObjCType = dyn_cast_or_null<ObjCInterfaceType>(Desugared))
107+ reportBug (Member, MemberType, ObjCType->getDecl (), RD);
90108 }
91109 }
92110 }
@@ -107,11 +125,12 @@ class RawPtrRefMemberChecker
107125
108126 void visitIvarDecl (const ObjCContainerDecl *CD,
109127 const ObjCIvarDecl *Ivar) const {
110- const Type *IvarType = Ivar->getType ().getTypePtrOrNull ();
128+ auto QT = Ivar->getType ();
129+ const Type *IvarType = QT.getTypePtrOrNull ();
111130 if (!IvarType)
112131 return ;
113132 if (auto *IvarCXXRD = IvarType->getPointeeCXXRecordDecl ()) {
114- std::optional<bool > IsCompatible = isPtrCompatible (IvarCXXRD);
133+ std::optional<bool > IsCompatible = isPtrCompatible (QT, IvarCXXRD);
115134 if (IsCompatible && *IsCompatible)
116135 reportBug (Ivar, IvarType, IvarCXXRD, CD);
117136 }
@@ -151,13 +170,13 @@ class RawPtrRefMemberChecker
151170 return false ;
152171 }
153172
154- template <typename DeclType, typename ParentDeclType>
173+ template <typename DeclType, typename PointeeType, typename ParentDeclType>
155174 void reportBug (const DeclType *Member, const Type *MemberType,
156- const CXXRecordDecl *MemberCXXRD ,
175+ const PointeeType *Pointee ,
157176 const ParentDeclType *ClassCXXRD) const {
158177 assert (Member);
159178 assert (MemberType);
160- assert (MemberCXXRD );
179+ assert (Pointee );
161180
162181 SmallString<100 > Buf;
163182 llvm::raw_svector_ostream Os (Buf);
@@ -169,10 +188,13 @@ class RawPtrRefMemberChecker
169188 printQuotedName (Os, Member);
170189 Os << " in " ;
171190 printQuotedQualifiedName (Os, ClassCXXRD);
172- Os << " is a "
173- << (isa<PointerType>(MemberType) ? " raw pointer" : " reference" ) << " to "
174- << typeName () << " " ;
175- printQuotedQualifiedName (Os, MemberCXXRD);
191+ Os << " is a " ;
192+ if (printPointer (Os, MemberType) == PrintDeclKind::Pointer) {
193+ auto Typedef = MemberType->getAs <TypedefType>();
194+ assert (Typedef);
195+ printQuotedQualifiedName (Os, Typedef->getDecl ());
196+ } else
197+ printQuotedQualifiedName (Os, Pointee);
176198 Os << " ; " << invariant () << " ." ;
177199
178200 PathDiagnosticLocation BSLoc (Member->getSourceRange ().getBegin (),
@@ -181,6 +203,15 @@ class RawPtrRefMemberChecker
181203 Report->addRange (Member->getSourceRange ());
182204 BR->emitReport (std::move (Report));
183205 }
206+
207+ enum class PrintDeclKind { Pointee, Pointer };
208+ virtual PrintDeclKind printPointer (llvm::raw_svector_ostream &Os,
209+ const Type *T) const {
210+ T = T->getUnqualifiedDesugaredType ();
211+ bool IsPtr = isa<PointerType>(T) || isa<ObjCObjectPointerType>(T);
212+ Os << (IsPtr ? " raw pointer" : " reference" ) << " to " << typeName () << " " ;
213+ return PrintDeclKind::Pointee;
214+ }
184215};
185216
186217class NoUncountedMemberChecker final : public RawPtrRefMemberChecker {
@@ -190,8 +221,9 @@ class NoUncountedMemberChecker final : public RawPtrRefMemberChecker {
190221 " reference-countable type" ) {}
191222
192223 std::optional<bool >
193- isPtrCompatible (const clang::CXXRecordDecl *R) const final {
194- return isRefCountable (R);
224+ isPtrCompatible (const clang::QualType,
225+ const clang::CXXRecordDecl *R) const final {
226+ return R && isRefCountable (R);
195227 }
196228
197229 bool isPtrCls (const clang::CXXRecordDecl *R) const final {
@@ -212,8 +244,9 @@ class NoUncheckedPtrMemberChecker final : public RawPtrRefMemberChecker {
212244 " checked-pointer capable type" ) {}
213245
214246 std::optional<bool >
215- isPtrCompatible (const clang::CXXRecordDecl *R) const final {
216- return isCheckedPtrCapable (R);
247+ isPtrCompatible (const clang::QualType,
248+ const clang::CXXRecordDecl *R) const final {
249+ return R && isCheckedPtrCapable (R);
217250 }
218251
219252 bool isPtrCls (const clang::CXXRecordDecl *R) const final {
@@ -228,6 +261,40 @@ class NoUncheckedPtrMemberChecker final : public RawPtrRefMemberChecker {
228261 }
229262};
230263
264+ class NoUnretainedMemberChecker final : public RawPtrRefMemberChecker {
265+ public:
266+ NoUnretainedMemberChecker ()
267+ : RawPtrRefMemberChecker(" Member variable is a raw-pointer/reference to "
268+ " retainable type" ) {
269+ RTC = RetainTypeChecker ();
270+ }
271+
272+ std::optional<bool >
273+ isPtrCompatible (const clang::QualType QT,
274+ const clang::CXXRecordDecl *) const final {
275+ return RTC->isUnretained (QT);
276+ }
277+
278+ bool isPtrCls (const clang::CXXRecordDecl *R) const final {
279+ return isRetainPtr (R);
280+ }
281+
282+ const char *typeName () const final { return " retainable type" ; }
283+
284+ const char *invariant () const final {
285+ return " member variables must be a RetainPtr" ;
286+ }
287+
288+ PrintDeclKind printPointer (llvm::raw_svector_ostream &Os,
289+ const Type *T) const final {
290+ if (!isa<ObjCObjectPointerType>(T) && T->getAs <TypedefType>()) {
291+ Os << typeName () << " " ;
292+ return PrintDeclKind::Pointer;
293+ }
294+ return RawPtrRefMemberChecker::printPointer (Os, T);
295+ }
296+ };
297+
231298} // namespace
232299
233300void ento::registerNoUncountedMemberChecker (CheckerManager &Mgr) {
@@ -246,3 +313,11 @@ bool ento::shouldRegisterNoUncheckedPtrMemberChecker(
246313 const CheckerManager &Mgr) {
247314 return true ;
248315}
316+
317+ void ento::registerNoUnretainedMemberChecker (CheckerManager &Mgr) {
318+ Mgr.registerChecker <NoUnretainedMemberChecker>();
319+ }
320+
321+ bool ento::shouldRegisterNoUnretainedMemberChecker (const CheckerManager &Mgr) {
322+ return true ;
323+ }
0 commit comments