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/Type.h"
13#include "clang/Basic/SourceManager.h"
14
15using namespace clang;
16
17namespace {
18
19class RefCountedSafetyModel : public PtrRefSafetyModel {
20public:
21 std::optional<bool> isUnsafeType(QualType QT) const override {
22 return isUncounted(T: QT);
23 }
24 std::optional<bool> isUnsafePtr(QualType QT, bool) const override {
25 return isUncountedPtr(T: QT.getCanonicalType());
26 }
27 bool isSafePtr(const CXXRecordDecl *Record) const override {
28 return isRefCounted(Class: Record) || isCheckedPtr(Class: Record);
29 }
30 bool isSafePtrType(QualType T) const override {
31 return isRefOrCheckedPtrType(T);
32 }
33 bool isPtrType(const std::string &Name) const override {
34 return isRefType(Name);
35 }
36 const char *typeName() const override { return "RefPtr-capable type"; }
37};
38
39class CheckedPtrSafetyModel : public PtrRefSafetyModel {
40public:
41 std::optional<bool> isUnsafeType(QualType QT) const override {
42 return isUnchecked(T: QT);
43 }
44 std::optional<bool> isUnsafePtr(QualType QT, bool) const override {
45 return isUncheckedPtr(T: QT.getCanonicalType());
46 }
47 bool isSafePtr(const CXXRecordDecl *Record) const override {
48 return isRefCounted(Class: Record) || isCheckedPtr(Class: Record);
49 }
50 bool isSafePtrType(QualType T) const override {
51 return isRefOrCheckedPtrType(T);
52 }
53 bool isPtrType(const std::string &Name) const override {
54 return isCheckedPtr(Name);
55 }
56 bool isSafeExpr(const Expr *E) const override {
57 return isExprToGetCheckedPtrCapableMember(E);
58 }
59 const char *typeName() const override { return "CheckedPtr-capable type"; }
60};
61
62class RetainPtrSafetyModel : public PtrRefSafetyModel {
63 mutable RetainTypeChecker RTC;
64
65public:
66 std::optional<bool> isUnsafeType(QualType QT) const override {
67 return RTC.isUnretained(QT);
68 }
69 std::optional<bool> isUnsafePtr(QualType QT, bool IgnoreARC) const override {
70 return RTC.isUnretained(QT, ignoreARC: IgnoreARC);
71 }
72 bool isSafePtr(const CXXRecordDecl *Record) const override {
73 return isRetainPtrOrOSPtr(Class: Record);
74 }
75 bool isSafePtrType(QualType T) const override {
76 return isRetainPtrOrOSPtrType(T);
77 }
78 bool isPtrType(const std::string &Name) const override {
79 return isRetainPtrOrOSPtr(Name);
80 }
81 bool isSafeDecl(const Decl *D, const SourceManager &SM) const override {
82 // Treat NS/CF globals in system header as immortal.
83 return SM.isInSystemHeader(Loc: D->getLocation());
84 }
85 const char *typeName() const override { return "RetainPtr-capable type"; }
86 RetainTypeChecker *retainTypeChecker() const override { return &RTC; }
87};
88
89} // namespace
90
91std::optional<bool> clang::isUnsafePtrForStorage(const PtrRefSafetyModel &Model,
92 QualType T, bool IgnoreARC) {
93 // A __strong / __weak Objective-C storage location is memory managed and
94 // thus safe. This exemption applies to variables/members/captures but not to
95 // call arguments, so it lives here rather than in the policy itself.
96 if (Model.retainTypeChecker() && T.hasStrongOrWeakObjCLifetime())
97 return false;
98 return Model.isUnsafePtr(QT: T, IgnoreARC);
99}
100
101std::unique_ptr<PtrRefSafetyModel> clang::makeRefPtrSafetyModel() {
102 return std::make_unique<RefCountedSafetyModel>();
103}
104
105std::unique_ptr<PtrRefSafetyModel> clang::makeCheckedPtrSafetyModel() {
106 return std::make_unique<CheckedPtrSafetyModel>();
107}
108
109std::unique_ptr<PtrRefSafetyModel> clang::makeRetainPtrSafetyModel() {
110 return std::make_unique<RetainPtrSafetyModel>();
111}
112