clang 24.0.0git
PtrTypesSemantics.cpp
Go to the documentation of this file.
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#include "PtrTypesSemantics.h"
10#include "ASTUtils.h"
11#include "clang/AST/Attr.h"
13#include "clang/AST/Decl.h"
14#include "clang/AST/DeclCXX.h"
16#include "clang/AST/ExprCXX.h"
20#include "llvm/ADT/StringSet.h"
21#include <optional>
22
23using namespace clang;
24
25namespace {
26
27bool hasPublicMethodInBaseClass(const CXXRecordDecl *R, StringRef NameToMatch) {
28 assert(R);
29 assert(R->hasDefinition());
30
31 for (const CXXMethodDecl *MD : R->methods()) {
32 const auto MethodName = safeGetName(MD);
33 if (MethodName == NameToMatch && MD->getAccess() == AS_public)
34 return true;
35 }
36
37 for (const Decl *D : R->decls()) {
38 const auto *Shadow = dyn_cast<UsingShadowDecl>(D);
39 if (!Shadow || Shadow->getAccess() != AS_public)
40 continue;
41 const auto *MD = dyn_cast<CXXMethodDecl>(Shadow->getTargetDecl());
42 if (MD && safeGetName(MD) == NameToMatch)
43 return true;
44 }
45 return false;
46}
47
48} // namespace
49
50namespace clang {
51
52std::optional<const clang::CXXRecordDecl *>
53hasPublicMethodInBase(const CXXBaseSpecifier *Base, StringRef NameToMatch) {
54 assert(Base);
55
56 const Type *T = Base->getType().getTypePtrOrNull();
57 if (!T)
58 return std::nullopt;
59
60 const CXXRecordDecl *R = T->getAsCXXRecordDecl();
61 if (!R) {
62 auto CT = Base->getType().getCanonicalType();
63 if (auto *TST = dyn_cast<TemplateSpecializationType>(CT)) {
64 auto TmplName = TST->getTemplateName();
65 if (!TmplName.isNull()) {
66 if (auto *TD = TmplName.getAsTemplateDecl())
67 R = dyn_cast_or_null<CXXRecordDecl>(TD->getTemplatedDecl());
68 }
69 }
70 if (!R)
71 return std::nullopt;
72 }
73 if (!R->hasDefinition())
74 return std::nullopt;
75
76 return hasPublicMethodInBaseClass(R, NameToMatch) ? R : nullptr;
77}
78
79static std::optional<bool> hasPublicMethodInHierarchy(const CXXRecordDecl *R,
80 StringRef MethodName) {
81 assert(R);
82
83 R = R->getDefinition();
84 if (!R)
85 return std::nullopt;
86
87 if (hasPublicMethodInBaseClass(R, MethodName))
88 return true;
89
90 CXXBasePaths Paths;
91 Paths.setOrigin(const_cast<CXXRecordDecl *>(R));
92
93 bool AnyInconclusiveBase = false;
94 const auto hasPublicMethod = [&](const CXXBaseSpecifier *Base,
95 CXXBasePath &) {
96 auto HasMethodInBase = clang::hasPublicMethodInBase(Base, MethodName);
97 if (!HasMethodInBase) {
98 AnyInconclusiveBase = true;
99 return false;
100 }
101 return (*HasMethodInBase) != nullptr;
102 };
103
104 bool Found = R->lookupInBases(hasPublicMethod, Paths,
105 /*LookupInDependent =*/true);
106 if (AnyInconclusiveBase)
107 return std::nullopt;
108
109 return Found;
110}
111
112std::optional<bool> isSmartPtrCompatible(const CXXRecordDecl *R,
113 StringRef IncMethodName,
114 StringRef DecMethodName) {
115 assert(R);
116
117 auto HasInc = hasPublicMethodInHierarchy(R, IncMethodName);
118 if (!HasInc)
119 return std::nullopt;
120
121 auto HasDec = hasPublicMethodInHierarchy(R, DecMethodName);
122 if (!HasDec)
123 return std::nullopt;
124
125 return *HasInc && *HasDec;
126}
127
128std::optional<bool> isRefCountable(const clang::CXXRecordDecl *R) {
129 return isSmartPtrCompatible(R, "ref", "deref");
130}
131
132std::optional<bool> isCheckedPtrCapable(const clang::CXXRecordDecl *R) {
133 return isSmartPtrCompatible(R, "incrementCheckedPtrCount",
134 "decrementCheckedPtrCount");
135}
136
137std::optional<bool> isBorrowable(const clang::CXXRecordDecl *R) {
138 assert(R);
139 return hasPublicMethodInHierarchy(R, "crashIfBorrowed");
140}
141
143 if (!R)
144 return false;
145 return isBorrow(safeGetName(R));
146}
147
149 return isBorrow(T->getAsCXXRecordDecl());
150}
151
153 while (!T.isNull()) {
154 QualType Pointee = T->getPointeeType();
155 if (Pointee.isNull())
156 break;
157 T = Pointee;
158 }
159 return T;
160}
161
163 const auto *Specialization =
164 dyn_cast_or_null<ClassTemplateSpecializationDecl>(
165 T->getAsCXXRecordDecl());
166 if (!Specialization)
167 return QualType();
168 const auto &Args = Specialization->getTemplateArgs();
169 if (!Args.size() || Args[0].getKind() != TemplateArgument::Type)
170 return QualType();
171 return Args[0].getAsType();
172}
173
175 if (!R || !R->hasDefinition())
176 return false;
177 for (const CXXConstructorDecl *Ctor : R->ctors()) {
178 for (const ParmVarDecl *Param : Ctor->parameters()) {
179 if (Param->hasAttr<LifetimeBoundAttr>() ||
180 Param->hasAttr<LifetimeCaptureByAttr>())
181 return true;
182 }
183 }
184 return false;
185}
186
188 if (!R || !R->getIdentifier() || R->getName() != "view_interface")
189 return false;
190 const auto *NS = dyn_cast<NamespaceDecl>(R->getDeclContext());
191 return NS && NS->getIdentifier() && NS->getName() == "ranges" &&
192 NS->getParent()->isStdNamespace();
193}
194
196 if (!R)
197 return false;
198 R = R->getDefinition();
199 if (!R)
200 return false;
202 return true;
203 for (const CXXBaseSpecifier &Base : R->bases()) {
204 if (derivesFromViewInterface(Base.getType()->getAsCXXRecordDecl()))
205 return true;
206 }
207 return false;
208}
209
211 if (!R)
212 return false;
213 if (R->hasAttr<PointerAttr>())
214 return true;
215 static const llvm::StringSet<> StdIterators{
216 "reverse_iterator", "move_iterator", "common_iterator",
217 "counted_iterator", "basic_const_iterator"};
218 if (R->isInStdNamespace() && R->getIdentifier() &&
219 StdIterators.contains(R->getName()))
220 return true;
222 return true;
223 if (const auto *Parent = dyn_cast<CXXRecordDecl>(R->getDeclContext()))
224 return isStdView(Parent);
225 return false;
226}
227
229 if (T->isReferenceType())
230 return true;
232 return true;
233 auto *Record = T->getAsCXXRecordDecl();
234 if (isStdView(Record))
235 return true;
237}
238
239bool isRefType(const std::string &Name) {
240 return Name == "Ref" || Name == "RefAllowingPartiallyDestroyed" ||
241 Name == "RefPtr" || Name == "RefPtrAllowingPartiallyDestroyed";
242}
243
244bool isRetainPtrOrOSPtr(const std::string &Name) {
245 return Name == "RetainPtr" || Name == "RetainPtrArc" ||
246 Name == "OSObjectPtr" || Name == "OSObjectPtrArc";
247}
248
249bool isCheckedPtr(const std::string &Name) {
250 return Name == "CheckedPtr" || Name == "CheckedRef";
251}
252
253bool isUniquePtr(const std::string &Name) {
254 return Name == "unique_ptr" || Name == "UniqueRef" || Name == "LazyUniqueRef";
255}
256
257bool isBorrow(const std::string &Name) { return Name == "Borrow"; }
258
259bool isOwnerPtr(const std::string &Name) {
260 return isRefType(Name) || isCheckedPtr(Name) || isRetainPtrOrOSPtr(Name) ||
261 isUniquePtr(Name);
262}
263
264static bool isWeakPtrClass(const std::string &Name) {
265 return Name == "WeakPtr" || Name == "SingleThreadPackedWeakPtr" ||
266 Name == "SingleThreadWeakPtr" || Name == "ThreadSafeWeakPtr" ||
267 Name == "ThreadSafeWeakOrStrongPtr" || Name == "InlineWeakPtr";
268}
269
270bool isSmartPtrClass(const std::string &Name) {
271 return isRefType(Name) || isCheckedPtr(Name) || isRetainPtrOrOSPtr(Name) ||
272 isWeakPtrClass(Name) || Name == "WeakPtrFactory" ||
273 Name == "WeakPtrFactoryWithBitField" || Name == "WeakPtrImplBase" ||
274 Name == "WeakPtrImplBaseSingleThread" ||
275 Name == "ThreadSafeWeakOrStrongPtr" ||
276 Name == "ThreadSafeWeakPtrControlBlock" ||
277 Name == "ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr";
278}
279
281 if (auto *Ctor = dyn_cast_or_null<CXXConstructorDecl>(F))
282 return safeGetName(Ctor->getParent());
283 return safeGetName(F);
284}
285
287 assert(F);
288 auto FunctionName = getConstructorName(F);
289 return isRefType(FunctionName) || FunctionName == "adoptRef" ||
290 FunctionName == "UniqueRef" || FunctionName == "makeUniqueRef" ||
291 FunctionName == "makeUniqueRefWithoutFastMallocCheck"
292
293 || FunctionName == "String" || FunctionName == "AtomString" ||
294 FunctionName == "UniqueString"
295 // FIXME: Implement as attribute.
296 || FunctionName == "Identifier";
297}
298
300 assert(F);
302}
303
305 auto FunctionName = getConstructorName(F);
306 return isRetainPtrOrOSPtr(FunctionName) || FunctionName == "adoptNS" ||
307 FunctionName == "adoptNSNullable" || FunctionName == "adoptCF" ||
308 FunctionName == "adoptCFNullable" || FunctionName == "retainPtr" ||
309 FunctionName == "adoptNSArc" || FunctionName == "adoptOSObject" ||
310 FunctionName == "adoptOSObjectArc";
311}
312
317
319 auto FnName = safeGetName(F);
320 auto *Namespace = F->getParent();
321 if (!Namespace)
322 return false;
323 auto *TUDeck = Namespace->getParent();
324 if (!isa_and_nonnull<TranslationUnitDecl>(TUDeck))
325 return false;
326 auto NsName = safeGetName(Namespace);
327 return (NsName == "WTF" || NsName == "std") && FnName == "move";
328}
329
330template <typename Predicate>
331static bool isPtrOfType(const clang::QualType T, Predicate Pred) {
332 QualType type = T;
333 while (!type.isNull()) {
334 if (auto *SpecialT = type->getAs<TemplateSpecializationType>()) {
335 auto *Decl = SpecialT->getTemplateName().getAsTemplateDecl();
336 return Decl && Pred(Decl->getNameAsString());
337 } else if (auto *DTS = type->getAs<DeducedTemplateSpecializationType>()) {
338 auto *Decl = DTS->getTemplateName().getAsTemplateDecl();
339 return Decl && Pred(Decl->getNameAsString());
340 } else if (auto *RD = type->getAs<RecordType>()) {
341 auto *Decl = RD->getDecl();
342 return Decl && Pred(Decl->getNameAsString());
343 } else
344 break;
345 }
346 return false;
347}
348
350 return isPtrOfType(
351 T, [](auto Name) { return isRefType(Name) || isCheckedPtr(Name); });
352}
353
355 return isPtrOfType(T, [](auto Name) { return isRetainPtrOrOSPtr(Name); });
356}
357
359 return isPtrOfType(T, [](auto Name) { return isOwnerPtr(Name); });
360}
361
362std::optional<bool> isUncounted(const QualType T) {
363 if (auto *Subst = dyn_cast<SubstTemplateTypeParmType>(T)) {
364 if (auto *Decl = Subst->getAssociatedDecl()) {
366 return false;
367 }
368 }
369 return isUncounted(T->getAsCXXRecordDecl());
370}
371
372std::optional<bool> isUnchecked(const QualType T) {
373 if (auto *Subst = dyn_cast<SubstTemplateTypeParmType>(T)) {
374 if (auto *Decl = Subst->getAssociatedDecl()) {
376 return false;
377 }
378 }
379 return isUnchecked(T->getAsCXXRecordDecl());
380}
381
383 const TranslationUnitDecl *TUD) {
384 IsARCEnabled = TUD->getLangOpts().ObjCAutoRefCount;
385 DefaultSynthProperties = TUD->getLangOpts().ObjCDefaultSynthProperties;
386}
387
389 auto QT = TD->getUnderlyingType();
390 if (!QT->isPointerType())
391 return;
392
393 auto PointeeQT = QT->getPointeeType();
394 const RecordType *RT = PointeeQT->getAsCanonical<RecordType>();
395 if (!RT) {
396 if (TD->hasAttr<ObjCBridgeAttr>() || TD->hasAttr<ObjCBridgeMutableAttr>()) {
397 RecordlessTypes.insert(TD->getASTContext()
399 /*Qualifier=*/std::nullopt, TD)
400 .getTypePtr());
401 }
402 return;
403 }
404
405 for (auto *Redecl : RT->getDecl()->getMostRecentDecl()->redecls()) {
406 if (Redecl->getAttr<ObjCBridgeAttr>() ||
407 Redecl->getAttr<ObjCBridgeMutableAttr>()) {
408 CFPointees.insert({RT, TD});
409 return;
410 }
411 }
412}
413
414bool RetainTypeChecker::isUnretained(const QualType QT, bool ignoreARC) {
415 if (ento::cocoa::isCocoaObjectRef(QT) && (!IsARCEnabled || ignoreARC))
416 return true;
417 if (auto *RT = dyn_cast_or_null<RecordType>(
419 return CFPointees.contains(RT);
420 return RecordlessTypes.contains(QT.getTypePtr());
421}
422
424 if (auto *TT = dyn_cast_or_null<TypedefType>(QT.getTypePtrOrNull())) {
425 if (auto *TD = dyn_cast<TypedefDecl>(TT->getDecl()))
426 return TD;
427 }
428 QT = QT.getCanonicalType();
429 auto PointeeQT = QT->getPointeeType();
430 auto *PointeeType = PointeeQT.getTypePtrOrNull();
431 if (!PointeeType)
432 return nullptr;
433 auto *RD = dyn_cast<RecordType>(PointeeType);
434 if (!RD)
435 return nullptr;
436 return CFPointees.lookup(RD);
437}
438
439std::optional<bool> isUncounted(const CXXRecordDecl* Class)
440{
441 // Keep isRefCounted first as it's cheaper.
442 if (!Class || isRefCounted(Class))
443 return false;
444
445 std::optional<bool> IsRefCountable = isRefCountable(Class);
446 if (!IsRefCountable)
447 return std::nullopt;
448
449 return (*IsRefCountable);
450}
451
452std::optional<bool> isUnchecked(const CXXRecordDecl *Class) {
453 if (!Class || isCheckedPtr(Class))
454 return false; // Cheaper than below
456}
457
458std::optional<bool> isUncountedPtr(const QualType T) {
459 if (T->isPointerType() || T->isReferenceType()) {
460 if (auto *CXXRD = T->getPointeeCXXRecordDecl())
461 return isUncounted(CXXRD);
462 }
463 return false;
464}
465
466std::optional<bool> isUncheckedPtr(const QualType T) {
467 if (T->isPointerType() || T->isReferenceType()) {
468 if (auto *CXXRD = T->getPointeeCXXRecordDecl())
469 return isUnchecked(CXXRD);
470 }
471 return false;
472}
473
474std::optional<bool> isGetterOfSafePtr(const CXXMethodDecl *M) {
475 assert(M);
476
477 const CXXRecordDecl *calleeMethodsClass = M->getParent();
478 std::string className = safeGetName(calleeMethodsClass);
479 std::string method = safeGetName(M);
480
481 auto OpType = M->getOverloadedOperator();
482 if (isCheckedPtr(className) &&
483 (method == "get" || method == "ptr" || OpType == OO_Star))
484 return true;
485
486 if ((isRefType(className) &&
487 (method == "get" || method == "ptr" || OpType == OO_Star)) ||
488 ((className == "String" || className == "AtomString" ||
489 className == "AtomStringImpl" || className == "UniqueString" ||
490 className == "UniqueStringImpl" || className == "Identifier") &&
491 method == "impl"))
492 return true;
493
494 if (isRetainPtrOrOSPtr(className) && method == "get")
495 return true;
496
497 // Ref<T> -> T conversion
498 // FIXME: Currently allowing any Ref<T> -> whatever cast.
499 if (isRefType(className)) {
500 if (auto *maybeRefToRawOperator = dyn_cast<CXXConversionDecl>(M)) {
501 QualType QT = maybeRefToRawOperator->getConversionType();
502 const Type *T = QT.getTypePtrOrNull();
503 return T && (T->isPointerType() || T->isReferenceType());
504 }
505 }
506
507 if (isCheckedPtr(className)) {
508 if (auto *maybeRefToRawOperator = dyn_cast<CXXConversionDecl>(M)) {
509 QualType QT = maybeRefToRawOperator->getConversionType();
510 const Type *T = QT.getTypePtrOrNull();
511 return T && (T->isPointerType() || T->isReferenceType());
512 }
513 }
514
515 if (isRetainPtrOrOSPtr(className)) {
516 if (auto *maybeRefToRawOperator = dyn_cast<CXXConversionDecl>(M)) {
517 QualType QT = maybeRefToRawOperator->getConversionType();
518 const Type *T = QT.getTypePtrOrNull();
519 return T && (T->isPointerType() || T->isReferenceType() ||
520 T->isObjCObjectPointerType());
521 }
522 }
523 return false;
524}
525
527 assert(M);
529 return false;
530 auto method = safeGetName(M);
531 if (method == "get" || method == "ptr")
532 return true;
533 if (auto *conversion = dyn_cast<CXXConversionDecl>(M)) {
534 const Type *T = conversion->getConversionType().getTypePtrOrNull();
535 return T && (T->isPointerType() || T->isReferenceType());
536 }
537 return false;
538}
539
540// The object lives until the program exits but a pointer stored in it doesn't
541// keep its pointee alive. A smart pointer keeps its pointee alive only if it
542// can't be reassigned or swapped.
544 if (T.isNull() || T->isPointerType() || T->isReferenceType() ||
545 T->isObjCObjectPointerType())
546 return false;
547 auto Name = safeGetName(T->getAsCXXRecordDecl());
548 if (isSmartPtrClass(Name) || isOwnerPtr(Name))
549 return T.isConstQualified();
550 return true;
551}
552
553/// \returns true if \p R is NeverDestroyed or LazyNeverDestroyed which stores
554/// a non-pointer type.
556 auto *Spec = dyn_cast_or_null<ClassTemplateSpecializationDecl>(R);
557 if (!Spec)
558 return false;
559 auto Name = safeGetName(Spec);
560 if (Name != "NeverDestroyed" && Name != "LazyNeverDestroyed")
561 return false;
562 const auto &Args = Spec->getTemplateArgs();
563 return Args.size() && Args[0].getKind() == TemplateArgument::Type &&
564 isImmortalStorageType(Args[0].getAsType());
565}
566
568 assert(M);
570 return false;
571 if (safeGetName(M) == "get" || M->getOverloadedOperator() == OO_Arrow)
572 return true;
573 if (auto *Conversion = dyn_cast<CXXConversionDecl>(M)) {
574 const Type *T = Conversion->getConversionType().getTypePtrOrNull();
575 return T && (T->isPointerType() || T->isReferenceType());
576 }
577 return false;
578}
579
580bool isImmortalVar(const VarDecl *V) {
581 assert(V);
582 if (!V->hasGlobalStorage())
583 return false;
584 QualType T = V->getType();
585 if (V->hasAttr<NoDestroyAttr>() && isImmortalStorageType(T))
586 return true;
587 return isNeverDestroyedOfObject(T->getAsCXXRecordDecl());
588}
589
591 assert(R);
592 if (auto *TmplR = R->getTemplateInstantiationPattern()) {
593 // FIXME: String/AtomString/UniqueString
594 const auto &ClassName = safeGetName(TmplR);
595 return isRefType(ClassName);
596 }
597 return false;
598}
599
601 assert(R);
602 if (auto *TmplR = R->getTemplateInstantiationPattern()) {
603 const auto &ClassName = safeGetName(TmplR);
604 return isCheckedPtr(ClassName);
605 }
606 return false;
607}
608
610 assert(R);
611 if (auto *TmplR = R->getTemplateInstantiationPattern())
612 return isRetainPtrOrOSPtr(safeGetName(TmplR));
613 return false;
614}
615
616bool isWeakPtr(const CXXRecordDecl *R) {
617 assert(R);
618 if (auto *TmplR = R->getTemplateInstantiationPattern())
619 return isWeakPtrClass(safeGetName(TmplR));
620 return false;
621}
622
623bool isSmartPtr(const CXXRecordDecl *R) {
624 assert(R);
625 if (auto *TmplR = R->getTemplateInstantiationPattern())
626 return isSmartPtrClass(safeGetName(TmplR));
627 return false;
628}
629
635
636static WebKitAnnotation annotationType(StringRef Annotation) {
637 if (Annotation == "webkit.pointerconversion")
639 if (Annotation == "webkit.nodelete")
642}
643
645 WebKitAnnotation TargetAnnotation) {
646 for (auto *Attr : FD->specific_attrs<AnnotateAttr>()) {
647 if (annotationType(Attr->getAnnotation()) == TargetAnnotation)
648 return true;
649 }
650 auto RetType = FD->getReturnType();
651 auto *Type = RetType.getTypePtrOrNull();
652 if (auto *MacroQualified = dyn_cast_or_null<MacroQualifiedType>(Type))
653 Type = MacroQualified->desugar().getTypePtrOrNull();
654 auto *Attr = dyn_cast_or_null<AttributedType>(Type);
655 if (!Attr)
656 return false;
657 auto *AnnotateType = dyn_cast_or_null<AnnotateTypeAttr>(Attr->getAttr());
658 if (!AnnotateType)
659 return false;
660 return annotationType(AnnotateType->getAnnotation()) == TargetAnnotation;
661}
662
664 assert(F);
665 if (isCtorOfRefCounted(F))
666 return true;
667
668 // FIXME: check # of params == 1
669 const auto FunctionName = safeGetName(F);
670 if (FunctionName == "getPtr" || FunctionName == "WeakPtr" ||
671 FunctionName == "dynamicDowncast" || FunctionName == "downcast" ||
672 FunctionName == "checkedDowncast" || FunctionName == "bit_cast" ||
673 FunctionName == "uncheckedDowncast" || FunctionName == "bitwise_cast" ||
674 FunctionName == "bridge_cast" || FunctionName == "bridge_id_cast" ||
675 FunctionName == "dynamic_cf_cast" || FunctionName == "checked_cf_cast" ||
676 FunctionName == "dynamic_objc_cast" ||
677 FunctionName == "checked_objc_cast")
678 return true;
679
681 return true;
682
683 return false;
684}
685
689
691 if (llvm::any_of(F->redecls(), isNoDeleteFunctionDecl))
692 return true;
693
694 const auto *MD = dyn_cast<CXXMethodDecl>(F);
695 if (!MD || !MD->isVirtual())
696 return false;
697
698 auto Overriders = llvm::to_vector(MD->overridden_methods());
699 while (!Overriders.empty()) {
700 const auto *Fn = Overriders.pop_back_val();
701 llvm::append_range(Overriders, Fn->overridden_methods());
703 return true;
704 }
705
706 return false;
707}
708
710 if (!F || !F->getDeclName().isIdentifier())
711 return false;
712 auto Name = F->getName();
713 return Name.starts_with("__builtin") || Name == "__libcpp_verbose_abort" ||
714 Name.starts_with("os_log") || Name.starts_with("_os_log");
715}
716
717bool isSingleton(const NamedDecl *F) {
718 assert(F);
719 // FIXME: check # of params == 1
720 if (auto *MethodDecl = dyn_cast<CXXMethodDecl>(F)) {
721 if (!MethodDecl->isStatic())
722 return false;
723 }
724 const auto &NameStr = safeGetName(F);
725 StringRef Name = NameStr; // FIXME: Make safeGetName return StringRef.
726 return Name == "singleton" || Name.ends_with("Singleton");
727}
728
729// We only care about statements so let's use the simple
730// (non-recursive) visitor.
732 : public ConstStmtVisitor<TrivialFunctionAnalysisVisitor, bool> {
734
735 // Returns false if at least one child is non-trivial.
736 bool VisitChildren(const Stmt *S) {
737 for (const Stmt *Child : S->children()) {
738 if (Child && !Visit(Child))
739 return false;
740 }
741
742 return true;
743 }
744
745 bool canUseCachedResult(bool CachedResult) const {
746 return CachedResult || !CallStack;
747 }
748
749 template <typename StmtOrDecl, typename CheckFunction>
750 bool WithCachedResult(const StmtOrDecl *S, CheckFunction Function) {
751 auto CacheIt = Cache.find(S);
752 if (CacheIt != Cache.end() && canUseCachedResult(CacheIt->second))
753 return CacheIt->second;
754
755 // Treat a recursive statement to be trivial until proven otherwise.
756 auto [RecursiveIt, IsNew] = RecursiveFn.insert(std::make_pair(S, true));
757 if (!IsNew)
758 return RecursiveIt->second;
759
760 bool Result = Function();
761
762 if (!Result) {
763 for (auto &It : RecursiveFn)
764 It.second = false;
765 }
766 RecursiveIt = RecursiveFn.find(S);
767 assert(RecursiveIt != RecursiveFn.end());
768 Result = RecursiveIt->second;
769 RecursiveFn.erase(RecursiveIt);
770 Cache[S] = Result;
771
772 return Result;
773 }
774
775 static bool isTrivialType(QualType Ty) {
776 // T*, T&, or T&& does not delete.
777 if (Ty->isPointerOrReferenceType())
778 return true;
779
780 // Fundamental types (integral, nullptr, etc...) does not delete.
782 return true;
783
784 return false;
785 }
786
787 bool CanTriviallyDestruct(QualType Ty) {
788 if (Ty.isNull())
789 return false;
790
791 // FIXME: Handle a case when there is a local autorelease pool.
792 if (Ty->isObjCObjectPointerType()) {
793 auto Type = Ty.isDestructedType();
795 return true;
796 // strong lifetime in ARC could dealloc an object.
797 }
798
799 if (isTrivialType(Ty))
800 return true;
801
802 if (const auto *R = Ty->getAsCXXRecordDecl()) {
803 // C++ trivially destructible classes are fine.
804 if (R->hasDefinition() && R->hasTrivialDestructor())
805 return true;
806
807 if (auto *Dtor = R->getDestructor()) {
808 if (isNoDeleteFunction(Dtor))
809 return true;
810 }
811
813 return false;
814
815 // For Webkit, side-effects are fine as long as we don't delete objects,
816 // so check recursively.
817 if (const auto *Dtor = R->getDestructor())
818 return IsFunctionTrivial(Dtor);
819 }
820
821 // Structs in C are trivial.
822 if (Ty->isRecordType())
823 return true;
824
825 // For arrays it depends on the element type.
826 // FIXME: We should really use ASTContext::getAsArrayType instead.
827 if (const auto *AT = Ty->getAsArrayTypeUnsafe())
828 return CanTriviallyDestruct(AT->getElementType());
829
830 return false; // Otherwise it's likely not trivial.
831 }
832
833 bool CanTriviallyConstruct(QualType Ty) {
834 if (Ty.isNull())
835 return false;
836
837 if (isTrivialType(Ty))
838 return true;
839
840 if (const auto *R = Ty->getAsCXXRecordDecl()) {
841 // C++ trivially destructible classes are fine.
842 if (R->hasDefinition() && R->hasTrivialDefaultConstructor())
843 return true;
844 for (auto *Ctor : R->ctors()) {
845 if (Ctor->isDefaultConstructor() && IsFunctionTrivial(Ctor))
846 return true;
847 }
848 }
849
850 return false;
851 }
852
853 template <typename CacheTy, typename IsTrivialTypeFn>
854 bool hasNonTrivialField(const CXXRecordDecl *Cls,
855 const FieldDecl **OffendingField, CacheTy &Cache,
856 IsTrivialTypeFn IsTrivialType) {
857 auto CacheIt = Cache.find(Cls);
858 if (CacheIt != Cache.end() && !OffendingField)
859 return CacheIt->second;
860
861 bool Result = ([&] {
862 auto HasNonTrivialField = [&](const CXXRecordDecl *R) {
863 for (const FieldDecl *F : R->fields()) {
864 if (!IsTrivialType(F->getType())) {
865 if (OffendingField)
866 *OffendingField = F;
867 return true;
868 }
869 }
870 return false;
871 };
872
873 if (HasNonTrivialField(Cls))
874 return true;
875
876 if (!Cls->hasDefinition())
877 return false;
878
879 CXXBasePaths Paths;
880 Paths.setOrigin(const_cast<CXXRecordDecl *>(Cls));
881 return Cls->lookupInBases(
882 [&](const CXXBaseSpecifier *B, CXXBasePath &) {
883 auto *T = B->getType().getTypePtrOrNull();
884 if (!T)
885 return false;
886 auto *R = T->getAsCXXRecordDecl();
887 return R && HasNonTrivialField(R);
888 },
889 Paths, /*LookupInDependent =*/true);
890 })();
891
892 Cache[Cls] = Result;
893
894 return Result;
895 }
896
897public:
898 using CacheTy = TrivialFunctionAnalysis::CacheTy;
899
901 NonTrivialityReason *Reason = nullptr)
902 : Cache(Cache), OffendingStmt(Reason ? &Reason->OffendingStmt : nullptr),
903 CallStack(Reason ? &Reason->CallStack : nullptr) {}
904
905 // Hides ConstStmtVisitor::Visit so that every recursive step in this class
906 // funnels through here. Recursion unwinds innermost-first, so the first
907 // statement recorded is the deepest one that failed -- the code actually
908 // responsible, rather than the enclosing statement that contains it.
909 // Implicit nodes have no location to point at, so they are passed over in
910 // favour of the nearest enclosing node that was actually written.
911 bool Visit(const Stmt *S) {
912 bool Result = Base::Visit(S);
913 if (!Result && OffendingStmt && !*OffendingStmt &&
914 S->getBeginLoc().isValid())
915 *OffendingStmt = S;
916 return Result;
917 }
918
919 bool IsFunctionTrivial(const Decl *D) {
920 if (!CallStack)
921 return IsFunctionTrivialImpl(D);
922
923 const auto *FnDecl = dyn_cast<FunctionDecl>(D);
924 if (!FnDecl)
925 return IsFunctionTrivialImpl(D);
926
927 // CallStack[0, ActiveDepth) mirrors the functions currently being
928 // analyzed. Anything past that was left by a callee whose failure was
929 // tolerated, e.g. one of several candidate default constructors, and is
930 // not part of the chain that explains this call.
931 CallStack->truncate(ActiveDepth);
932 size_t Index = ActiveDepth++;
933 CallStack->push_back({FnDecl, nullptr});
934
935 // Blame is recorded separately for each function, so that every frame
936 // can point at the code within it that leads further down the chain.
937 const Stmt *CalleeOffendingStmt = nullptr;
938 const Stmt **SavedOffendingStmt =
939 std::exchange(OffendingStmt, &CalleeOffendingStmt);
941 OffendingStmt = SavedOffendingStmt;
942
943 --ActiveDepth;
944 // On failure, keep this frame along with the frames its body left behind:
945 // together they are the chain from here down to the root cause.
946 if (Result)
947 CallStack->truncate(Index);
948 else
949 (*CallStack)[Index].OffendingStmt = CalleeOffendingStmt;
950 return Result;
951 }
952
954 return WithCachedResult(D, [&]() {
955 auto *FnDecl = dyn_cast<FunctionDecl>(D);
956 auto *MethodDecl = dyn_cast<CXXMethodDecl>(D);
957 auto *CtorDecl = dyn_cast<CXXConstructorDecl>(D);
958 auto *DtorDecl = dyn_cast<CXXDestructorDecl>(D);
959
960 if (FnDecl) {
961 if (isNoDeleteFunction(FnDecl))
962 return true;
963 if (MethodDecl && MethodDecl->isVirtual())
964 return false;
965 for (auto *Param : FnDecl->parameters()) {
966 if (!HasTrivialDestructor(Param))
967 return false;
968 }
969 }
970 if (CtorDecl) {
971 for (auto *CtorInit : CtorDecl->inits()) {
972 if (!Visit(CtorInit->getInit()))
973 return false;
974 }
975 }
976 // An implicit or =default special member runs no user code when it is
977 // trivial in the C++ standard sense, so it cannot delete. Such a
978 // member's synthesized body is typically absent from the AST until
979 // codegen materialises it, which the generic null-body check below
980 // would otherwise conservatively classify as non-trivial.
981 if (MethodDecl && !MethodDecl->isUserProvided()) {
982 if (CtorDecl) {
983 const CXXRecordDecl *RD = CtorDecl->getParent();
984 if ((CtorDecl->isDefaultConstructor() &&
986 (CtorDecl->isCopyConstructor() &&
988 (CtorDecl->isMoveConstructor() &&
990 return true;
991 }
992 if (DtorDecl && DtorDecl->getParent()->hasTrivialDestructor())
993 return true;
994 }
995 const Stmt *Body = D->getBody();
996 if (!Body)
997 return false;
998 return Visit(Body);
999 });
1000 }
1001
1003 return WithCachedResult(
1004 VD, [&] { return CanTriviallyDestruct(VD->getType()); });
1005 }
1006
1008 const FieldDecl *OffendingField = nullptr;
1009 hasNonTrivialField(
1010 Cls, &OffendingField, FieldCtorCache,
1011 [&](const QualType Ty) { return CanTriviallyConstruct(Ty); });
1012 return OffendingField;
1013 }
1014
1016 const FieldDecl *OffendingField = nullptr;
1017 hasNonTrivialField(
1018 Cls, &OffendingField, FieldDtorCache,
1019 [&](const QualType Ty) { return CanTriviallyDestruct(Ty); });
1020 return OffendingField;
1021 }
1022
1023 bool IsStatementTrivial(const Stmt *S) {
1024 auto CacheIt = Cache.find(S);
1025 if (CacheIt != Cache.end() && canUseCachedResult(CacheIt->second))
1026 return CacheIt->second;
1027 bool Result = Visit(S);
1028 Cache[S] = Result;
1029 return Result;
1030 }
1031
1032 bool VisitStmt(const Stmt *S) {
1033 // All statements are non-trivial unless overriden later.
1034 // Don't even recurse into children by default.
1035 return false;
1036 }
1037
1039 // Ignore attributes.
1040 return Visit(AS->getSubStmt());
1041 }
1042
1044 // A compound statement is allowed as long each individual sub-statement
1045 // is trivial.
1046 return WithCachedResult(CS, [&]() { return VisitChildren(CS); });
1047 }
1048
1050 return WithCachedResult(CBS, [&]() { return VisitChildren(CBS); });
1051 }
1052
1053 bool VisitReturnStmt(const ReturnStmt *RS) {
1054 // A return statement is allowed as long as the return value is trivial. A
1055 // returned smart-pointer prvalue is special: under guaranteed copy elision
1056 // the temporary *is* the function's return slot, so it is destructed by the
1057 // caller, not here. Hence we may ignore that temporary's destructor.
1058 if (auto *RV = RS->getRetValue())
1059 return visitReturnValueElidingTemp(RV);
1060 return true;
1061 }
1062
1063 bool VisitDeclStmt(const DeclStmt *DS) {
1064 for (auto &Decl : DS->decls()) {
1065 // FIXME: Handle DecompositionDecls.
1066 if (auto *VD = dyn_cast<VarDecl>(Decl)) {
1067 if (!HasTrivialDestructor(VD))
1068 return false;
1069 }
1070 }
1071 return VisitChildren(DS);
1072 }
1073 bool VisitDoStmt(const DoStmt *DS) { return VisitChildren(DS); }
1074 bool VisitIfStmt(const IfStmt *IS) {
1075 return WithCachedResult(IS, [&]() { return VisitChildren(IS); });
1076 }
1077 bool VisitForStmt(const ForStmt *FS) {
1078 return WithCachedResult(FS, [&]() { return VisitChildren(FS); });
1079 }
1081 return WithCachedResult(FS, [&]() { return VisitChildren(FS); });
1082 }
1083 bool VisitWhileStmt(const WhileStmt *WS) {
1084 return WithCachedResult(WS, [&]() { return VisitChildren(WS); });
1085 }
1086 bool VisitSwitchStmt(const SwitchStmt *SS) { return VisitChildren(SS); }
1087 bool VisitCaseStmt(const CaseStmt *CS) { return VisitChildren(CS); }
1088 bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); }
1089
1090 // break, continue, goto, and label statements are always trivial.
1091 bool VisitBreakStmt(const BreakStmt *) { return true; }
1092 bool VisitContinueStmt(const ContinueStmt *) { return true; }
1093 bool VisitGotoStmt(const GotoStmt *) { return true; }
1094 bool VisitLabelStmt(const LabelStmt *) { return true; }
1095
1097 // Unary operators are trivial if its operand is trivial except co_await.
1098 return UO->getOpcode() != UO_Coawait && Visit(UO->getSubExpr());
1099 }
1100
1102 // Binary operators are trivial if their operands are trivial.
1103 return Visit(BO->getLHS()) && Visit(BO->getRHS());
1104 }
1105
1107 // Compound assignment operator such as |= is trivial if its
1108 // subexpresssions are trivial.
1109 return VisitChildren(CAO);
1110 }
1111
1113 return VisitChildren(ASE);
1114 }
1115
1117 // Ternary operators are trivial if their conditions & values are trivial.
1118 return VisitChildren(CO);
1119 }
1120
1121 bool VisitAtomicExpr(const AtomicExpr *E) { return VisitChildren(E); }
1122
1124 // Any static_assert is considered trivial.
1125 return true;
1126 }
1127
1128 bool VisitCallExpr(const CallExpr *CE) {
1129 if (!checkArguments(CE))
1130 return false;
1131
1132 auto *Callee = CE->getDirectCallee();
1133 if (!Callee)
1134 return false;
1135
1136 if (isPtrConversion(Callee))
1137 return true;
1138
1139 const auto &Name = safeGetName(Callee);
1140
1141 if (Callee->isInStdNamespace() &&
1142 (Name == "addressof" || Name == "forward" || Name == "move"))
1143 return true;
1144
1145 if (Name == "WTFCrashWithInfo" || Name == "WTFBreakpointTrap" ||
1146 Name == "WTFReportBacktrace" ||
1147 Name == "WTFCrashWithSecurityImplication" || Name == "WTFCrash" ||
1148 Name == "WTFReportAssertionFailure" || Name == "isMainThread" ||
1149 Name == "isMainThreadOrGCThread" || Name == "isMainRunLoop" ||
1150 Name == "isWebThread" || Name == "isUIThread" ||
1151 Name == "mayBeGCThread" || Name == "compilerFenceForCrash" ||
1153 return true;
1154
1155 return IsFunctionTrivial(Callee);
1156 }
1157
1158 bool VisitGCCAsmStmt(const GCCAsmStmt *AS) {
1159 return AS->getAsmString() == "brk #0xc471";
1160 }
1161
1162 bool
1164 // Non-type template paramter is compile time constant and trivial.
1165 return true;
1166 }
1167
1169 return VisitChildren(E);
1170 }
1171
1173 // A predefined identifier such as "func" is considered trivial.
1174 return true;
1175 }
1176
1178 // offsetof(T, D) is considered trivial.
1179 return true;
1180 }
1181
1183 if (!checkArguments(MCE))
1184 return false;
1185
1186 bool TrivialThis = Visit(MCE->getImplicitObjectArgument());
1187 if (!TrivialThis)
1188 return false;
1189
1190 auto *Callee = MCE->getMethodDecl();
1191 if (!Callee)
1192 return false;
1193
1194 if (isa<CXXDestructorDecl>(Callee) &&
1195 !CanTriviallyDestruct(MCE->getObjectType()))
1196 return false;
1197
1198 auto Name = safeGetName(Callee);
1199 if (Name == "ref" || Name == "incrementCheckedPtrCount")
1200 return true;
1201
1202 std::optional<bool> IsGetterOfRefCounted = isGetterOfSafePtr(Callee);
1203 if (IsGetterOfRefCounted && *IsGetterOfRefCounted)
1204 return true;
1205
1206 // Recursively descend into the callee to confirm that it's trivial as well.
1207 return IsFunctionTrivial(Callee);
1208 }
1209
1211 if (!checkArguments(OCE))
1212 return false;
1213 auto *Callee = OCE->getCalleeDecl();
1214 if (!Callee)
1215 return false;
1216 // Recursively descend into the callee to confirm that it's trivial as well.
1217 return IsFunctionTrivial(Callee);
1218 }
1219
1221 auto *SemanticExpr = Op->getSemanticForm();
1222 return SemanticExpr && Visit(SemanticExpr);
1223 }
1224
1226 if (auto *Expr = E->getExpr()) {
1227 if (!Visit(Expr))
1228 return false;
1229 }
1230 return true;
1231 }
1232
1234 return Visit(E->getExpr());
1235 }
1236
1237 bool checkArguments(const CallExpr *CE) {
1238 for (const Expr *Arg : CE->arguments()) {
1239 if (Arg && !Visit(Arg))
1240 return false;
1241 }
1242 return true;
1243 }
1244
1245 // Triviality check for a return value that may elide a smart-pointer
1246 // temporary's destructor.
1247 //
1248 // This is only valid for *return values*: a returned class prvalue is
1249 // constructed directly into the function's return slot (C++17 guaranteed copy
1250 // elision), so the temporary is destructed by the caller rather than here.
1251 //
1252 // It is deliberately NOT applied to call/constructor arguments. An argument
1253 // temporary's lifetime ends at the full-expression *in this function* (the
1254 // caller destroys arguments, e.g. per the Itanium C++ ABI), so its destructor
1255 // runs here and may invoke delete. Proving otherwise would require
1256 // interprocedural ownership analysis, so arguments are checked normally.
1258 QualType OriginalQT = Arg->getType();
1259 auto *Type = OriginalQT.getTypePtrOrNull();
1260 if (!Type)
1261 return Visit(Arg);
1262 auto *CXXRD = Type->getAsCXXRecordDecl();
1263 if (!CXXRD || !isSmartPtrClass(safeGetName(CXXRD)))
1264 return Visit(Arg);
1265 Arg = Arg->IgnoreParenCasts();
1266 if (!Arg->isPRValue())
1267 return Visit(Arg);
1268 if (auto *Init = dyn_cast<InitListExpr>(Arg)) {
1269 if (Init->getNumInits() == 1)
1270 Arg = Init->getInit(0);
1271 }
1272 if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Arg)) {
1273 // Only elide when the temporary *is* the returned object, i.e. it has the
1274 // same smart-pointer type as the return value. Compare canonical,
1275 // unqualified types rather than relying on exact QualType identity, which
1276 // is sensitive to sugar (typedefs/aliases) and cv-qualifiers.
1277 if (OriginalQT.getCanonicalType().getUnqualifiedType() ==
1278 BTE->getType().getCanonicalType().getUnqualifiedType())
1279 return Visit(BTE->getSubExpr());
1280 }
1281 return Visit(Arg);
1282 }
1283
1285 if (CE->getNumArgs() == 1) {
1286 auto *InnerArg = CE->getArg(0);
1287 if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(InnerArg)) {
1288 auto *InnerExpr = MTE->getSubExpr();
1289 if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(InnerExpr))
1290 InnerExpr = BTE->getSubExpr();
1291 auto InnerQT = InnerExpr->getType();
1292 if (auto *InnerDecl = InnerQT->getAsCXXRecordDecl()) {
1293 auto *OuterCls = CE->getConstructor()->getParent();
1294 if (isRefType(safeGetName(OuterCls)) &&
1295 isRefType(safeGetName(InnerDecl)))
1296 return Visit(InnerExpr);
1297 }
1298 }
1299 }
1300
1301 for (const Expr *Arg : CE->arguments()) {
1302 if (Arg && !Visit(Arg))
1303 return false;
1304 }
1305
1306 // Recursively descend into the callee to confirm that it's trivial.
1307 return IsFunctionTrivial(CE->getConstructor());
1308 }
1309
1313
1314 bool VisitCXXNewExpr(const CXXNewExpr *NE) { return VisitChildren(NE); }
1315
1317 return Visit(ICE->getSubExpr());
1318 }
1319
1321 return Visit(ECE->getSubExpr());
1322 }
1323
1325 if (auto *ICE = dyn_cast<ImplicitCastExpr>(VMT->getSubExpr());
1326 ICE && ICE->getCastKind() == CK_NoOp &&
1327 ICE->getType().isConstQualified()) {
1328 if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(ICE->getSubExpr());
1329 BTE && isNullSmartPtr(BTE->getSubExpr()))
1330 return Visit(BTE->getSubExpr());
1331 }
1332 return Visit(VMT->getSubExpr());
1333 }
1334
1335 // Returns true if E is known to evaluate to a smart pointer which holds
1336 // nullptr, e.g. RefPtr<T>(), RefPtr<T>(nullptr), Ref<T>(HashTableEmptyValue),
1337 // or a call to a function which simply returns one such as
1338 // HashTraits<Ref<T>>::emptyValue(). Destructing such a smart pointer can't
1339 // delete anything.
1340 bool isNullSmartPtr(const Expr *E, unsigned Depth = 0) {
1341 if (!E || Depth > 4)
1342 return false;
1343 while (true) {
1344 E = E->IgnoreParenCasts();
1345 if (auto *EWC = dyn_cast<ExprWithCleanups>(E))
1346 E = EWC->getSubExpr();
1347 else if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
1348 E = MTE->getSubExpr();
1349 else if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E))
1350 E = BTE->getSubExpr();
1351 else
1352 break;
1353 }
1354 if (auto *CE = dyn_cast<CXXConstructExpr>(E)) {
1355 auto *Ctor = CE->getConstructor();
1356 if (!Ctor || !isOwnerPtr(safeGetName(Ctor->getParent())))
1357 return false;
1358 if (Ctor->isDefaultConstructor())
1359 return true;
1360 if (CE->getNumArgs() != 1)
1361 return false;
1362 auto *Arg = CE->getArg(0)->IgnoreParenImpCasts();
1363 auto ArgType = Arg->getType();
1364 if (ArgType->isNullPtrType())
1365 return true;
1366 if (auto *TD = ArgType->getAsTagDecl();
1367 TD && safeGetName(TD) == "HashTableEmptyValueType")
1368 return true;
1369 if (Ctor->isCopyOrMoveConstructor())
1370 return isNullSmartPtr(Arg, Depth + 1);
1371 return false;
1372 }
1373 if (auto *CE = dyn_cast<CallExpr>(E)) {
1374 auto *Callee = CE->getDirectCallee();
1375 if (!Callee)
1376 return false;
1377 if (auto *MD = dyn_cast<CXXMethodDecl>(Callee); MD && MD->isVirtual())
1378 return false;
1379 auto *Body = dyn_cast_or_null<CompoundStmt>(Callee->getBody());
1380 if (!Body || Body->size() != 1)
1381 return false;
1382 auto *RS = dyn_cast<ReturnStmt>(Body->body_front());
1383 return RS && isNullSmartPtr(RS->getRetValue(), Depth + 1);
1384 }
1385 return false;
1386 }
1387
1389 if (auto *Temp = BTE->getTemporary()) {
1390 if (!IsFunctionTrivial(Temp->getDestructor()))
1391 return false;
1392 }
1393 return Visit(BTE->getSubExpr());
1394 }
1395
1397 return Visit(AILE->getCommonExpr()) && Visit(AILE->getSubExpr());
1398 }
1399
1401 return true; // The current array index in VisitArrayInitLoopExpr is always
1402 // trivial.
1403 }
1404
1406 return Visit(OVE->getSourceExpr());
1407 }
1408
1410 return Visit(EWC->getSubExpr());
1411 }
1412
1413 bool VisitParenExpr(const ParenExpr *PE) { return Visit(PE->getSubExpr()); }
1414
1416 for (const Expr *Child : ILE->inits()) {
1417 if (Child && !Visit(Child))
1418 return false;
1419 }
1420 return true;
1421 }
1422
1424 auto *SubExpr = ILE->getSubExpr();
1425 if (!SubExpr)
1426 return false;
1427 // The backing array of a std::initializer_list is a temporary whose
1428 // lifetime ends in this function, so its elements are destructed here.
1429 if (!CanTriviallyDestruct(SubExpr->getType()))
1430 return false;
1431 return Visit(SubExpr);
1432 }
1433
1434 bool VisitMemberExpr(const MemberExpr *ME) {
1435 // Field access is allowed but the base pointer may itself be non-trivial.
1436 return Visit(ME->getBase());
1437 }
1438
1440 // The expression 'this' is always trivial, be it explicit or implicit.
1441 return true;
1442 }
1443
1445 // nullptr is trivial.
1446 return true;
1447 }
1448
1450 // The use of a variable is trivial.
1451 return true;
1452 }
1453
1454 // Constant literal expressions are always trivial
1455 bool VisitIntegerLiteral(const IntegerLiteral *E) { return true; }
1456 bool VisitFloatingLiteral(const FloatingLiteral *E) { return true; }
1457 bool VisitFixedPointLiteral(const FixedPointLiteral *E) { return true; }
1458 bool VisitCharacterLiteral(const CharacterLiteral *E) { return true; }
1459 bool VisitStringLiteral(const StringLiteral *E) { return true; }
1460 bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { return true; }
1461
1463 // Constant expressions are trivial.
1464 return true;
1465 }
1466
1468 // An implicit value initialization is trvial.
1469 return true;
1470 }
1471
1473 // A value initialization of a scalar type such as int() is trivial.
1474 return true;
1475 }
1476
1477private:
1478 CacheTy &Cache;
1479 CacheTy FieldCtorCache;
1480 CacheTy FieldDtorCache;
1481 CacheTy RecursiveFn;
1482 const Stmt **OffendingStmt;
1484 unsigned ActiveDepth = 0;
1485};
1486
1487bool TrivialFunctionAnalysis::isTrivialImpl(
1488 const Decl *D, TrivialFunctionAnalysis::CacheTy &Cache) {
1490 return V.IsFunctionTrivial(D);
1491}
1492
1493bool TrivialFunctionAnalysis::isTrivialImpl(
1494 const Stmt *S, TrivialFunctionAnalysis::CacheTy &Cache) {
1496 return V.IsStatementTrivial(S);
1497}
1498
1500 NonTrivialityReason Reason;
1501 CacheTy Cache;
1503 [[maybe_unused]] bool Trivial = V.IsStatementTrivial(S);
1504 assert(!Trivial && "computeReason called on a trivial statement");
1505 return Reason;
1506}
1507
1508bool TrivialFunctionAnalysis::hasTrivialDtorImpl(const VarDecl *VD,
1509 CacheTy &Cache) {
1511 return V.HasTrivialDestructor(VD);
1512}
1513
1514const FieldDecl *
1515TrivialFunctionAnalysis::fieldWithNonTrivialCtorImpl(const CXXRecordDecl *RD,
1516 CacheTy &Cache) {
1518 return V.FieldWithNonTrivialCtor(RD);
1519}
1520
1521const FieldDecl *
1522TrivialFunctionAnalysis::fieldWithNonTrivialDtorImpl(const CXXRecordDecl *RD,
1523 CacheTy &Cache) {
1525 return V.FieldWithNonTrivialDtor(RD);
1526}
1527
1528} // namespace clang
#define V(N, I)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
Defines the clang::Expr interface and subclasses for C++ expressions.
llvm::MachO::Record Record
Definition MachO.h:31
TypePropertyCache< Private > Cache
Definition Type.cpp:5092
QualType getTypedefType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, const TypedefNameDecl *Decl, QualType UnderlyingType=QualType(), std::optional< bool > TypeMatchesDeclOrNone=std::nullopt) const
Return the unique reference to the type for the specified typedef-name decl.
Represents the index of the current element of an array being initialized by an ArrayInitLoopExpr.
Definition Expr.h:6107
Represents a loop initializing the elements of an array.
Definition Expr.h:6054
OpaqueValueExpr * getCommonExpr() const
Get the common subexpression shared by all initializations (the source array).
Definition Expr.h:6069
Expr * getSubExpr() const
Get the initializer to use for each array element.
Definition Expr.h:6074
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Definition Expr.h:2790
AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*, __atomic_load,...
Definition Expr.h:7014
Attr - This represents one attribute.
Definition Attr.h:47
Represents an attribute applied to a statement.
Definition Stmt.h:2214
Stmt * getSubStmt()
Definition Stmt.h:2250
A builtin binary operation expression such as "x + y" or "x <= y".
Definition Expr.h:4107
Expr * getLHS() const
Definition Expr.h:4157
Expr * getRHS() const
Definition Expr.h:4159
BreakStmt - This represents a break.
Definition Stmt.h:3148
Represents a path from a specific derived class (which is not represented as part of the path) to a p...
BasePaths - Represents the set of paths from a derived class to one of its (direct or indirect) bases...
void setOrigin(const CXXRecordDecl *Rec)
Represents a base class of a C++ class.
Definition DeclCXX.h:146
QualType getType() const
Retrieves the type of the base class.
Definition DeclCXX.h:249
Represents binding an expression to a temporary.
Definition ExprCXX.h:1498
CXXTemporary * getTemporary()
Definition ExprCXX.h:1516
const Expr * getSubExpr() const
Definition ExprCXX.h:1520
A boolean literal, per ([C++ lex.bool] Boolean literals).
Definition ExprCXX.h:728
Represents a call to a C++ constructor.
Definition ExprCXX.h:1553
Expr * getArg(unsigned Arg)
Return the specified argument.
Definition ExprCXX.h:1696
arg_range arguments()
Definition ExprCXX.h:1677
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Definition ExprCXX.h:1616
unsigned getNumArgs() const
Return the number of arguments to the constructor call.
Definition ExprCXX.h:1693
Represents a C++ constructor within a class.
Definition DeclCXX.h:2645
A default argument (C++ [dcl.fct.default]).
Definition ExprCXX.h:1275
A use of a default initializer in a constructor or in aggregate initialization.
Definition ExprCXX.h:1382
Expr * getExpr()
Get the initialization expression that will be used.
Definition ExprCXX.cpp:1137
CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...
Definition StmtCXX.h:136
Represents a call to an inherited base class constructor from an inheriting constructor.
Definition ExprCXX.h:1756
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will call.
Definition ExprCXX.h:1793
Represents a call to a member function that may be written either with member call syntax (e....
Definition ExprCXX.h:184
CXXMethodDecl * getMethodDecl() const
Retrieve the declaration of the called method.
Definition ExprCXX.cpp:773
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
Definition ExprCXX.cpp:754
QualType getObjectType() const
Retrieve the type of the object argument.
Definition ExprCXX.cpp:766
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2153
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition DeclCXX.h:2296
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
Definition ExprCXX.h:2360
The null pointer literal (C++11 [lex.nullptr])
Definition ExprCXX.h:773
A call to an overloaded operator written using operator syntax.
Definition ExprCXX.h:86
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
bool hasTrivialDefaultConstructor() const
Determine whether this class has a trivial default constructor (C++11 [class.ctor]p5).
Definition DeclCXX.h:1256
bool hasTrivialMoveConstructor() const
Determine whether this class has a trivial move constructor (C++11 [class.copy]p12)
Definition DeclCXX.h:1317
bool hasTrivialCopyConstructor() const
Determine whether this class has a trivial copy constructor (C++ [class.copy]p6, C++11 [class....
Definition DeclCXX.h:1294
bool lookupInBases(BaseMatchesCallback BaseMatches, CXXBasePaths &Paths, bool LookupInDependent=false) const
Look for entities within the base classes of this C++ class, transitively searching all base class su...
bool hasDefinition() const
Definition DeclCXX.h:562
A rewritten comparison expression that was originally written using operator syntax.
Definition ExprCXX.h:291
Expr * getSemanticForm()
Get an equivalent semantic form for this expression.
Definition ExprCXX.h:309
An expression "T()" which creates an rvalue of a non-class type T.
Definition ExprCXX.h:2201
Implicit construction of a std::initializer_list<T> object from an array temporary within list-initia...
Definition ExprCXX.h:805
Represents the this expression in C++.
Definition ExprCXX.h:1159
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:3012
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3195
arg_range arguments()
Definition Expr.h:3264
Decl * getCalleeDecl()
Definition Expr.h:3189
CaseStmt - Represent a case statement.
Definition Stmt.h:1931
Expr * getSubExpr()
Definition Expr.h:3795
CompoundAssignOperator - For compound assignments (e.g.
Definition Expr.h:4369
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition Stmt.h:1751
ConditionalOperator - The ?
Definition Expr.h:4460
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
An expression that occurs in a constant context and the result of evaluating the expression.
Definition Expr.h:1127
ContinueStmt - This represents a continue.
Definition Stmt.h:3132
Represents the body of a coroutine.
Definition StmtCXX.h:321
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition DeclBase.h:2108
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1315
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition Stmt.h:1642
decl_range decls()
Definition Stmt.h:1690
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:550
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Definition DeclBase.h:1105
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
Definition DeclBase.h:568
bool hasAttr() const
Definition DeclBase.h:586
const LangOptions & getLangOpts() const LLVM_READONLY
Helper to get the language options from the ASTContext.
Definition DeclBase.cpp:556
bool isIdentifier() const
Predicate functions for querying what type of name this is.
DoStmt - This represents a 'do/while' stmt.
Definition Stmt.h:2843
ExplicitCastExpr - An explicit cast written in the source code.
Definition Expr.h:3997
Represents an expression – generally a full-expression – that introduces cleanups to be run at the en...
Definition ExprCXX.h:3715
This represents one expression.
Definition Expr.h:114
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition Expr.cpp:3134
bool isPRValue() const
Definition Expr.h:287
QualType getType() const
Definition Expr.h:146
Represents a member of a struct/union/class.
Definition Decl.h:3311
ForStmt - This represents a 'for (init;cond;inc)' stmt.
Definition Stmt.h:2899
const Expr * getSubExpr() const
Definition Expr.h:1107
Represents a function declaration or definition.
Definition Decl.h:2071
QualType getReturnType() const
Definition Decl.h:2992
redecl_range redecls() const
Returns an iterator range for all the redeclarations of the same decl.
OverloadedOperatorKind getOverloadedOperator() const
getOverloadedOperator - Which C++ overloaded operator this function represents, if any.
Definition Decl.cpp:4192
This represents a GCC inline-assembly statement extension.
Definition Stmt.h:3459
std::string getAsmString() const
Definition Stmt.cpp:574
GotoStmt - This represents a direct goto.
Definition Stmt.h:2980
IfStmt - This represents an if/then/else.
Definition Stmt.h:2270
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Definition Expr.h:3922
Represents an implicitly-generated value initialization of an object of a given type.
Definition Expr.h:6143
Describes an C or C++ initializer list.
Definition Expr.h:5377
ArrayRef< Expr * > inits() const
Definition Expr.h:5441
LabelStmt - Represents a label, which has a substatement.
Definition Stmt.h:2157
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
Definition ExprCXX.h:4974
Expr * getSubExpr() const
Retrieve the temporary-generating subexpression whose value will be materialized into a glvalue.
Definition ExprCXX.h:4991
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition Expr.h:3433
Expr * getBase() const
Definition Expr.h:3510
This represents a decl that may have a name.
Definition Decl.h:276
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:303
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition Decl.h:342
OffsetOfExpr - [C99 7.17] - This represents an expression of the form offsetof(record-type,...
Definition Expr.h:2596
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class.
Definition Expr.h:1223
Expr * getSourceExpr() const
The source expression of an opaque value expression is the expression which originally generated the ...
Definition Expr.h:1273
ParenExpr - This represents a parenthesized expression, e.g.
Definition Expr.h:2251
const Expr * getSubExpr() const
Definition Expr.h:2268
Represents a parameter to a function.
Definition Decl.h:1832
[C99 6.4.2.2] - A predefined identifier such as func.
Definition Expr.h:2074
A (possibly-)qualified type.
Definition TypeBase.h:938
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1005
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8578
QualType getCanonicalType() const
Definition TypeBase.h:8630
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition TypeBase.h:8672
DestructionKind isDestructedType() const
Returns a nonzero value if objects of this type require non-trivial work to clean up after.
Definition TypeBase.h:1561
const Type * getTypePtrOrNull() const
Definition TypeBase.h:8582
const TypedefDecl * getCanonicalDecl(QualType)
bool isUnretained(const QualType, bool ignoreARC=false)
void visitTranslationUnitDecl(const TranslationUnitDecl *)
void visitTypedef(const TypedefDecl *)
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3173
Expr * getRetValue()
Definition Stmt.h:3200
bool isValid() const
Return true if this is a valid SourceLocation object.
Represents a C++11 static_assert declaration.
Definition DeclCXX.h:4174
RetTy Visit(PTR(Stmt) S, ParamTys... P)
Definition StmtVisitor.h:45
Stmt - This represents one statement.
Definition Stmt.h:85
child_range children()
Definition Stmt.cpp:304
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Stmt.cpp:355
StringLiteral - This represents a string literal expression, e.g.
Definition Expr.h:1844
Represents a reference to a non-type template parameter that has been substituted with a template arg...
Definition ExprCXX.h:4718
SwitchStmt - This represents a 'switch' stmt.
Definition Stmt.h:2520
@ Type
The template argument is a type.
The top declaration context.
Definition Decl.h:107
bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E)
bool VisitStringLiteral(const StringLiteral *E)
bool VisitStaticAssertDecl(const StaticAssertDecl *SAD)
bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE)
bool VisitCXXThisExpr(const CXXThisExpr *CTE)
TrivialFunctionAnalysisVisitor(CacheTy &Cache, NonTrivialityReason *Reason=nullptr)
bool VisitUnaryOperator(const UnaryOperator *UO)
bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *AILE)
bool VisitPredefinedExpr(const PredefinedExpr *E)
bool VisitContinueStmt(const ContinueStmt *)
bool VisitCompoundAssignOperator(const CompoundAssignOperator *CAO)
const FieldDecl * FieldWithNonTrivialDtor(const CXXRecordDecl *Cls)
bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E)
bool VisitFixedPointLiteral(const FixedPointLiteral *E)
bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E)
bool VisitDeclRefExpr(const DeclRefExpr *DRE)
bool VisitIntegerLiteral(const IntegerLiteral *E)
bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *VMT)
bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E)
bool VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *Op)
bool VisitFloatingLiteral(const FloatingLiteral *E)
TrivialFunctionAnalysis::CacheTy CacheTy
bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *ILE)
bool VisitConditionalOperator(const ConditionalOperator *CO)
bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E)
bool VisitCompoundStmt(const CompoundStmt *CS)
bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *IVIE)
bool VisitConstantExpr(const ConstantExpr *CE)
bool VisitImplicitCastExpr(const ImplicitCastExpr *ICE)
bool VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE)
bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E)
bool VisitOpaqueValueExpr(const OpaqueValueExpr *OVE)
bool VisitExprWithCleanups(const ExprWithCleanups *EWC)
bool VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE)
bool VisitBinaryOperator(const BinaryOperator *BO)
bool VisitCoroutineBodyStmt(const CoroutineBodyStmt *CBS)
bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE)
bool VisitCXXForRangeStmt(const CXXForRangeStmt *FS)
bool VisitCharacterLiteral(const CharacterLiteral *E)
bool VisitInitListExpr(const InitListExpr *ILE)
bool VisitAttributedStmt(const AttributedStmt *AS)
bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E)
bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E)
const FieldDecl * FieldWithNonTrivialCtor(const CXXRecordDecl *Cls)
bool VisitExplicitCastExpr(const ExplicitCastExpr *ECE)
bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *AIIE)
bool VisitDefaultStmt(const DefaultStmt *DS)
bool VisitOffsetOfExpr(const OffsetOfExpr *OE)
bool VisitCXXConstructExpr(const CXXConstructExpr *CE)
bool isNullSmartPtr(const Expr *E, unsigned Depth=0)
static NonTrivialityReason computeReason(const Stmt *S)
The base class of the type hierarchy.
Definition TypeBase.h:1879
bool isFundamentalType() const
Tests whether the type is categorized as a fundamental type.
Definition TypeBase.h:8778
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:885
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
Definition TypeBase.h:9326
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition TypeBase.h:9484
bool isPointerOrReferenceType() const
Definition TypeBase.h:8819
bool isObjCObjectPointerType() const
Definition TypeBase.h:8994
const T * getAsCanonical() const
If this type is canonically the specified type, return its canonical type cast to that specified type...
Definition TypeBase.h:3002
bool isRecordType() const
Definition TypeBase.h:8942
Represents the declaration of a typedef-name via the 'typedef' type specifier.
Definition Decl.h:3818
QualType getUnderlyingType() const
Definition Decl.h:3768
UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) expression operand.
Definition Expr.h:2694
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition Expr.h:2313
Expr * getSubExpr() const
Definition Expr.h:2354
Opcode getOpcode() const
Definition Expr.h:2349
QualType getType() const
Definition Decl.h:725
Represents a variable declaration or definition.
Definition Decl.h:934
WhileStmt - This represents a 'while' stmt.
Definition Stmt.h:2708
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
bool isCocoaObjectRef(QualType T)
bool isPointerLikeType(QualType QT)
Top level wrappers for InstallAPI frontend operations.
bool isCtorOfSafePtr(const clang::FunctionDecl *F)
bool isTrivialBuiltinFunction(const FunctionDecl *F)
bool isa(CodeGen::Address addr)
Definition Address.h:330
static bool isNoDeleteFunctionDecl(const FunctionDecl *F)
bool isPtrConversion(const FunctionDecl *F)
static bool isWeakPtrClass(const std::string &Name)
QualType pointeeType(QualType T)
std::optional< bool > isCheckedPtrCapable(const clang::CXXRecordDecl *R)
@ Specialization
We are substituting template parameters for template arguments in order to form a template specializa...
Definition Template.h:50
std::optional< bool > isUnchecked(const QualType T)
QualType borrowedType(QualType T)
bool isAccessorOfNeverDestroyed(const CXXMethodDecl *M)
bool isCtorOfRefCounted(const clang::FunctionDecl *F)
bool isRefOrCheckedPtrType(const clang::QualType T)
bool isView(const clang::QualType T)
static bool hasLifetimeBoundCtor(const clang::CXXRecordDecl *R)
@ AS_public
Definition Specifiers.h:128
bool isRetainPtrOrOSPtrType(const clang::QualType T)
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
bool isGetterOfUniquePtr(const CXXMethodDecl *M)
static bool isStdRangesViewInterface(const clang::CXXRecordDecl *R)
bool isCtorOfRetainPtrOrOSPtr(const clang::FunctionDecl *F)
static bool isNeverDestroyedOfObject(const CXXRecordDecl *R)
bool isBorrow(const clang::CXXRecordDecl *R)
std::optional< bool > isBorrowable(const clang::CXXRecordDecl *R)
@ Result
The result type of a method or function.
Definition TypeBase.h:906
bool isOwnerPtr(const std::string &Name)
bool isStdView(const clang::CXXRecordDecl *R)
const FunctionProtoType * T
std::optional< bool > isRefCountable(const clang::CXXRecordDecl *R)
std::optional< const clang::CXXRecordDecl * > hasPublicMethodInBase(const CXXBaseSpecifier *Base, StringRef NameToMatch)
bool isSmartPtrClass(const std::string &Name)
bool isImmortalVar(const VarDecl *V)
std::string getConstructorName(const clang::FunctionDecl *F)
bool isRefCounted(const CXXRecordDecl *R)
static bool derivesFromViewInterface(const clang::CXXRecordDecl *R)
static bool isPtrOfType(const clang::QualType T, Predicate Pred)
std::optional< bool > isSmartPtrCompatible(const CXXRecordDecl *R, StringRef IncMethodName, StringRef DecMethodName)
bool isNoDeleteFunction(const FunctionDecl *F)
bool isOwnerPtrType(const clang::QualType T)
bool isSmartPtr(const CXXRecordDecl *R)
static bool isImmortalStorageType(QualType T)
std::optional< bool > isGetterOfSafePtr(const CXXMethodDecl *M)
bool isRetainPtrOrOSPtr(const std::string &Name)
bool isRefType(const std::string &Name)
bool isUniquePtr(const std::string &Name)
std::optional< bool > isUncountedPtr(const QualType T)
static std::optional< bool > hasPublicMethodInHierarchy(const CXXRecordDecl *R, StringRef MethodName)
std::string safeGetName(const T *ASTNode)
Definition ASTUtils.h:109
bool isCtorOfCheckedPtr(const clang::FunctionDecl *F)
bool isSingleton(const NamedDecl *F)
bool isCheckedPtr(const std::string &Name)
bool isStdOrWTFMove(const clang::FunctionDecl *F)
bool isBorrowType(const clang::QualType T)
@ None
No keyword precedes the qualified type name.
Definition TypeBase.h:6167
@ Class
The "class" keyword introduces the elaborated-type-specifier.
Definition TypeBase.h:6157
static bool hasAnnotationForFunction(const FunctionDecl *FD, WebKitAnnotation TargetAnnotation)
std::optional< bool > isUncounted(const QualType T)
static WebKitAnnotation annotationType(StringRef Annotation)
std::optional< bool > isUncheckedPtr(const QualType T)
bool isWeakPtr(const CXXRecordDecl *R)
Explains why TrivialFunctionAnalysis rejected a statement, so that a diagnostic can blame the code th...