aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp115
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;
+}