@@ -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,16 @@ 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 "
213+ << typeName () << " " ;
214+ return PrintDeclKind::Pointee;
215+ }
184216};
185217
186218class NoUncountedMemberChecker final : public RawPtrRefMemberChecker {
@@ -190,8 +222,9 @@ class NoUncountedMemberChecker final : public RawPtrRefMemberChecker {
190222 " reference-countable type" ) {}
191223
192224 std::optional<bool >
193- isPtrCompatible (const clang::CXXRecordDecl *R) const final {
194- return isRefCountable (R);
225+ isPtrCompatible (const clang::QualType,
226+ const clang::CXXRecordDecl *R) const final {
227+ return R && isRefCountable (R);
195228 }
196229
197230 bool isPtrCls (const clang::CXXRecordDecl *R) const final {
@@ -212,8 +245,9 @@ class NoUncheckedPtrMemberChecker final : public RawPtrRefMemberChecker {
212245 " checked-pointer capable type" ) {}
213246
214247 std::optional<bool >
215- isPtrCompatible (const clang::CXXRecordDecl *R) const final {
216- return isCheckedPtrCapable (R);
248+ isPtrCompatible (const clang::QualType,
249+ const clang::CXXRecordDecl *R) const final {
250+ return R && isCheckedPtrCapable (R);
217251 }
218252
219253 bool isPtrCls (const clang::CXXRecordDecl *R) const final {
@@ -228,6 +262,40 @@ class NoUncheckedPtrMemberChecker final : public RawPtrRefMemberChecker {
228262 }
229263};
230264
265+ class NoUnretainedMemberChecker final : public RawPtrRefMemberChecker {
266+ public:
267+ NoUnretainedMemberChecker ()
268+ : RawPtrRefMemberChecker(" Member variable is a raw-pointer/reference to "
269+ " retainable type" ) {
270+ RTC = RetainTypeChecker ();
271+ }
272+
273+ std::optional<bool >
274+ isPtrCompatible (const clang::QualType QT,
275+ const clang::CXXRecordDecl *) const final {
276+ return RTC->isUnretained (QT);
277+ }
278+
279+ bool isPtrCls (const clang::CXXRecordDecl *R) const final {
280+ return isRetainPtr (R);
281+ }
282+
283+ const char *typeName () const final { return " retainable type" ; }
284+
285+ const char *invariant () const final {
286+ return " member variables must be a RetainPtr" ;
287+ }
288+
289+ PrintDeclKind printPointer (llvm::raw_svector_ostream& Os,
290+ const Type *T) const final {
291+ if (!isa<ObjCObjectPointerType>(T) && T->getAs <TypedefType>()) {
292+ Os << typeName () << " " ;
293+ return PrintDeclKind::Pointer;
294+ }
295+ return RawPtrRefMemberChecker::printPointer (Os, T);
296+ }
297+ };
298+
231299} // namespace
232300
233301void ento::registerNoUncountedMemberChecker (CheckerManager &Mgr) {
@@ -246,3 +314,12 @@ bool ento::shouldRegisterNoUncheckedPtrMemberChecker(
246314 const CheckerManager &Mgr) {
247315 return true ;
248316}
317+
318+ void ento::registerNoUnretainedMemberChecker (CheckerManager &Mgr) {
319+ Mgr.registerChecker <NoUnretainedMemberChecker>();
320+ }
321+
322+ bool ento::shouldRegisterNoUnretainedMemberChecker (
323+ const CheckerManager &Mgr) {
324+ return true ;
325+ }
0 commit comments