1//=======- PtrTypesSemantics.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#ifndef LLVM_CLANG_ANALYZER_WEBKIT_PTRTYPESEMANTICS_H
10#define LLVM_CLANG_ANALYZER_WEBKIT_PTRTYPESEMANTICS_H
11
12#include "llvm/ADT/APInt.h"
13#include "llvm/ADT/DenseMap.h"
14#include "llvm/ADT/DenseSet.h"
15#include "llvm/ADT/PointerUnion.h"
16#include "llvm/ADT/SmallVector.h"
17#include <optional>
18#include <string>
19
20namespace clang {
21class CXXBaseSpecifier;
22class CXXMethodDecl;
23class CXXRecordDecl;
24class Decl;
25class FieldDecl;
26class FunctionDecl;
27class NamedDecl;
28class QualType;
29class RecordType;
30class Stmt;
31class TranslationUnitDecl;
32class Type;
33class TypedefDecl;
34class VarDecl;
35
36// Ref-countability of a type is implicitly defined by Ref<T> and RefPtr<T>
37// implementation. It can be modeled as: type T having public methods ref() and
38// deref()
39
40// In WebKit there are two ref-counted templated smart pointers: RefPtr<T> and
41// Ref<T>.
42
43/// \returns CXXRecordDecl of the base if the type has ref as a public method,
44/// nullptr if not, std::nullopt if inconclusive.
45std::optional<const clang::CXXRecordDecl *>
46hasPublicMethodInBase(const CXXBaseSpecifier *Base,
47 llvm::StringRef NameToMatch);
48
49/// \returns true if \p Class is ref-countable, false if not, std::nullopt if
50/// inconclusive.
51std::optional<bool> isRefCountable(const clang::CXXRecordDecl *Class);
52
53/// \returns true if \p Class is checked-pointer compatible, false if not,
54/// std::nullopt if inconclusive.
55std::optional<bool> isCheckedPtrCapable(const clang::CXXRecordDecl *Class);
56
57/// \returns true if \p Class implements the CanBorrow protocol, meaning a
58/// Borrow<T> can be taken on it, false if not, std::nullopt if inconclusive.
59std::optional<bool> isBorrowable(const clang::CXXRecordDecl *Class);
60
61/// \returns true if \p Class is a Borrow<T>, false if not.
62bool isBorrow(const clang::CXXRecordDecl *Class);
63
64/// \returns true if \p T is a Borrow<T>.
65bool isBorrowType(const clang::QualType T);
66
67/// \returns the innermost type reached by stripping every pointer/reference
68/// layer from \p T; \p T itself if it has none; a null type if \p T is null.
69clang::QualType pointeeType(clang::QualType T);
70
71/// \returns the type a Borrow<T> specialization \p T borrows, or a null type
72/// if \p T is not a template specialization whose first argument is a type.
73clang::QualType borrowedType(clang::QualType T);
74
75/// \returns true if a value of type \p T is a pointer/reference/view.
76bool isView(const clang::QualType T);
77
78/// \returns true if \p Class declares reference semantics structurally: it is
79/// annotated [[gsl::Pointer]] (explicitly, or by Sema's inference for
80/// standard types), derives from std::ranges::view_interface, is a standard
81/// iterator adaptor, or is nested inside such a class, as the iterators of
82/// standard views are.
83bool isStdView(const clang::CXXRecordDecl *Class);
84
85/// \returns true if \p Class is ref-counted, false if not.
86bool isRefCounted(const clang::CXXRecordDecl *Class);
87
88/// \returns true if \p Class is a CheckedPtr / CheckedRef, false if not.
89bool isCheckedPtr(const clang::CXXRecordDecl *Class);
90
91/// \returns true if \p Class is a RetainPtr, false if not.
92bool isRetainPtrOrOSPtr(const clang::CXXRecordDecl *Class);
93
94/// \returns true if \p Class is a weak smart pointer (WeakPtr, InlineWeakPtr,
95/// etc...), false if not.
96bool isWeakPtr(const clang::CXXRecordDecl *Class);
97
98/// \returns true if \p Class is a smart pointer (RefPtr, WeakPtr, etc...),
99/// false if not.
100bool isSmartPtr(const clang::CXXRecordDecl *Class);
101
102/// \returns true if \p Class is ref-countable AND not ref-counted, false if
103/// not, std::nullopt if inconclusive.
104std::optional<bool> isUncounted(const clang::QualType T);
105
106/// \returns true if \p Class is CheckedPtr capable AND not checked, false if
107/// not, std::nullopt if inconclusive.
108std::optional<bool> isUnchecked(const clang::QualType T);
109
110/// An inter-procedural analysis facility that detects CF types with the
111/// underlying pointer type.
112class RetainTypeChecker {
113 llvm::DenseMap<const RecordType *, const TypedefDecl *> CFPointees;
114 llvm::DenseSet<const Type *> RecordlessTypes;
115 bool IsARCEnabled{false};
116 bool DefaultSynthProperties{true};
117
118public:
119 void visitTranslationUnitDecl(const TranslationUnitDecl *);
120 void visitTypedef(const TypedefDecl *);
121 bool isUnretained(const QualType, bool ignoreARC = false);
122 bool isARCEnabled() const { return IsARCEnabled; }
123 bool defaultSynthProperties() const { return DefaultSynthProperties; }
124 const TypedefDecl *getCanonicalDecl(QualType);
125};
126
127/// \returns true if \p Class is ref-countable AND not ref-counted, false if
128/// not, std::nullopt if inconclusive.
129std::optional<bool> isUncounted(const clang::CXXRecordDecl* Class);
130
131/// \returns true if \p Class is CheckedPtr capable AND not checked, false if
132/// not, std::nullopt if inconclusive.
133std::optional<bool> isUnchecked(const clang::CXXRecordDecl *Class);
134
135/// \returns true if \p T is either a raw pointer or reference to an uncounted
136/// class, false if not, std::nullopt if inconclusive.
137std::optional<bool> isUncountedPtr(const clang::QualType T);
138
139/// \returns true if \p T is either a raw pointer or reference to an unchecked
140/// class, false if not, std::nullopt if inconclusive.
141std::optional<bool> isUncheckedPtr(const clang::QualType T);
142
143/// \returns true if \p T is a RefPtr, Ref, CheckedPtr, CheckedRef, or its
144/// variant, false if not.
145bool isRefOrCheckedPtrType(const clang::QualType T);
146
147/// \returns true if \p T is a RetainPtr, false if not.
148bool isRetainPtrOrOSPtrType(const clang::QualType T);
149
150/// \returns true if \p T is a RefPtr, Ref, CheckedPtr, CheckedRef, or
151/// unique_ptr, false if not.
152bool isOwnerPtrType(const clang::QualType T);
153
154/// \returns true if \p F creates ref-countable object from uncounted parameter,
155/// false if not.
156bool isCtorOfRefCounted(const clang::FunctionDecl *F);
157
158/// \returns true if \p F creates checked ptr object from uncounted parameter,
159/// false if not.
160bool isCtorOfCheckedPtr(const clang::FunctionDecl *F);
161
162/// \returns true if \p F creates ref-countable or checked ptr object from
163/// uncounted parameter, false if not.
164bool isCtorOfSafePtr(const clang::FunctionDecl *F);
165
166/// \returns true if \p F is std::move or WTF::move.
167bool isStdOrWTFMove(const clang::FunctionDecl *F);
168
169/// \returns true if \p Name is RefPtr, Ref, or its variant, false if not.
170bool isRefType(const std::string &Name);
171
172/// \returns true if \p Name is CheckedRef or CheckedPtr, false if not.
173bool isCheckedPtr(const std::string &Name);
174
175/// \returns true if \p Name is Borrow, false if not.
176bool isBorrow(const std::string &Name);
177
178/// \returns true if \p Name is RetainPtr or its variant, false if not.
179bool isRetainPtrOrOSPtr(const std::string &Name);
180
181/// \returns true if \p Name is an owning smart pointer such as Ref, CheckedPtr,
182/// and unique_ptr.
183bool isOwnerPtr(const std::string &Name);
184
185/// \returns true if \p Name is unique_ptr, UniqueRef, or LazyUniqueRef.
186bool isUniquePtr(const std::string &Name);
187
188/// \returns true if \p Name is a smart pointer type name, false if not.
189bool isSmartPtrClass(const std::string &Name);
190
191/// \returns true if \p M is getter of a ref-counted class, false if not.
192std::optional<bool> isGetterOfSafePtr(const clang::CXXMethodDecl *Method);
193
194/// \returns true if \p M is a getter of unique_ptr, UniqueRef, or
195/// LazyUniqueRef, false if not.
196bool isGetterOfUniquePtr(const clang::CXXMethodDecl *Method);
197
198/// \returns true if \p F is a conversion between ref-countable or ref-counted
199/// pointer types.
200bool isPtrConversion(const FunctionDecl *F);
201
202/// \returns true if \p F's return type is annotated with
203/// [[clang::annotate_type("webkit.nodelete")]].
204bool isNoDeleteFunction(const FunctionDecl *F);
205
206/// \returns true if \p F is a builtin function which is considered trivial.
207bool isTrivialBuiltinFunction(const FunctionDecl *F);
208
209/// \returns true if \p F is a static singleton function.
210bool isSingleton(const NamedDecl *F);
211
212/// Explains why TrivialFunctionAnalysis rejected a statement, so that a
213/// diagnostic can blame the code that is actually responsible.
214struct NonTrivialityReason {
215 /// The innermost non-trivial statement inside the analyzed function's own
216 /// body. Without this, a diagnostic would have to blame the whole enclosing
217 /// statement, which often reads as an accusation against an innocent callee
218 /// that merely happens to appear first, e.g. the std::min in
219 /// `x = std::min(a, unsafe())`.
220 const Stmt *OffendingStmt = nullptr;
221
222 /// One function in the chain of calls that leads from OffendingStmt to the
223 /// code that could destruct an object.
224 struct Frame {
225 const FunctionDecl *Callee = nullptr;
226 /// The innermost non-trivial statement inside Callee's body. Null when
227 /// Callee has no visible definition, or is rejected without looking at its
228 /// body, e.g. because it is virtual or takes a parameter by value that
229 /// could destruct an object.
230 const Stmt *OffendingStmt = nullptr;
231 };
232
233 /// The callees that could not be proven free of destruction, outermost
234 /// first: the first frame is called from OffendingStmt, each subsequent frame
235 /// is called from the previous frame's OffendingStmt, and the last frame is
236 /// where the destruction actually happens or a function without a visible
237 /// definition. Empty when OffendingStmt destructs an object by itself, e.g.
238 /// a delete expression or a local variable with a non-trivial destructor.
239 llvm::SmallVector<Frame> CallStack;
240};
241
242/// An inter-procedural analysis facility that detects functions with "trivial"
243/// behavior with respect to reference counting, such as simple field getters.
244class TrivialFunctionAnalysis {
245public:
246 /// \returns true if \p D is a "trivial" function.
247 bool isTrivial(const Decl *D) const { return isTrivialImpl(D, Cache&: TheCache); }
248 bool isTrivial(const Stmt *S) const { return isTrivialImpl(S, Cache&: TheCache); }
249 bool hasTrivialDtor(const VarDecl *VD) const {
250 return hasTrivialDtorImpl(VD, Cache&: TheCache);
251 }
252 const FieldDecl *fieldWithNonTrivialCtor(const CXXRecordDecl *RD) const {
253 return fieldWithNonTrivialCtorImpl(RD, Cache&: TheCache);
254 }
255 const FieldDecl *fieldWithNonTrivialDtor(const CXXRecordDecl *RD) const {
256 return fieldWithNonTrivialDtorImpl(RD, Cache&: TheCache);
257 }
258
259 /// \returns why \p S is not trivial. Runs on a private, empty cache because
260 /// pinpointing the root cause requires descending into callees that a shared
261 /// cache would short-circuit. Only call this when about to emit a diagnostic.
262 static NonTrivialityReason computeReason(const Stmt *S);
263
264private:
265 friend class TrivialFunctionAnalysisVisitor;
266
267 using CacheTy =
268 llvm::DenseMap<llvm::PointerUnion<const Decl *, const Stmt *>, bool>;
269 mutable CacheTy TheCache{};
270
271 static bool isTrivialImpl(const Decl *D, CacheTy &Cache);
272 static bool isTrivialImpl(const Stmt *S, CacheTy &Cache);
273 static bool hasTrivialDtorImpl(const VarDecl *VD, CacheTy &Cache);
274 static const FieldDecl *fieldWithNonTrivialCtorImpl(const CXXRecordDecl *RD,
275 CacheTy &Cache);
276 static const FieldDecl *fieldWithNonTrivialDtorImpl(const CXXRecordDecl *RD,
277 CacheTy &Cache);
278};
279
280} // namespace clang
281
282#endif
283