diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp | 115 |
1 files changed, 95 insertions, 20 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp index 963f598..593e6e3 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp @@ -31,12 +31,16 @@ private: BugType Bug; mutable BugReporter *BR; +protected: + mutable std::optional<RetainTypeChecker> RTC; + public: RawPtrRefMemberChecker(const char *description) : Bug(this, description, "WebKit coding guidelines") {} virtual std::optional<bool> - isPtrCompatible(const clang::CXXRecordDecl *) const = 0; + isPtrCompatible(const clang::QualType, + const clang::CXXRecordDecl *R) const = 0; virtual bool isPtrCls(const clang::CXXRecordDecl *) const = 0; virtual const char *typeName() const = 0; virtual const char *invariant() const = 0; @@ -57,6 +61,12 @@ public: ShouldVisitImplicitCode = false; } + bool VisitTypedefDecl(const TypedefDecl *TD) override { + if (Checker->RTC) + Checker->RTC->visitTypedef(TD); + return true; + } + bool VisitRecordDecl(const RecordDecl *RD) override { Checker->visitRecordDecl(RD); return true; @@ -69,6 +79,8 @@ public: }; LocalVisitor visitor(this); + if (RTC) + RTC->visitTranslationUnitDecl(TUD); visitor.TraverseDecl(TUD); } @@ -77,16 +89,22 @@ public: return; for (auto *Member : RD->fields()) { - const Type *MemberType = Member->getType().getTypePtrOrNull(); + auto QT = Member->getType(); + const Type *MemberType = QT.getTypePtrOrNull(); if (!MemberType) continue; if (auto *MemberCXXRD = MemberType->getPointeeCXXRecordDecl()) { - // If we don't see the definition we just don't know. - if (MemberCXXRD->hasDefinition()) { - std::optional<bool> isRCAble = isPtrCompatible(MemberCXXRD); - if (isRCAble && *isRCAble) - reportBug(Member, MemberType, MemberCXXRD, RD); + std::optional<bool> IsCompatible = isPtrCompatible(QT, MemberCXXRD); + if (IsCompatible && *IsCompatible) + reportBug(Member, MemberType, MemberCXXRD, RD); + } else { + std::optional<bool> IsCompatible = isPtrCompatible(QT, nullptr); + auto *PointeeType = MemberType->getPointeeType().getTypePtrOrNull(); + if (IsCompatible && *IsCompatible) { + auto *Desugared = PointeeType->getUnqualifiedDesugaredType(); + if (auto *ObjCType = dyn_cast_or_null<ObjCInterfaceType>(Desugared)) + reportBug(Member, MemberType, ObjCType->getDecl(), RD); } } } @@ -107,11 +125,12 @@ public: void visitIvarDecl(const ObjCContainerDecl *CD, const ObjCIvarDecl *Ivar) const { - const Type *IvarType = Ivar->getType().getTypePtrOrNull(); + auto QT = Ivar->getType(); + const Type *IvarType = QT.getTypePtrOrNull(); if (!IvarType) return; if (auto *IvarCXXRD = IvarType->getPointeeCXXRecordDecl()) { - std::optional<bool> IsCompatible = isPtrCompatible(IvarCXXRD); + std::optional<bool> IsCompatible = isPtrCompatible(QT, IvarCXXRD); if (IsCompatible && *IsCompatible) reportBug(Ivar, IvarType, IvarCXXRD, CD); } @@ -151,13 +170,13 @@ public: return false; } - template <typename DeclType, typename ParentDeclType> + template <typename DeclType, typename PointeeType, typename ParentDeclType> void reportBug(const DeclType *Member, const Type *MemberType, - const CXXRecordDecl *MemberCXXRD, + const PointeeType *Pointee, const ParentDeclType *ClassCXXRD) const { assert(Member); assert(MemberType); - assert(MemberCXXRD); + assert(Pointee); SmallString<100> Buf; llvm::raw_svector_ostream Os(Buf); @@ -169,10 +188,13 @@ public: printQuotedName(Os, Member); Os << " in "; printQuotedQualifiedName(Os, ClassCXXRD); - Os << " is a " - << (isa<PointerType>(MemberType) ? "raw pointer" : "reference") << " to " - << typeName() << " "; - printQuotedQualifiedName(Os, MemberCXXRD); + Os << " is a "; + if (printPointer(Os, MemberType) == PrintDeclKind::Pointer) { + auto Typedef = MemberType->getAs<TypedefType>(); + assert(Typedef); + printQuotedQualifiedName(Os, Typedef->getDecl()); + } else + printQuotedQualifiedName(Os, Pointee); Os << "; " << invariant() << "."; PathDiagnosticLocation BSLoc(Member->getSourceRange().getBegin(), @@ -181,6 +203,15 @@ public: Report->addRange(Member->getSourceRange()); BR->emitReport(std::move(Report)); } + + enum class PrintDeclKind { Pointee, Pointer }; + virtual PrintDeclKind printPointer(llvm::raw_svector_ostream &Os, + const Type *T) const { + T = T->getUnqualifiedDesugaredType(); + bool IsPtr = isa<PointerType>(T) || isa<ObjCObjectPointerType>(T); + Os << (IsPtr ? "raw pointer" : "reference") << " to " << typeName() << " "; + return PrintDeclKind::Pointee; + } }; class NoUncountedMemberChecker final : public RawPtrRefMemberChecker { @@ -190,8 +221,9 @@ public: "reference-countable type") {} std::optional<bool> - isPtrCompatible(const clang::CXXRecordDecl *R) const final { - return isRefCountable(R); + isPtrCompatible(const clang::QualType, + const clang::CXXRecordDecl *R) const final { + return R && isRefCountable(R); } bool isPtrCls(const clang::CXXRecordDecl *R) const final { @@ -212,8 +244,9 @@ public: "checked-pointer capable type") {} std::optional<bool> - isPtrCompatible(const clang::CXXRecordDecl *R) const final { - return isCheckedPtrCapable(R); + isPtrCompatible(const clang::QualType, + const clang::CXXRecordDecl *R) const final { + return R && isCheckedPtrCapable(R); } bool isPtrCls(const clang::CXXRecordDecl *R) const final { @@ -228,6 +261,40 @@ public: } }; +class NoUnretainedMemberChecker final : public RawPtrRefMemberChecker { +public: + NoUnretainedMemberChecker() + : RawPtrRefMemberChecker("Member variable is a raw-pointer/reference to " + "retainable type") { + RTC = RetainTypeChecker(); + } + + std::optional<bool> + isPtrCompatible(const clang::QualType QT, + const clang::CXXRecordDecl *) const final { + return RTC->isUnretained(QT); + } + + bool isPtrCls(const clang::CXXRecordDecl *R) const final { + return isRetainPtr(R); + } + + const char *typeName() const final { return "retainable type"; } + + const char *invariant() const final { + return "member variables must be a RetainPtr"; + } + + PrintDeclKind printPointer(llvm::raw_svector_ostream &Os, + const Type *T) const final { + if (!isa<ObjCObjectPointerType>(T) && T->getAs<TypedefType>()) { + Os << typeName() << " "; + return PrintDeclKind::Pointer; + } + return RawPtrRefMemberChecker::printPointer(Os, T); + } +}; + } // namespace void ento::registerNoUncountedMemberChecker(CheckerManager &Mgr) { @@ -246,3 +313,11 @@ bool ento::shouldRegisterNoUncheckedPtrMemberChecker( const CheckerManager &Mgr) { return true; } + +void ento::registerNoUnretainedMemberChecker(CheckerManager &Mgr) { + Mgr.registerChecker<NoUnretainedMemberChecker>(); +} + +bool ento::shouldRegisterNoUnretainedMemberChecker(const CheckerManager &Mgr) { + return true; +} |