25class RawPtrRefLambdaCapturesChecker
26 :
public Checker<check::ASTDecl<TranslationUnitDecl>> {
29 mutable BugReporter *BR =
nullptr;
30 TrivialFunctionAnalysis TFA;
33 const std::unique_ptr<PtrRefSafetyModel> Model;
36 RawPtrRefLambdaCapturesChecker(
const char *description,
37 std::unique_ptr<PtrRefSafetyModel> Model)
38 : Bug(this, description,
"WebKit coding guidelines"),
39 Model(std::move(Model)) {}
41 std::optional<bool> isUnsafePtr(QualType QT)
const {
44 bool isPtrType(
const std::string &Name)
const {
45 return Model->isPtrType(Name);
48 void checkASTDecl(
const TranslationUnitDecl *TUD, AnalysisManager &MGR,
49 BugReporter &BRArg)
const {
56 const RawPtrRefLambdaCapturesChecker *Checker;
57 llvm::DenseSet<const DeclRefExpr *> DeclRefExprsToIgnore;
58 llvm::DenseSet<const LambdaExpr *> LambdasToIgnore;
59 llvm::DenseSet<const ValueDecl *> ProtectedThisDecls;
60 llvm::DenseSet<const CallExpr *> CallToIgnore;
61 llvm::DenseSet<const CXXConstructExpr *> ConstructToIgnore;
62 llvm::DenseMap<const VarDecl *, SmallVector<const LambdaExpr *>>
67 explicit LocalVisitor(
const RawPtrRefLambdaCapturesChecker *Checker)
70 ShouldVisitTemplateInstantiations =
true;
71 ShouldVisitImplicitCode =
false;
74 bool TraverseDecl(Decl *D)
override {
85 bool TraverseCXXConstructorDecl(CXXConstructorDecl *Ctor)
override {
86 llvm::SaveAndRestore SavedDecl(ClsType);
88 return DynamicRecursiveASTVisitor::TraverseCXXConstructorDecl(Ctor);
91 bool TraverseCXXDestructorDecl(CXXDestructorDecl *Dtor)
override {
92 llvm::SaveAndRestore SavedDecl(ClsType);
93 ClsType =
Dtor->getThisType();
94 return DynamicRecursiveASTVisitor::TraverseCXXDestructorDecl(Dtor);
97 bool TraverseCXXMethodDecl(CXXMethodDecl *CXXMD)
override {
98 llvm::SaveAndRestore SavedDecl(ClsType);
105 return DynamicRecursiveASTVisitor::TraverseCXXMethodDecl(CXXMD);
108 bool TraverseObjCMethodDecl(ObjCMethodDecl *OCMD)
override {
109 llvm::SaveAndRestore SavedDecl(ClsType);
112 ClsType = ImplParamDecl->getType();
114 return DynamicRecursiveASTVisitor::TraverseObjCMethodDecl(OCMD);
117 bool VisitTypedefDecl(TypedefDecl *TD)
override {
118 if (
auto *RTC = Checker->Model->retainTypeChecker())
119 RTC->visitTypedef(TD);
123 bool shouldCheckThis() {
125 if (Checker->Model->checksForInteriorDestruction())
128 !ClsType.
isNull() ? Checker->isUnsafePtr(ClsType) : std::nullopt;
129 return result && *result;
132 bool VisitLambdaExpr(
LambdaExpr *L)
override {
133 if (LambdasToIgnore.contains(L))
135 Checker->visitLambdaExpr(L, shouldCheckThis() && !hasProtectedThis(L),
140 bool TraverseLambdaExpr(
LambdaExpr *L)
override {
143 return DynamicRecursiveASTVisitor::TraverseLambdaExpr(L);
152 if (!VisitLambdaExpr(L))
154 for (
unsigned I = 0, N = L->
capture_size(); I != N; ++I) {
161 return TraverseDecl(FTD);
164 bool VisitVarDecl(VarDecl *VD)
override {
168 if (
auto *L = dyn_cast_or_null<LambdaExpr>(
Init->IgnoreParenCasts())) {
169 LambdasToIgnore.insert(L);
174 if (
auto *E = dyn_cast<ExprWithCleanups>(
Init))
175 Init = E->getSubExpr();
176 if (
auto *E = dyn_cast<CXXBindTemporaryExpr>(
Init))
177 Init = E->getSubExpr();
178 if (
auto *CE = dyn_cast<CallExpr>(
Init)) {
179 if (
auto *Callee = CE->getDirectCallee()) {
181 unsigned ArgCnt = CE->getNumArgs();
182 if (FnName ==
"makeScopeExit" && ArgCnt == 1) {
183 auto *Arg = CE->getArg(0);
184 if (
auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
185 Arg = E->getSubExpr();
186 if (
auto *L = dyn_cast<LambdaExpr>(Arg))
187 addLambdaOwner(VD, CE, L);
188 }
else if (FnName ==
"makeVisitor") {
189 for (
unsigned ArgIndex = 0; ArgIndex < ArgCnt; ++ArgIndex) {
190 auto *Arg = CE->getArg(ArgIndex);
191 if (
auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
192 Arg = E->getSubExpr();
193 if (
auto *L = dyn_cast<LambdaExpr>(Arg))
194 addLambdaOwner(VD, CE, L);
198 }
else if (
auto *CE = dyn_cast<CXXConstructExpr>(
Init)) {
199 if (
auto *Ctor = CE->getConstructor()) {
202 unsigned ArgCnt = CE->getNumArgs();
203 if (FnName ==
"ScopeExit" && ArgCnt == 1) {
204 auto *Arg = CE->getArg(0);
205 if (
auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
206 Arg = E->getSubExpr();
207 if (
auto *L = dyn_cast<LambdaExpr>(Arg))
208 addLambdaOwner(VD, CE, L);
216 void addLambdaOwner(VarDecl *VD, CallExpr *CE,
LambdaExpr *L) {
217 auto result = LambdaOwnerMap.insert(
218 std::make_pair(VD, SmallVector<const LambdaExpr *>{L}));
220 result.first->second.push_back(L);
221 CallToIgnore.insert(CE);
222 LambdasToIgnore.insert(L);
225 void addLambdaOwner(VarDecl *VD, CXXConstructExpr *CE,
LambdaExpr *L) {
226 auto result = LambdaOwnerMap.insert(
227 std::make_pair(VD, SmallVector<const LambdaExpr *>{L}));
229 result.first->second.push_back(L);
230 ConstructToIgnore.insert(CE);
231 LambdasToIgnore.insert(L);
234 bool VisitExplicitCastExpr(ExplicitCastExpr *CE)
override {
239 DeclRefExprsToIgnore.insert(DRE);
243 bool VisitDeclRefExpr(DeclRefExpr *DRE)
override {
244 if (DeclRefExprsToIgnore.contains(DRE))
246 auto *VD = dyn_cast_or_null<VarDecl>(DRE->
getDecl());
249 if (
auto It = LambdaOwnerMap.find(VD); It != LambdaOwnerMap.end()) {
250 for (
auto *L : It->second) {
251 Checker->visitLambdaExpr(
252 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
259 auto *L = dyn_cast_or_null<LambdaExpr>(
Init->IgnoreParenCasts());
262 LambdasToIgnore.insert(L);
263 Checker->visitLambdaExpr(L, shouldCheckThis() && !hasProtectedThis(L),
268 bool shouldTreatAllArgAsNoEscape(FunctionDecl *FDecl) {
270 for (
auto *Decl = FDecl->
getParent(); Decl; Decl =
Decl->getParent()) {
273 if (
auto *NS = dyn_cast<NamespaceDecl>(Decl); NS && NS->isInline())
279 if (Name ==
"WTF" && PreviousName ==
"switchOn")
283 if (PreviousName ==
"ranges")
288 if (PreviousName ==
"call_once")
296 bool VisitCXXConstructExpr(CXXConstructExpr *CE)
override {
297 if (ConstructToIgnore.contains(CE))
300 unsigned ArgIndex = 0;
301 for (
auto *Param :
Callee->parameters()) {
305 if (
auto *L = findLambdaInArg(Arg)) {
306 LambdasToIgnore.insert(L);
307 if (!Param->hasAttr<NoEscapeAttr>())
308 Checker->visitLambdaExpr(
309 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
317 bool VisitCallExpr(CallExpr *CE)
override {
318 if (CallToIgnore.contains(CE))
320 checkCalleeLambda(CE);
322 if (isVisitFunction(CE, Callee))
324 checkParameters(CE, Callee);
325 }
else if (
auto *CalleeE = CE->
getCallee()) {
326 if (
auto *DRE = dyn_cast<DeclRefExpr>(CalleeE->IgnoreParenCasts())) {
327 if (
auto *Callee = dyn_cast_or_null<FunctionDecl>(DRE->
getDecl()))
328 checkParameters(CE, Callee);
334 bool isVisitFunction(CallExpr *CallExpr, FunctionDecl *FnDecl) {
345 if (NsName !=
"WTF" && NsName !=
"std")
347 auto *Arg = CallExpr->
getArg(0);
350 auto *DRE = dyn_cast<DeclRefExpr>(Arg->IgnoreParenCasts());
353 auto *VD = dyn_cast<VarDecl>(DRE->
getDecl());
356 if (!LambdaOwnerMap.contains(VD))
358 DeclRefExprsToIgnore.insert(DRE);
362 void checkParameters(CallExpr *CE, FunctionDecl *Callee) {
364 bool TreatAllArgsAsNoEscape = shouldTreatAllArgAsNoEscape(Callee);
365 for (
auto *Param :
Callee->parameters()) {
369 if (
auto *L = findLambdaInArg(Arg)) {
370 LambdasToIgnore.insert(L);
371 if (!Param->hasAttr<NoEscapeAttr>() && !TreatAllArgsAsNoEscape)
372 Checker->visitLambdaExpr(
373 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
380 if (
auto *Lambda = dyn_cast_or_null<LambdaExpr>(E))
382 auto *TempExpr = dyn_cast_or_null<CXXBindTemporaryExpr>(E);
388 if (
auto *Lambda = dyn_cast<LambdaExpr>(E))
390 auto *CE = dyn_cast_or_null<CXXConstructExpr>(E);
396 auto *InnerCE = dyn_cast_or_null<CXXConstructExpr>(CtorArg);
397 if (InnerCE && InnerCE->getNumArgs())
398 CtorArg = InnerCE->getArg(0)->IgnoreParenCasts();
399 auto updateIgnoreList = [&] {
400 ConstructToIgnore.insert(CE);
402 ConstructToIgnore.insert(InnerCE);
404 if (
auto *Lambda = dyn_cast<LambdaExpr>(CtorArg)) {
408 if (
auto *TempExpr = dyn_cast<CXXBindTemporaryExpr>(CtorArg)) {
410 if (
auto *Lambda = dyn_cast<LambdaExpr>(E)) {
415 auto *DRE = dyn_cast<DeclRefExpr>(CtorArg);
418 auto *VD = dyn_cast_or_null<VarDecl>(DRE->
getDecl());
424 if (
auto *Lambda = dyn_cast<LambdaExpr>(
Init)) {
425 DeclRefExprsToIgnore.insert(DRE);
432 void checkCalleeLambda(CallExpr *CE) {
437 if (
auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Callee)) {
438 Callee = MTE->getSubExpr();
443 if (
auto *L = dyn_cast<LambdaExpr>(Callee)) {
444 LambdasToIgnore.insert(L);
447 auto *DRE = dyn_cast<DeclRefExpr>(
Callee->IgnoreParenCasts());
450 auto *MD = dyn_cast_or_null<CXXMethodDecl>(DRE->
getDecl());
454 if (
auto *L = dyn_cast_or_null<LambdaExpr>(Arg)) {
455 LambdasToIgnore.insert(L);
458 auto *ArgRef = dyn_cast<DeclRefExpr>(Arg);
461 auto *VD = dyn_cast_or_null<VarDecl>(ArgRef->getDecl());
467 auto *L = dyn_cast_or_null<LambdaExpr>(
Init->IgnoreParenCasts());
470 DeclRefExprsToIgnore.insert(ArgRef);
471 LambdasToIgnore.insert(L);
475 for (
const LambdaCapture &OtherCapture : L->
captures()) {
476 if (!OtherCapture.capturesVariable())
478 if (
auto *ValueDecl = OtherCapture.getCapturedVar()) {
479 if (declProtectsThis(ValueDecl)) {
480 ProtectedThisDecls.insert(ValueDecl);
488 bool declProtectsThis(
const ValueDecl *ValueDecl)
const {
489 auto *VD = dyn_cast<VarDecl>(ValueDecl);
497 if (
auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Arg))
499 if (
auto *CE = dyn_cast<CXXConstructExpr>(Arg)) {
500 auto *Ctor = CE->getConstructor();
503 auto ArgClsTy = dyn_cast_or_null<CXXRecordDecl>(Ctor->
getParent());
504 if (Checker->Model->isSafePtr(ArgClsTy) && CE->
getNumArgs()) {
509 if (
auto *CXXR =
Type->getPointeeCXXRecordDecl()) {
519 if (
auto *CE = dyn_cast<CallExpr>(Arg)) {
528 if (
auto *OpCE = dyn_cast<CXXOperatorCallExpr>(Arg)) {
529 auto OpCode = OpCE->getOperator();
530 if (OpCode == OO_Star || OpCode == OO_Amp) {
531 auto *
Callee = OpCE->getDirectCallee();
535 if (!Checker->isPtrType(clsName) || !OpCE->getNumArgs())
541 if (
auto *UO = dyn_cast<UnaryOperator>(Arg)) {
542 auto OpCode = UO->getOpcode();
543 if (OpCode == UO_Deref || OpCode == UO_AddrOf) {
550 if (
auto *DRE = dyn_cast<DeclRefExpr>(Arg)) {
552 if (
auto *ImplicitParam = dyn_cast<ImplicitParamDecl>(Decl)) {
553 auto kind = ImplicitParam->getParameterKind();
554 return kind == ImplicitParamKind::ObjCSelf ||
555 kind == ImplicitParamKind::CXXThis;
557 return ProtectedThisDecls.contains(Decl);
563 LocalVisitor visitor(
this);
564 if (
auto *RTC = Model->retainTypeChecker())
565 RTC->visitTranslationUnitDecl(TUD);
566 visitor.TraverseDecl(
const_cast<TranslationUnitDecl *
>(TUD));
569 void visitLambdaExpr(
const LambdaExpr *L,
bool shouldCheckThis,
571 bool ignoreParamVarDecl =
false)
const {
572 if (BR->getSourceManager().isInSystemHeader(L->
getBeginLoc()))
577 if (TFA.isTrivial(L->
getBody()))
579 for (
auto [
C, CaptureInit] :
581 if (
C.capturesVariable()) {
582 ValueDecl *CapturedVar =
C.getCapturedVar();
585 if (
auto *ImplicitParam = dyn_cast<ImplicitParamDecl>(CapturedVar)) {
586 auto kind = ImplicitParam->getParameterKind();
587 if ((
kind == ImplicitParamKind::ObjCSelf ||
588 kind == ImplicitParamKind::CXXThis) &&
592 QualType CapturedVarQualType = CapturedVar->
getType();
593 auto IsUncountedPtr = isUnsafePtr(CapturedVarQualType);
597 if (!IsUncountedPtr || !*IsUncountedPtr)
599 const Expr *Origin =
nullptr;
600 if (Model->checksForInteriorDestruction()) {
603 if (isCaptureOriginSafeToEscape(CaptureInit, Origin,
604 CapturedVarQualType))
607 reportBug(
C, CapturedVar, CapturedVarQualType, L, Origin);
608 }
else if (
C.capturesThis() && shouldCheckThis) {
609 if (ignoreParamVarDecl)
611 reportBugOnThisPtr(
C,
T);
616 bool isCaptureOriginSafeToEscape(
const Expr *CaptureInit,
const Expr *&Origin,
617 QualType SinkType)
const {
620 Model->checksForInteriorDestruction(),
624 [](
const clang::CXXRecordDecl *) { return false; },
625 [](
const clang::QualType) { return false; },
629 [&](
const clang::Decl *D) {
630 return Model->isSafeDecl(D, BR->getSourceManager());
633 [&](
const clang::Expr *CaptureOrigin,
bool IsSafe,
635 bool PtrIsLifetimeBoundToOrigin) {
638 if (isa<CXXThisExpr>(CaptureOrigin))
642 if (Model->isSafeExpr(CaptureOrigin, PtrIsLifetimeBoundToOrigin,
646 Origin = CaptureOrigin;
651 void reportBug(
const LambdaCapture &
Capture, ValueDecl *CapturedVar,
653 const Expr *Origin)
const {
656 auto Location =
Capture.getLocation();
660 SmallString<100> Buf;
661 llvm::raw_svector_ostream Os(Buf);
666 Os <<
"Implicitly captured ";
670 bool IsUnsafePtr = CapturedVar->
getType() ==
T;
674 Os <<
" contains a ";
675 if (Model->checksForInteriorDestruction())
676 Model->describeHazard(Os, Origin,
T);
678 printPointer(Os,
T.getTypePtrOrNull());
680 PathDiagnosticLocation BSLoc(Location, BR->getSourceManager());
681 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
682 BR->emitReport(std::move(
Report));
685 void reportBugOnThisPtr(
const LambdaCapture &
Capture,
686 const QualType
T)
const {
687 SmallString<100> Buf;
688 llvm::raw_svector_ostream Os(Buf);
693 Os <<
"Implicitly captured ";
696 Os <<
"variable 'this' is a raw pointer to " << Model->typeName();
702 PathDiagnosticLocation BSLoc(
Capture.getLocation(), BR->getSourceManager());
703 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
704 BR->emitReport(std::move(
Report));
707 void printPointer(llvm::raw_svector_ostream &Os,
const Type *
T)
const {
708 if (Model->retainTypeChecker()) {
711 if (
auto *ObjCPtr = dyn_cast<ObjCObjectPointerType>(
T)) {
712 for (ObjCProtocolDecl *P : ObjCPtr->quals()) {
713 if (
const auto *II = P->getIdentifier()) {
714 auto Name = II->getName();
715 if (Name.starts_with(
"OS_")) {
716 Os << Model->typeName() <<
" ";
728 Os << Model->typeName() <<
" ";
735 Os << (IsPtr ?
"raw pointer" :
"raw reference") <<
" to ";
736 Os << Model->typeName();
748class UncountedLambdaCapturesChecker :
public RawPtrRefLambdaCapturesChecker {
750 UncountedLambdaCapturesChecker()
751 : RawPtrRefLambdaCapturesChecker(
"Lambda capture of uncounted variable",
755class UncheckedLambdaCapturesChecker :
public RawPtrRefLambdaCapturesChecker {
757 UncheckedLambdaCapturesChecker()
758 : RawPtrRefLambdaCapturesChecker(
"Lambda capture of unchecked variable",
762class UnretainedLambdaCapturesChecker :
public RawPtrRefLambdaCapturesChecker {
764 UnretainedLambdaCapturesChecker()
765 : RawPtrRefLambdaCapturesChecker(
"Lambda capture of unretained "
770class UnborrowedLambdaCapturesChecker :
public RawPtrRefLambdaCapturesChecker {
772 UnborrowedLambdaCapturesChecker()
773 : RawPtrRefLambdaCapturesChecker(
"Lambda capture of a loan on a "
780void ento::registerUncountedLambdaCapturesChecker(
CheckerManager &Mgr) {
784bool ento::shouldRegisterUncountedLambdaCapturesChecker(
789void ento::registerUncheckedLambdaCapturesChecker(
CheckerManager &Mgr) {
793bool ento::shouldRegisterUncheckedLambdaCapturesChecker(
798void ento::registerUnretainedLambdaCapturesChecker(
CheckerManager &Mgr) {
802bool ento::shouldRegisterUnretainedLambdaCapturesChecker(
807void ento::registerUnborrowedLambdaCapturesChecker(
CheckerManager &Mgr) {
811bool ento::shouldRegisterUnborrowedLambdaCapturesChecker(
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
Defines the SourceManager interface.
Expr * getArg(unsigned Arg)
Return the specified argument.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
unsigned getNumArgs() const
Return the number of arguments to the constructor call.
bool isMoveConstructor(unsigned &TypeQuals) const
Determine whether this constructor is a move constructor (C++11 [class.copy]p3), which can be used to...
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
QualType getThisType() const
Return the type of the this pointer.
bool isLambda() const
Determine whether this class describes a lambda function object.
FunctionTemplateDecl * getDependentLambdaCallOperator() const
Retrieve the dependent lambda call operator of the closure type if this is a templated closure type.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
CastKind getCastKind() const
DeclContext * getParent()
getParent - Returns the containing DeclContext.
bool isTemplated() const
Determine whether this declaration is a templated entity (whether it is.
virtual bool TraverseDecl(MaybeConst< Decl > *D)
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
capture_iterator capture_begin() const
Retrieve an iterator pointing to the first lambda capture.
Stmt * getBody() const
Retrieve the body of the lambda.
unsigned capture_size() const
Determine the number of captures in this lambda.
llvm::iterator_range< capture_init_iterator > capture_inits()
Retrieve the initialization expressions for this lambda's captures.
SourceLocation getBeginLoc() const LLVM_READONLY
capture_range captures() const
Retrieve this lambda's captures.
capture_init_iterator capture_init_begin()
Retrieve the first initialization argument for this lambda expression (which initializes the first ca...
CXXRecordDecl * getLambdaClass() const
Retrieve the class that corresponds to the lambda.
ImplicitParamDecl * getSelfDecl() const
bool isInstanceMethod() const
bool isNull() const
Return true if this QualType doesn't point to a type yet.
const Type * getTypePtrOrNull() const
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
bool isReferenceType() const
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const T * getAs() const
Member-template getAs<specific type>'.
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
const Expr * getInit() const
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
constexpr bool isPtrType(PrimType T)
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
Top level wrappers for InstallAPI frontend operations.
bool isCtorOfSafePtr(const clang::FunctionDecl *F)
bool isa(CodeGen::Address addr)
std::unique_ptr< PtrRefSafetyModel > makeBorrowSafetyModel()
std::unique_ptr< PtrRefSafetyModel > makeCheckedPtrSafetyModel()
@ LCK_ByCopy
Capturing by copy (a.k.a., by value)
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
std::optional< bool > isUnsafePtrForStorage(const PtrRefSafetyModel &Model, QualType T, bool IgnoreARC=false)
Applies the memory-management exemptions that hold for a variable, member, or lambda capture (but not...
const FunctionProtoType * T
std::string safeGetName(const T *ASTNode)
ObjCInterfaceDecl * getObjCDeclFromObjCPtr(const Type *TypePtr)
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
bool isStdOrWTFMove(const clang::FunctionDecl *F)
std::unique_ptr< PtrRefSafetyModel > makeRefPtrSafetyModel()
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).
std::unique_ptr< PtrRefSafetyModel > makeRetainPtrSafetyModel()