clang 24.0.0git
ASTUtils.cpp
Go to the documentation of this file.
1//=======- ASTUtils.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 "ASTUtils.h"
10#include "PtrTypesSemantics.h"
11#include "clang/AST/Attr.h"
12#include "clang/AST/Decl.h"
13#include "clang/AST/DeclCXX.h"
14#include "clang/AST/ExprCXX.h"
15#include "clang/AST/ExprObjC.h"
18#include <optional>
19#include <utility>
20
21namespace clang {
22
26
27static bool tryToFindPtrOriginImpl(
28 const Expr *E, bool StopAtFirstRefCountedObj, bool FollowLifetimeBound,
30 std::function<bool(const clang::QualType)> isSafePtrType,
31 std::function<bool(const clang::Decl *)> isSafeGlobalDecl,
32 std::function<bool(const clang::Expr *, bool /*IsSafe*/,
33 bool /*OriginDependsOnFullExpressionTemporary*/,
34 bool /*PtrIsLifetimeBoundToOrigin*/)>
35 callback,
36 bool OriginDependsOnFullExpressionTemporary,
37 bool PtrIsLifetimeBoundToOrigin);
38
39namespace {
40
41bool isStdViewType(QualType T) {
42 return !T.isNull() &&
43 isStdView(T.getNonReferenceType()->getAsCXXRecordDecl());
44}
45
46void appendPresumedBorrowSources(
47 const FunctionDecl *Callee, ArrayRef<const Expr *> Args,
48 SmallVectorImpl<const Expr *> &LifetimeBoundArgs) {
49 for (unsigned I = 0; I < Args.size(); ++I) {
50 QualType ParamType;
51 if (Callee && I < Callee->getNumParams())
52 ParamType = Callee->getParamDecl(I)->getType();
53 QualType ArgType = Args[I]->getType();
54 if ((!ParamType.isNull() && ParamType->isReferenceType()) ||
55 (!ArgType.isNull() && isView(ArgType)))
56 LifetimeBoundArgs.push_back(Args[I]);
57 }
58}
59
60/// Collects the entries of \p Args that \p Callee declares
61/// [[clang::lifetimebound]].
62void findLifetimeBoundArgs(const FunctionDecl *Callee,
64 SmallVectorImpl<const Expr *> &LifetimeBoundArgs) {
65 if (!Callee)
66 return;
67 const FunctionDecl *Canon =
69 unsigned Count = std::min<unsigned>(Canon->getNumParams(), Args.size());
70 for (unsigned I = 0; I < Count; ++I) {
71 if (Canon->getParamDecl(I)->hasAttr<LifetimeBoundAttr>())
72 LifetimeBoundArgs.push_back(Args[I]);
73 }
74}
75
76/// Collects the arguments that \p Construct declares [[clang::lifetimebound]].
77/// Absent annotations, a std view constructor is treated as if libc++ had
78/// annotated it.
79void findLifetimeBoundArgs(const CXXConstructExpr *Construct,
80 SmallVectorImpl<const Expr *> &LifetimeBoundArgs) {
81 const auto *Ctor = Construct->getConstructor();
82 ArrayRef<const Expr *> Args(Construct->getArgs(), Construct->getNumArgs());
83 findLifetimeBoundArgs(Ctor, Args, LifetimeBoundArgs);
84 if (!LifetimeBoundArgs.empty() || !Ctor || !isStdView(Ctor->getParent()))
85 return;
86 appendPresumedBorrowSources(Ctor, Args, LifetimeBoundArgs);
87}
88
89/// Collects the arguments that \p Call declares [[clang::lifetimebound]],
90/// including the implicit 'this' argument. Absent annotations, a call that
91/// returns or operates on a std view, or to std::data or std::get, is treated
92/// as if libc++ had annotated it.
93void findLifetimeBoundArgs(const CallExpr *Call,
94 SmallVectorImpl<const Expr *> &LifetimeBoundArgs) {
95 const FunctionDecl *Callee = Call->getDirectCallee();
96
97 const Expr *ObjectArg = nullptr;
98 unsigned ArgOffset = 0;
99 if (isa<CXXOperatorCallExpr>(Call) && Callee &&
100 Callee->isCXXInstanceMember() && Call->getNumArgs()) {
101 ObjectArg = Call->getArg(0);
102 ArgOffset = 1;
103 } else if (auto *MemberCall = dyn_cast<CXXMemberCallExpr>(Call))
104 ObjectArg = MemberCall->getImplicitObjectArgument();
105 ArrayRef<const Expr *> Args(Call->getArgs() + ArgOffset,
106 Call->getNumArgs() - ArgOffset);
107
108 if (auto *MD = dyn_cast_or_null<CXXMethodDecl>(Callee)) {
110 LifetimeBoundArgs.push_back(ObjectArg);
111 }
112 findLifetimeBoundArgs(Callee, Args, LifetimeBoundArgs);
113 if (!LifetimeBoundArgs.empty() || !Callee)
114 return;
115
116 bool IsStdAccessor =
117 Callee->isInStdNamespace() &&
118 (safeGetName(Callee) == "data" || safeGetName(Callee) == "get");
119 if (!isStdViewType(Callee->getReturnType()) &&
120 !(ObjectArg && isStdViewType(ObjectArg->getType())) && !IsStdAccessor)
121 return;
122
123 if (ObjectArg)
124 LifetimeBoundArgs.push_back(ObjectArg);
125 appendPresumedBorrowSources(Callee, Args, LifetimeBoundArgs);
126}
127
128/// Traces each of \p Args independently and requires every one to be safe.
129bool tryToFindPtrOriginOfEach(
130 ArrayRef<const Expr *> Args, bool StopAtFirstRefCountedObj,
131 const std::function<bool(const clang::CXXRecordDecl *)> &isSafePtr,
132 const std::function<bool(const clang::QualType)> &isSafePtrType,
133 const std::function<bool(const clang::Decl *)> &isSafeGlobalDecl,
134 const std::function<bool(const clang::Expr *, bool, bool, bool)> &callback,
135 bool OriginDependsOnFullExpressionTemporary,
136 bool PtrIsLifetimeBoundToOrigin) {
137 for (const Expr *Arg : Args) {
139 Arg, StopAtFirstRefCountedObj, /*FollowLifetimeBound=*/true,
140 isSafePtr, isSafePtrType, isSafeGlobalDecl, callback,
141 OriginDependsOnFullExpressionTemporary, PtrIsLifetimeBoundToOrigin))
142 return false;
143 }
144 return true;
145}
146
147} // namespace
148
150 const Expr *E, bool StopAtFirstRefCountedObj, bool FollowLifetimeBound,
152 std::function<bool(const clang::QualType)> isSafePtrType,
153 std::function<bool(const clang::Decl *)> isSafeGlobalDecl,
154 std::function<bool(const clang::Expr *, bool /*IsSafe*/,
155 bool /*OriginDependsOnFullExpressionTemporary*/,
156 bool /*PtrIsLifetimeBoundToOrigin*/)>
157 callback,
158 bool OriginDependsOnFullExpressionTemporary,
159 bool PtrIsLifetimeBoundToOrigin) {
160 while (E) {
161 if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
162 if (auto *VD = dyn_cast_or_null<VarDecl>(DRE->getDecl())) {
163 auto QT = VD->getType();
164 auto IsImmortal = safeGetName(VD) == "NSApp";
165 if (VD->hasGlobalStorage() && (IsImmortal || QT.isConstQualified()))
166 return callback(E, /*IsSafe=*/true,
167 OriginDependsOnFullExpressionTemporary,
168 PtrIsLifetimeBoundToOrigin);
169 if (VD->hasGlobalStorage() && isSafeGlobalDecl(VD))
170 return callback(E, /*IsSafe=*/true,
171 OriginDependsOnFullExpressionTemporary,
172 PtrIsLifetimeBoundToOrigin);
173
174 if (FollowLifetimeBound && VD->isImplicit() && VD->isLocalVarDecl()) {
175 if (auto *Init = VD->getInit()) {
176 E = Init;
177 continue;
178 }
179 }
180 }
181 }
182 if (auto *Cleanups = dyn_cast<ExprWithCleanups>(E)) {
183 E = Cleanups->getSubExpr();
184 continue;
185 }
186 if (auto *tempExpr = dyn_cast<MaterializeTemporaryExpr>(E)) {
187 if (tempExpr->getStorageDuration() == SD_FullExpression)
188 OriginDependsOnFullExpressionTemporary = true;
189 E = tempExpr->getSubExpr();
190 continue;
191 }
192 if (auto *tempExpr = dyn_cast<CXXBindTemporaryExpr>(E)) {
193 E = tempExpr->getSubExpr();
194 continue;
195 }
196 if (auto *tempExpr = dyn_cast<CXXConstructExpr>(E)) {
197 if (auto *C = tempExpr->getConstructor()) {
198 if (auto *Class = C->getParent(); Class && isSafePtr(Class))
199 return callback(E, /*IsSafe=*/true,
200 OriginDependsOnFullExpressionTemporary,
201 PtrIsLifetimeBoundToOrigin);
202
203 if (FollowLifetimeBound) {
204 SmallVector<const Expr *, 2> LifetimeBoundArgs;
205 findLifetimeBoundArgs(tempExpr, LifetimeBoundArgs);
206 if (!LifetimeBoundArgs.empty())
207 return tryToFindPtrOriginOfEach(
208 LifetimeBoundArgs, StopAtFirstRefCountedObj, isSafePtr,
209 isSafePtrType, isSafeGlobalDecl, callback,
210 /*OriginDependsOnFullExpressionTemporary=*/false,
211 /*PtrIsLifetimeBoundToOrigin=*/true);
212 }
213 break;
214 }
215 }
216 if (auto *TempExpr = dyn_cast<CXXUnresolvedConstructExpr>(E)) {
217 if (isSafePtrType(TempExpr->getTypeAsWritten()))
218 return callback(TempExpr, /*IsSafe=*/true,
219 OriginDependsOnFullExpressionTemporary,
220 PtrIsLifetimeBoundToOrigin);
221 }
222 if (auto *POE = dyn_cast<PseudoObjectExpr>(E)) {
223 if (auto *RF = POE->getResultExpr()) {
224 E = RF;
225 continue;
226 }
227 }
228 if (auto *tempExpr = dyn_cast<ParenExpr>(E)) {
229 E = tempExpr->getSubExpr();
230 continue;
231 }
232 if (auto *OpaqueValue = dyn_cast<OpaqueValueExpr>(E)) {
233 E = OpaqueValue->getSourceExpr();
234 continue;
235 }
236 if (auto *Expr = dyn_cast<ConditionalOperator>(E)) {
237 return tryToFindPtrOriginImpl(Expr->getTrueExpr(),
238 StopAtFirstRefCountedObj,
239 FollowLifetimeBound, isSafePtr,
240 isSafePtrType, isSafeGlobalDecl, callback,
241 OriginDependsOnFullExpressionTemporary,
242 PtrIsLifetimeBoundToOrigin) &&
243 tryToFindPtrOriginImpl(Expr->getFalseExpr(),
244 StopAtFirstRefCountedObj,
245 FollowLifetimeBound, isSafePtr,
246 isSafePtrType, isSafeGlobalDecl, callback,
247 OriginDependsOnFullExpressionTemporary,
248 PtrIsLifetimeBoundToOrigin);
249 }
250 if (auto *cast = dyn_cast<CastExpr>(E)) {
251 if (StopAtFirstRefCountedObj) {
252 if (auto *ConversionFunc =
253 dyn_cast_or_null<FunctionDecl>(cast->getConversionFunction())) {
254 if (isCtorOfSafePtr(ConversionFunc))
255 return callback(E, /*IsSafe=*/true,
256 OriginDependsOnFullExpressionTemporary,
257 PtrIsLifetimeBoundToOrigin);
258 }
259 if (isa<CXXFunctionalCastExpr>(E) && isSafePtrType(cast->getType()))
260 return callback(E, /*IsSafe=*/true,
261 OriginDependsOnFullExpressionTemporary,
262 PtrIsLifetimeBoundToOrigin);
263 }
264 // FIXME: This can give false "origin" that would lead to false negatives
265 // in checkers. See https://reviews.llvm.org/D37023 for reference.
266 E = cast->getSubExpr();
267 continue;
268 }
269 if (auto *call = dyn_cast<CallExpr>(E)) {
270 if (auto *Callee = call->getCalleeDecl()) {
271 if (Callee->hasAttr<CFReturnsRetainedAttr>() ||
272 Callee->hasAttr<NSReturnsRetainedAttr>() ||
273 Callee->hasAttr<NSReturnsAutoreleasedAttr>()) {
274 return callback(E, /*IsSafe=*/true,
275 OriginDependsOnFullExpressionTemporary,
276 PtrIsLifetimeBoundToOrigin);
277 }
278 }
279
280 if (isSafePtrType(call->getType()))
281 return callback(E, /*IsSafe=*/true,
282 OriginDependsOnFullExpressionTemporary,
283 PtrIsLifetimeBoundToOrigin);
284
285 if (auto *memberCall = dyn_cast<CXXMemberCallExpr>(call)) {
286 if (auto *decl = memberCall->getMethodDecl()) {
287 std::optional<bool> IsGetterOfRefCt = isGetterOfSafePtr(decl);
288 if (IsGetterOfRefCt && *IsGetterOfRefCt) {
289 E = memberCall->getImplicitObjectArgument();
290 if (StopAtFirstRefCountedObj) {
291 return callback(E, /*IsSafe=*/true,
292 OriginDependsOnFullExpressionTemporary,
293 PtrIsLifetimeBoundToOrigin);
294 }
295 continue;
296 }
298 E = memberCall->getImplicitObjectArgument();
299 continue;
300 }
301 }
302 }
303
304 if (auto *operatorCall = dyn_cast<CXXOperatorCallExpr>(E)) {
305 if (auto *Callee = operatorCall->getDirectCallee()) {
306 auto ClsName = safeGetName(Callee->getParent());
307 if (isRefType(ClsName) || isCheckedPtr(ClsName) ||
308 isRetainPtrOrOSPtr(ClsName) || ClsName == "unique_ptr" ||
309 ClsName == "UniqueRef" || ClsName == "WeakPtr" ||
310 ClsName == "WeakRef") {
311 if (operatorCall->getNumArgs() == 1) {
312 E = operatorCall->getArg(0);
313 continue;
314 }
315 }
316 }
317 }
318
319 if (auto *callee = call->getDirectCallee()) {
320 if (isCtorOfSafePtr(callee)) {
321 if (StopAtFirstRefCountedObj)
322 return callback(E, /*IsSafe=*/true,
323 OriginDependsOnFullExpressionTemporary,
324 PtrIsLifetimeBoundToOrigin);
325
326 E = call->getArg(0);
327 continue;
328 }
329
330 if (isStdOrWTFMove(callee) && call->getNumArgs() == 1) {
331 E = call->getArg(0)->IgnoreParenCasts();
332 continue;
333 }
334
335 if (isSafePtrType(callee->getReturnType()))
336 return callback(E, /*IsSafe=*/true,
337 OriginDependsOnFullExpressionTemporary,
338 PtrIsLifetimeBoundToOrigin);
339
340 if (isSingleton(callee))
341 return callback(E, /*IsSafe=*/true,
342 OriginDependsOnFullExpressionTemporary,
343 PtrIsLifetimeBoundToOrigin);
344
345 if (callee->isInStdNamespace() && safeGetName(callee) == "forward") {
346 E = call->getArg(0);
347 continue;
348 }
349
350 if (isPtrConversion(callee)) {
351 E = call->getArg(0);
352 continue;
353 }
354
355 auto Name = safeGetName(callee);
356 if (Name == "__builtin___CFStringMakeConstantString" ||
357 Name == "NSStringFromSelector" || Name == "NSSelectorFromString" ||
358 Name == "NSStringFromClass" || Name == "NSClassFromString" ||
359 Name == "NSStringFromProtocol" || Name == "NSProtocolFromString")
360 return callback(E, /*IsSafe=*/true,
361 OriginDependsOnFullExpressionTemporary,
362 PtrIsLifetimeBoundToOrigin);
363 } else if (auto *CalleeE = call->getCallee()) {
364 if (auto *E = dyn_cast<DeclRefExpr>(CalleeE->IgnoreParenCasts())) {
365 if (isSingleton(E->getFoundDecl()))
366 return callback(E, /*IsSafe=*/true,
367 OriginDependsOnFullExpressionTemporary,
368 PtrIsLifetimeBoundToOrigin);
369 }
370
371 if (auto *MemberExpr = dyn_cast<CXXDependentScopeMemberExpr>(CalleeE)) {
372 auto *Base = MemberExpr->getBase();
373 auto MemberName = MemberExpr->getMember().getAsString();
374 bool IsGetter = MemberName == "get" || MemberName == "ptr";
375 if (Base && isSafePtrType(Base->getType()) && IsGetter)
376 return callback(E, /*IsSafe=*/true,
377 OriginDependsOnFullExpressionTemporary,
378 PtrIsLifetimeBoundToOrigin);
379 }
380 }
381
382 // Sometimes, canonical type erroneously turns Ref<T> into T.
383 // Workaround this problem by checking again if the original type was
384 // a SubstTemplateTypeParmType of a safe smart pointer type (e.g. Ref).
385 if (auto *CalleeDecl = call->getCalleeDecl()) {
386 if (auto *FD = dyn_cast<FunctionDecl>(CalleeDecl)) {
387 auto RetType = FD->getReturnType();
388 if (auto *Subst = dyn_cast<SubstTemplateTypeParmType>(RetType)) {
389 if (auto *SubstType = Subst->desugar().getTypePtr()) {
390 if (auto *RD = dyn_cast<RecordType>(SubstType)) {
391 if (auto *CXX = dyn_cast<CXXRecordDecl>(RD->getDecl()))
392 if (isSafePtr(CXX))
393 return callback(E, /*IsSafe=*/true,
394 OriginDependsOnFullExpressionTemporary,
395 PtrIsLifetimeBoundToOrigin);
396 }
397 }
398 }
399 }
400 }
401
402 if (FollowLifetimeBound) {
403 SmallVector<const Expr *, 2> LifetimeBoundArgs;
404 findLifetimeBoundArgs(call, LifetimeBoundArgs);
405 if (!LifetimeBoundArgs.empty())
406 return tryToFindPtrOriginOfEach(
407 LifetimeBoundArgs, StopAtFirstRefCountedObj, isSafePtr,
408 isSafePtrType, isSafeGlobalDecl, callback,
409 /*OriginDependsOnFullExpressionTemporary=*/false,
410 /*PtrIsLifetimeBoundToOrigin=*/true);
411 }
412 }
413 if (auto *ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(E)) {
414 if (auto *Method = ObjCMsgExpr->getMethodDecl()) {
415 if (isSafePtrType(Method->getReturnType()))
416 return callback(E, /*IsSafe=*/true,
417 OriginDependsOnFullExpressionTemporary,
418 PtrIsLifetimeBoundToOrigin);
419 }
420 auto Selector = ObjCMsgExpr->getSelector();
421 auto NameForFirstSlot = Selector.getNameForSlot(0);
422 if ((NameForFirstSlot == "class" || NameForFirstSlot == "superclass") &&
424 return callback(E, /*IsSafe=*/true,
425 OriginDependsOnFullExpressionTemporary,
426 PtrIsLifetimeBoundToOrigin);
427 }
428 if (auto *ObjCProtocol = dyn_cast<ObjCProtocolExpr>(E))
429 return callback(ObjCProtocol, /*IsSafe=*/true,
430 OriginDependsOnFullExpressionTemporary,
431 PtrIsLifetimeBoundToOrigin);
432 if (auto *ObjCDict = dyn_cast<ObjCDictionaryLiteral>(E))
433 return callback(ObjCDict, /*IsSafe=*/true,
434 OriginDependsOnFullExpressionTemporary,
435 PtrIsLifetimeBoundToOrigin);
436 if (auto *ObjCArray = dyn_cast<ObjCArrayLiteral>(E))
437 return callback(ObjCArray, /*IsSafe=*/true,
438 OriginDependsOnFullExpressionTemporary,
439 PtrIsLifetimeBoundToOrigin);
440 if (auto *ObjCStr = dyn_cast<ObjCStringLiteral>(E))
441 return callback(ObjCStr, /*IsSafe=*/true,
442 OriginDependsOnFullExpressionTemporary,
443 PtrIsLifetimeBoundToOrigin);
444 if (auto *unaryOp = dyn_cast<UnaryOperator>(E)) {
445 // FIXME: Currently accepts ANY unary operator. Is it OK?
446 E = unaryOp->getSubExpr();
447 continue;
448 }
449 if (auto *BoxedExpr = dyn_cast<ObjCBoxedExpr>(E)) {
450 if (StopAtFirstRefCountedObj)
451 return callback(BoxedExpr, /*IsSafe=*/true,
452 OriginDependsOnFullExpressionTemporary,
453 PtrIsLifetimeBoundToOrigin);
454 E = BoxedExpr->getSubExpr();
455 continue;
456 }
457 break;
458 }
459 // Some other expression.
460 return callback(E, /*IsSafe=*/false, OriginDependsOnFullExpressionTemporary,
461 PtrIsLifetimeBoundToOrigin);
462}
463
465 const Expr *E, bool StopAtFirstRefCountedObj, bool FollowLifetimeBound,
467 std::function<bool(const clang::QualType)> isSafePtrType,
468 std::function<bool(const clang::Decl *)> isSafeGlobalDecl,
469 std::function<bool(const clang::Expr *, bool /*IsSafe*/,
470 bool /*OriginDependsOnFullExpressionTemporary*/,
471 bool /*PtrIsLifetimeBoundToOrigin*/)>
472 callback) {
474 E, StopAtFirstRefCountedObj, FollowLifetimeBound, std::move(isSafePtr),
475 std::move(isSafePtrType), std::move(isSafeGlobalDecl),
476 std::move(callback),
477 /*OriginDependsOnFullExpressionTemporary=*/false,
478 /*PtrIsLifetimeBoundToOrigin=*/false);
479}
480
481bool originOutlivesCall(const Expr *E) {
482 assert(E);
483 auto IsCheckedLocalVarOrParam = [](const VarDecl *Decl) {
484 auto Ty = Decl->getType();
485 const CXXRecordDecl *CXXRD = Ty->getAsCXXRecordDecl();
486 if (!CXXRD)
487 CXXRD = Ty->getPointeeCXXRecordDecl();
488 if (CXXRD && isWeakPtr(CXXRD))
489 return false;
490 return Decl->isLocalVarDeclOrParm();
491 };
492 if (auto *Ref = dyn_cast<DeclRefExpr>(E)) {
493 auto *FoundDecl = Ref->getFoundDecl();
494 if (auto *D = dyn_cast_or_null<VarDecl>(FoundDecl)) {
495 if (IsCheckedLocalVarOrParam(D))
496 return true;
497 if (auto *ImplicitP = dyn_cast<ImplicitParamDecl>(D)) {
498 auto Kind = ImplicitP->getParameterKind();
499 if (Kind == ImplicitParamKind::ObjCSelf ||
503 return true;
504 }
505 } else if (auto *BD = dyn_cast_or_null<BindingDecl>(FoundDecl)) {
506 if (VarDecl *VD = BD->getHoldingVar()) {
507 if (IsCheckedLocalVarOrParam(VD))
508 return true;
509 }
510 }
511 }
513 return true; // A temporary lives until the end of this statement.
515 return true;
516
517 // TODO: checker for method calls on non-refcounted objects
518 return isa<CXXThisExpr>(E);
519}
520
521bool isNullPtr(const clang::Expr *E) {
523 return true;
524 if (auto *Int = dyn_cast_or_null<IntegerLiteral>(E)) {
525 if (Int->getValue().isZero())
526 return true;
527 }
528 return false;
529}
530
532 if (auto *MCE = dyn_cast<CXXMemberCallExpr>(E)) {
533 if (auto *Callee = MCE->getDirectCallee()) {
534 auto Name = safeGetName(Callee);
535 if (Name == "get" || Name == "ptr")
536 E = MCE->getImplicitObjectArgument();
537 if (isa<CXXConversionDecl>(Callee))
538 E = MCE->getImplicitObjectArgument();
539 }
540 } else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(E)) {
541 if (OCE->getOperator() == OO_Star && OCE->getNumArgs() == 1)
542 E = OCE->getArg(0);
543 }
544 const ValueDecl *D = nullptr;
545 if (auto *ME = dyn_cast<MemberExpr>(E))
546 D = ME->getMemberDecl();
547 else if (auto *IVR = dyn_cast<ObjCIvarRefExpr>(E))
548 D = IVR->getDecl();
549 if (!D)
550 return false;
551 auto T = D->getType();
552 return isOwnerPtrType(T) && T.isConstQualified();
553}
554
556 auto *ME = dyn_cast<MemberExpr>(E);
557 if (!ME)
558 return false;
559 auto *Base = ME->getBase();
560 if (!Base)
561 return false;
562 if (!isa<CXXThisExpr>(Base->IgnoreParenCasts()))
563 return false;
564 auto *D = ME->getMemberDecl();
565 if (!D)
566 return false;
567 auto T = D->getType();
568 auto *CXXRD = T->getAsCXXRecordDecl();
569 if (!CXXRD)
570 return false;
571 auto result = isCheckedPtrCapable(CXXRD);
572 return result && *result;
573}
574
575bool isAllocInit(const Expr *E, const Expr **InnerExpr) {
576 auto *ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(E);
577 if (auto *POE = dyn_cast<PseudoObjectExpr>(E)) {
578 if (unsigned ExprCount = POE->getNumSemanticExprs()) {
579 auto *Expr = POE->getSemanticExpr(ExprCount - 1)->IgnoreParenCasts();
580 ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(Expr);
581 if (InnerExpr)
582 *InnerExpr = ObjCMsgExpr;
583 }
584 }
585 if (!ObjCMsgExpr)
586 return false;
587 auto Selector = ObjCMsgExpr->getSelector();
588 auto NameForFirstSlot = Selector.getNameForSlot(0);
589 if (NameForFirstSlot.starts_with("alloc") ||
590 NameForFirstSlot.starts_with("copy") ||
591 NameForFirstSlot.starts_with("mutableCopy")) {
592 if (auto *MD = ObjCMsgExpr->getMethodDecl()) {
593 if (MD->getReturnType()->isVoidType())
594 return false;
595 }
596 return true;
597 }
598 if (!NameForFirstSlot.starts_with("init") &&
599 !NameForFirstSlot.starts_with("_init"))
600 return false;
601 if (!ObjCMsgExpr->isInstanceMessage())
602 return false;
603 auto *Receiver = ObjCMsgExpr->getInstanceReceiver();
604 if (!Receiver)
605 return false;
606 Receiver = Receiver->IgnoreParenCasts();
607 if (auto *Inner = dyn_cast<ObjCMessageExpr>(Receiver)) {
608 if (InnerExpr)
609 *InnerExpr = Inner;
610 auto InnerSelector = Inner->getSelector();
611 return InnerSelector.getNameForSlot(0).starts_with("alloc");
612 } else if (auto *CE = dyn_cast<CallExpr>(Receiver)) {
613 if (InnerExpr)
614 *InnerExpr = CE;
615 if (auto *Callee = CE->getDirectCallee()) {
616 if (Callee->getDeclName().isIdentifier()) {
617 auto CalleeName = Callee->getName();
618 return CalleeName.starts_with("alloc");
619 }
620 }
621 }
622 return false;
623}
624
626 auto *PointeeType = TypePtr->getPointeeType().getTypePtrOrNull();
627 if (!PointeeType)
628 return nullptr;
629 auto *Desugared = PointeeType->getUnqualifiedDesugaredType();
630 if (!Desugared)
631 return nullptr;
632 if (auto *ObjCType = dyn_cast<ObjCInterfaceType>(Desugared))
633 return ObjCType->getDecl();
634 if (auto *ObjCType = dyn_cast<ObjCObjectType>(Desugared))
635 return ObjCType->getInterface();
636 return nullptr;
637}
638
640 : public ConstStmtVisitor<EnsureFunctionVisitor, bool> {
641public:
642 bool VisitStmt(const Stmt *S) {
643 for (const Stmt *Child : S->children()) {
644 if (Child && !Visit(Child))
645 return false;
646 }
647 return true;
648 }
649
650 bool VisitReturnStmt(const ReturnStmt *RS) {
651 if (auto *RV = RS->getRetValue()) {
652 RV = RV->IgnoreParenCasts();
653 if (isNullPtr(RV))
654 return true;
655 return isConstOwnerPtrMemberExpr(RV);
656 }
657 return false;
658 }
659};
660
662 auto *MCE = dyn_cast<CXXMemberCallExpr>(E);
663 if (!MCE)
664 return false;
665 auto *Callee = MCE->getDirectCallee();
666 if (!Callee)
667 return false;
668 auto *Body = Callee->getBody();
669 if (!Body || Callee->isVirtualAsWritten())
670 return false;
671 auto [CacheIt, IsNew] = Cache.insert(std::make_pair(Callee, false));
672 if (IsNew)
673 CacheIt->second = EnsureFunctionVisitor().Visit(Body);
674 return CacheIt->second;
675}
676
677} // namespace clang
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
Represents a call to a C++ constructor.
Definition ExprCXX.h:1552
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2987
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
bool isACallToEnsureFn(const Expr *E) const
Definition ASTUtils.cpp:661
bool VisitReturnStmt(const ReturnStmt *RS)
Definition ASTUtils.cpp:650
bool VisitStmt(const Stmt *S)
Definition ASTUtils.cpp:642
This represents one expression.
Definition Expr.h:113
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition Expr.cpp:3128
Represents a function declaration or definition.
Definition Decl.h:2059
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition Expr.h:3408
Expr * getBase() const
Definition Expr.h:3485
Represents an ObjC class declaration.
Definition DeclObjC.h:1160
A (possibly-)qualified type.
Definition TypeBase.h:938
const Type * getTypePtrOrNull() const
Definition TypeBase.h:8432
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3172
Expr * getRetValue()
Definition Stmt.h:3199
Smart pointer class that efficiently represents Objective-C method names.
StringRef getNameForSlot(unsigned argIndex) const
Retrieve the name at a given position in the selector.
unsigned getNumArgs() const
Stmt - This represents one statement.
Definition Stmt.h:85
child_range children()
Definition Stmt.cpp:304
The base class of the type hierarchy.
Definition TypeBase.h:1879
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:881
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
Definition Type.cpp:782
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:713
QualType getType() const
Definition Decl.h:724
Represents a variable declaration or definition.
Definition Decl.h:933
const internal::VariadicAllOfMatcher< Decl > decl
Matches declarations.
bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD)
const FunctionDecl * getDeclWithMergedLifetimeBoundAttrs(const FunctionDecl *FD)
Top level wrappers for InstallAPI frontend operations.
bool isCtorOfSafePtr(const clang::FunctionDecl *F)
bool isa(CodeGen::Address addr)
Definition Address.h:330
bool isExprToGetCheckedPtrCapableMember(const clang::Expr *E)
Definition ASTUtils.cpp:555
bool isPtrConversion(const FunctionDecl *F)
std::optional< bool > isCheckedPtrCapable(const clang::CXXRecordDecl *R)
bool isView(const clang::QualType T)
bool isGetterOfUniquePtr(const CXXMethodDecl *M)
@ SD_FullExpression
Full-expression storage duration (for temporaries).
Definition Specifiers.h:339
bool isStdView(const clang::CXXRecordDecl *R)
const FunctionProtoType * T
bool originOutlivesCall(const Expr *E)
For E referring to a ref-countable/-counted pointer/reference we return whether the pointee outlives ...
Definition ASTUtils.cpp:481
bool isRefCounted(const CXXRecordDecl *R)
bool isOwnerPtrType(const clang::QualType T)
static bool tryToFindPtrOriginImpl(const Expr *E, bool StopAtFirstRefCountedObj, bool FollowLifetimeBound, std::function< bool(const clang::CXXRecordDecl *)> isSafePtr, std::function< bool(const clang::QualType)> isSafePtrType, std::function< bool(const clang::Decl *)> isSafeGlobalDecl, std::function< bool(const clang::Expr *, bool, bool, bool)> callback, bool OriginDependsOnFullExpressionTemporary, bool PtrIsLifetimeBoundToOrigin)
Definition ASTUtils.cpp:149
std::optional< bool > isGetterOfSafePtr(const CXXMethodDecl *M)
bool isRetainPtrOrOSPtr(const std::string &Name)
bool isRefType(const std::string &Name)
bool isSafePtr(clang::CXXRecordDecl *Decl)
Definition ASTUtils.cpp:23
std::string safeGetName(const T *ASTNode)
Definition ASTUtils.h:109
ObjCInterfaceDecl * getObjCDeclFromObjCPtr(const Type *TypePtr)
Definition ASTUtils.cpp:625
bool isSingleton(const NamedDecl *F)
bool isNullPtr(const clang::Expr *E)
Definition ASTUtils.cpp:521
bool isCheckedPtr(const std::string &Name)
bool isStdOrWTFMove(const clang::FunctionDecl *F)
U cast(CodeGen::Address addr)
Definition Address.h:327
bool tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj, bool FollowLifetimeBound, std::function< bool(const clang::CXXRecordDecl *)> isSafePtr, std::function< bool(const clang::QualType)> isSafePtrType, std::function< bool(const clang::Decl *)> isSafeGlobalDecl, std::function< bool(const clang::Expr *, bool, bool, bool)> callback)
This function de-facto defines a set of transformations that we consider safe (in heuristical sense).
Definition ASTUtils.cpp:464
bool isAllocInit(const Expr *E, const Expr **InnerExpr)
Definition ASTUtils.cpp:575
@ Class
The "class" keyword introduces the elaborated-type-specifier.
Definition TypeBase.h:6007
@ CXXThis
Parameter for C++ 'this' argument.
Definition Decl.h:1763
@ CXXVTT
Parameter for C++ virtual table pointers.
Definition Decl.h:1766
@ ObjCSelf
Parameter for Objective-C 'self' argument.
Definition Decl.h:1757
@ ObjCCmd
Parameter for Objective-C '_cmd' argument.
Definition Decl.h:1760
bool isConstOwnerPtrMemberExpr(const clang::Expr *E)
Definition ASTUtils.cpp:531
bool isWeakPtr(const CXXRecordDecl *R)
int const char * function
Definition c++config.h:31