1//=======- RawPtrRefSafetyModel.cpp -----------------------------*- C++ -*-==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "RawPtrRefSafetyModel.h"
10#include "ASTUtils.h"
11#include "clang/AST/Decl.h"
12#include "clang/AST/ExprObjC.h"
13#include "clang/AST/Type.h"
14#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
15#include "clang/Basic/SourceManager.h"
16
17using namespace clang;
18
19namespace {
20
21class RefCountedSafetyModel : public PtrRefSafetyModel {
22public:
23 std::optional<bool> isUnsafeType(QualType QT) const override {
24 return isUncounted(T: QT);
25 }
26 std::optional<bool> isUnsafePtr(QualType QT, bool) const override {
27 return isUncountedPtr(T: QT.getCanonicalType());
28 }
29 bool isSafePtr(const CXXRecordDecl *Record) const override {
30 return isRefCounted(Class: Record) || isCheckedPtr(Class: Record);
31 }
32 bool isSafePtrType(QualType T) const override {
33 return isRefOrCheckedPtrType(T);
34 }
35 bool isPtrType(const std::string &Name) const override {
36 return isRefType(Name);
37 }
38 const char *typeName() const override { return "RefPtr-capable type"; }
39};
40
41class CheckedPtrSafetyModel : public PtrRefSafetyModel {
42public:
43 std::optional<bool> isUnsafeType(QualType QT) const override {
44 return isUnchecked(T: QT);
45 }
46 std::optional<bool> isUnsafePtr(QualType QT, bool) const override {
47 return isUncheckedPtr(T: QT.getCanonicalType());
48 }
49 bool isSafePtr(const CXXRecordDecl *Record) const override {
50 return isRefCounted(Class: Record) || isCheckedPtr(Class: Record);
51 }
52 bool isSafePtrType(QualType T) const override {
53 return isRefOrCheckedPtrType(T);
54 }
55 bool isPtrType(const std::string &Name) const override {
56 return isCheckedPtr(Name);
57 }
58 bool isSafeExpr(const Expr *E) const override {
59 return isExprToGetCheckedPtrCapableMember(E);
60 }
61 const char *typeName() const override { return "CheckedPtr-capable type"; }
62};
63
64class RetainPtrSafetyModel : public PtrRefSafetyModel {
65 mutable RetainTypeChecker RTC;
66
67public:
68 std::optional<bool> isUnsafeType(QualType QT) const override {
69 return RTC.isUnretained(QT);
70 }
71 std::optional<bool> isUnsafePtr(QualType QT, bool IgnoreARC) const override {
72 return RTC.isUnretained(QT, ignoreARC: IgnoreARC);
73 }
74 bool isSafePtr(const CXXRecordDecl *Record) const override {
75 return isRetainPtrOrOSPtr(Class: Record);
76 }
77 bool isSafePtrType(QualType T) const override {
78 return isRetainPtrOrOSPtrType(T);
79 }
80 bool isPtrType(const std::string &Name) const override {
81 return isRetainPtrOrOSPtr(Name);
82 }
83 bool isSafeExpr(const Expr *E) const override {
84 return ento::cocoa::isCocoaObjectRef(T: E->getType()) &&
85 isa<ObjCMessageExpr>(Val: E);
86 }
87 bool isSafeDecl(const Decl *D, const SourceManager &SM) const override {
88 // Treat NS/CF globals in system header as immortal.
89 return SM.isInSystemHeader(Loc: D->getLocation());
90 }
91 const char *typeName() const override { return "RetainPtr-capable type"; }
92 RetainTypeChecker *retainTypeChecker() const override { return &RTC; }
93};
94
95} // namespace
96
97std::optional<bool> clang::isUnsafePtrForStorage(const PtrRefSafetyModel &Model,
98 QualType T, bool IgnoreARC) {
99 // A __strong / __weak Objective-C storage location is memory managed and
100 // thus safe. This exemption applies to variables/members/captures but not to
101 // call arguments, so it lives here rather than in the policy itself.
102 if (Model.retainTypeChecker() && T.hasStrongOrWeakObjCLifetime())
103 return false;
104 return Model.isUnsafePtr(QT: T, IgnoreARC);
105}
106
107std::unique_ptr<PtrRefSafetyModel> clang::makeRefPtrSafetyModel() {
108 return std::make_unique<RefCountedSafetyModel>();
109}
110
111std::unique_ptr<PtrRefSafetyModel> clang::makeCheckedPtrSafetyModel() {
112 return std::make_unique<CheckedPtrSafetyModel>();
113}
114
115std::unique_ptr<PtrRefSafetyModel> clang::makeRetainPtrSafetyModel() {
116 return std::make_unique<RetainPtrSafetyModel>();
117}
118