24class RawPtrRefLambdaCapturesChecker
25 :
public Checker<check::ASTDecl<TranslationUnitDecl>> {
28 mutable BugReporter *BR =
nullptr;
29 TrivialFunctionAnalysis TFA;
32 const std::unique_ptr<PtrRefSafetyModel> Model;
35 RawPtrRefLambdaCapturesChecker(
const char *description,
36 std::unique_ptr<PtrRefSafetyModel> Model)
37 : Bug(this, description,
"WebKit coding guidelines"),
38 Model(std::move(Model)) {}
40 std::optional<bool> isUnsafePtr(QualType QT)
const {
43 bool isPtrType(
const std::string &Name)
const {
44 return Model->isPtrType(Name);
47 void checkASTDecl(
const TranslationUnitDecl *TUD, AnalysisManager &MGR,
48 BugReporter &BRArg)
const {
55 const RawPtrRefLambdaCapturesChecker *Checker;
56 llvm::DenseSet<const DeclRefExpr *> DeclRefExprsToIgnore;
57 llvm::DenseSet<const LambdaExpr *> LambdasToIgnore;
58 llvm::DenseSet<const ValueDecl *> ProtectedThisDecls;
59 llvm::DenseSet<const CallExpr *> CallToIgnore;
60 llvm::DenseSet<const CXXConstructExpr *> ConstructToIgnore;
61 llvm::DenseMap<const VarDecl *, SmallVector<const LambdaExpr *>>
66 explicit LocalVisitor(
const RawPtrRefLambdaCapturesChecker *Checker)
69 ShouldVisitTemplateInstantiations =
true;
70 ShouldVisitImplicitCode =
false;
73 bool TraverseDecl(Decl *D)
override {
84 bool TraverseCXXConstructorDecl(CXXConstructorDecl *Ctor)
override {
85 llvm::SaveAndRestore SavedDecl(ClsType);
87 return DynamicRecursiveASTVisitor::TraverseCXXConstructorDecl(Ctor);
90 bool TraverseCXXDestructorDecl(CXXDestructorDecl *Dtor)
override {
91 llvm::SaveAndRestore SavedDecl(ClsType);
92 ClsType =
Dtor->getThisType();
93 return DynamicRecursiveASTVisitor::TraverseCXXDestructorDecl(Dtor);
96 bool TraverseCXXMethodDecl(CXXMethodDecl *CXXMD)
override {
97 llvm::SaveAndRestore SavedDecl(ClsType);
104 return DynamicRecursiveASTVisitor::TraverseCXXMethodDecl(CXXMD);
107 bool TraverseObjCMethodDecl(ObjCMethodDecl *OCMD)
override {
108 llvm::SaveAndRestore SavedDecl(ClsType);
111 ClsType = ImplParamDecl->getType();
113 return DynamicRecursiveASTVisitor::TraverseObjCMethodDecl(OCMD);
116 bool VisitTypedefDecl(TypedefDecl *TD)
override {
117 if (
auto *RTC = Checker->Model->retainTypeChecker())
118 RTC->visitTypedef(TD);
122 bool shouldCheckThis() {
124 if (Checker->Model->checksForInteriorDestruction())
127 !ClsType.
isNull() ? Checker->isUnsafePtr(ClsType) : std::nullopt;
128 return result && *result;
131 bool VisitLambdaExpr(
LambdaExpr *L)
override {
132 if (LambdasToIgnore.contains(L))
134 Checker->visitLambdaExpr(L, shouldCheckThis() && !hasProtectedThis(L),
139 bool TraverseLambdaExpr(
LambdaExpr *L)
override {
142 return DynamicRecursiveASTVisitor::TraverseLambdaExpr(L);
151 if (!VisitLambdaExpr(L))
153 for (
unsigned I = 0, N = L->
capture_size(); I != N; ++I) {
160 return TraverseDecl(FTD);
163 bool VisitVarDecl(VarDecl *VD)
override {
167 if (
auto *L = dyn_cast_or_null<LambdaExpr>(
Init->IgnoreParenCasts())) {
168 LambdasToIgnore.insert(L);
173 if (
auto *E = dyn_cast<ExprWithCleanups>(
Init))
174 Init = E->getSubExpr();
175 if (
auto *E = dyn_cast<CXXBindTemporaryExpr>(
Init))
176 Init = E->getSubExpr();
177 if (
auto *CE = dyn_cast<CallExpr>(
Init)) {
178 if (
auto *Callee = CE->getDirectCallee()) {
180 unsigned ArgCnt = CE->getNumArgs();
181 if (FnName ==
"makeScopeExit" && ArgCnt == 1) {
182 auto *Arg = CE->getArg(0);
183 if (
auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
184 Arg = E->getSubExpr();
185 if (
auto *L = dyn_cast<LambdaExpr>(Arg))
186 addLambdaOwner(VD, CE, L);
187 }
else if (FnName ==
"makeVisitor") {
188 for (
unsigned ArgIndex = 0; ArgIndex < ArgCnt; ++ArgIndex) {
189 auto *Arg = CE->getArg(ArgIndex);
190 if (
auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
191 Arg = E->getSubExpr();
192 if (
auto *L = dyn_cast<LambdaExpr>(Arg))
193 addLambdaOwner(VD, CE, L);
197 }
else if (
auto *CE = dyn_cast<CXXConstructExpr>(
Init)) {
198 if (
auto *Ctor = CE->getConstructor()) {
201 unsigned ArgCnt = CE->getNumArgs();
202 if (FnName ==
"ScopeExit" && ArgCnt == 1) {
203 auto *Arg = CE->getArg(0);
204 if (
auto *E = dyn_cast<MaterializeTemporaryExpr>(Arg))
205 Arg = E->getSubExpr();
206 if (
auto *L = dyn_cast<LambdaExpr>(Arg))
207 addLambdaOwner(VD, CE, L);
215 void addLambdaOwner(VarDecl *VD, CallExpr *CE,
LambdaExpr *L) {
216 auto result = LambdaOwnerMap.insert(
217 std::make_pair(VD, SmallVector<const LambdaExpr *>{L}));
219 result.first->second.push_back(L);
220 CallToIgnore.insert(CE);
221 LambdasToIgnore.insert(L);
224 void addLambdaOwner(VarDecl *VD, CXXConstructExpr *CE,
LambdaExpr *L) {
225 auto result = LambdaOwnerMap.insert(
226 std::make_pair(VD, SmallVector<const LambdaExpr *>{L}));
228 result.first->second.push_back(L);
229 ConstructToIgnore.insert(CE);
230 LambdasToIgnore.insert(L);
233 bool VisitDeclRefExpr(DeclRefExpr *DRE)
override {
234 if (DeclRefExprsToIgnore.contains(DRE))
236 auto *VD = dyn_cast_or_null<VarDecl>(DRE->
getDecl());
239 if (
auto It = LambdaOwnerMap.find(VD); It != LambdaOwnerMap.end()) {
240 for (
auto *L : It->second) {
241 Checker->visitLambdaExpr(
242 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
249 auto *L = dyn_cast_or_null<LambdaExpr>(
Init->IgnoreParenCasts());
252 LambdasToIgnore.insert(L);
253 Checker->visitLambdaExpr(L, shouldCheckThis() && !hasProtectedThis(L),
258 bool shouldTreatAllArgAsNoEscape(FunctionDecl *FDecl) {
260 for (
auto *Decl = FDecl->
getParent(); Decl; Decl =
Decl->getParent()) {
263 if (
auto *NS = dyn_cast<NamespaceDecl>(Decl); NS && NS->isInline())
269 if (Name ==
"WTF" && PreviousName ==
"switchOn")
273 if (PreviousName ==
"ranges")
278 if (PreviousName ==
"call_once")
286 bool VisitCXXConstructExpr(CXXConstructExpr *CE)
override {
287 if (ConstructToIgnore.contains(CE))
290 unsigned ArgIndex = 0;
291 for (
auto *Param :
Callee->parameters()) {
295 if (
auto *L = findLambdaInArg(Arg)) {
296 LambdasToIgnore.insert(L);
297 if (!Param->hasAttr<NoEscapeAttr>())
298 Checker->visitLambdaExpr(
299 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
307 bool VisitCallExpr(CallExpr *CE)
override {
308 if (CallToIgnore.contains(CE))
310 checkCalleeLambda(CE);
312 if (isVisitFunction(CE, Callee))
314 checkParameters(CE, Callee);
315 }
else if (
auto *CalleeE = CE->
getCallee()) {
316 if (
auto *DRE = dyn_cast<DeclRefExpr>(CalleeE->IgnoreParenCasts())) {
317 if (
auto *Callee = dyn_cast_or_null<FunctionDecl>(DRE->
getDecl()))
318 checkParameters(CE, Callee);
324 bool isVisitFunction(CallExpr *CallExpr, FunctionDecl *FnDecl) {
335 if (NsName !=
"WTF" && NsName !=
"std")
337 auto *Arg = CallExpr->
getArg(0);
340 auto *DRE = dyn_cast<DeclRefExpr>(Arg->IgnoreParenCasts());
343 auto *VD = dyn_cast<VarDecl>(DRE->
getDecl());
346 if (!LambdaOwnerMap.contains(VD))
348 DeclRefExprsToIgnore.insert(DRE);
352 void checkParameters(CallExpr *CE, FunctionDecl *Callee) {
354 bool TreatAllArgsAsNoEscape = shouldTreatAllArgAsNoEscape(Callee);
355 for (
auto *Param :
Callee->parameters()) {
359 if (
auto *L = findLambdaInArg(Arg)) {
360 LambdasToIgnore.insert(L);
361 if (!Param->hasAttr<NoEscapeAttr>() && !TreatAllArgsAsNoEscape)
362 Checker->visitLambdaExpr(
363 L, shouldCheckThis() && !hasProtectedThis(L), ClsType);
370 if (
auto *Lambda = dyn_cast_or_null<LambdaExpr>(E))
372 auto *TempExpr = dyn_cast_or_null<CXXBindTemporaryExpr>(E);
378 if (
auto *Lambda = dyn_cast<LambdaExpr>(E))
380 auto *CE = dyn_cast_or_null<CXXConstructExpr>(E);
386 auto *InnerCE = dyn_cast_or_null<CXXConstructExpr>(CtorArg);
387 if (InnerCE && InnerCE->getNumArgs())
388 CtorArg = InnerCE->getArg(0)->IgnoreParenCasts();
389 auto updateIgnoreList = [&] {
390 ConstructToIgnore.insert(CE);
392 ConstructToIgnore.insert(InnerCE);
394 if (
auto *Lambda = dyn_cast<LambdaExpr>(CtorArg)) {
398 if (
auto *TempExpr = dyn_cast<CXXBindTemporaryExpr>(CtorArg)) {
400 if (
auto *Lambda = dyn_cast<LambdaExpr>(E)) {
405 auto *DRE = dyn_cast<DeclRefExpr>(CtorArg);
408 auto *VD = dyn_cast_or_null<VarDecl>(DRE->
getDecl());
414 if (
auto *Lambda = dyn_cast<LambdaExpr>(
Init)) {
415 DeclRefExprsToIgnore.insert(DRE);
422 void checkCalleeLambda(CallExpr *CE) {
427 if (
auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Callee)) {
428 Callee = MTE->getSubExpr();
433 if (
auto *L = dyn_cast<LambdaExpr>(Callee)) {
434 LambdasToIgnore.insert(L);
437 auto *DRE = dyn_cast<DeclRefExpr>(
Callee->IgnoreParenCasts());
440 auto *MD = dyn_cast_or_null<CXXMethodDecl>(DRE->
getDecl());
444 if (
auto *L = dyn_cast_or_null<LambdaExpr>(Arg)) {
445 LambdasToIgnore.insert(L);
448 auto *ArgRef = dyn_cast<DeclRefExpr>(Arg);
451 auto *VD = dyn_cast_or_null<VarDecl>(ArgRef->getDecl());
457 auto *L = dyn_cast_or_null<LambdaExpr>(
Init->IgnoreParenCasts());
460 DeclRefExprsToIgnore.insert(ArgRef);
461 LambdasToIgnore.insert(L);
465 for (
const LambdaCapture &OtherCapture : L->
captures()) {
466 if (!OtherCapture.capturesVariable())
468 if (
auto *ValueDecl = OtherCapture.getCapturedVar()) {
469 if (declProtectsThis(ValueDecl)) {
470 ProtectedThisDecls.insert(ValueDecl);
478 bool declProtectsThis(
const ValueDecl *ValueDecl)
const {
479 auto *VD = dyn_cast<VarDecl>(ValueDecl);
487 if (
auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Arg))
489 if (
auto *CE = dyn_cast<CXXConstructExpr>(Arg)) {
490 auto *Ctor = CE->getConstructor();
493 auto ArgClsTy = dyn_cast_or_null<CXXRecordDecl>(Ctor->
getParent());
494 if (Checker->Model->isSafePtr(ArgClsTy) && CE->
getNumArgs()) {
499 if (
auto *CXXR =
Type->getPointeeCXXRecordDecl()) {
509 if (
auto *CE = dyn_cast<CallExpr>(Arg)) {
518 if (
auto *OpCE = dyn_cast<CXXOperatorCallExpr>(Arg)) {
519 auto OpCode = OpCE->getOperator();
520 if (OpCode == OO_Star || OpCode == OO_Amp) {
521 auto *
Callee = OpCE->getDirectCallee();
525 if (!Checker->isPtrType(clsName) || !OpCE->getNumArgs())
531 if (
auto *UO = dyn_cast<UnaryOperator>(Arg)) {
532 auto OpCode = UO->getOpcode();
533 if (OpCode == UO_Deref || OpCode == UO_AddrOf) {
540 if (
auto *DRE = dyn_cast<DeclRefExpr>(Arg)) {
542 if (
auto *ImplicitParam = dyn_cast<ImplicitParamDecl>(Decl)) {
543 auto kind = ImplicitParam->getParameterKind();
544 return kind == ImplicitParamKind::ObjCSelf ||
545 kind == ImplicitParamKind::CXXThis;
547 return ProtectedThisDecls.contains(Decl);
553 LocalVisitor visitor(
this);
554 if (
auto *RTC = Model->retainTypeChecker())
555 RTC->visitTranslationUnitDecl(TUD);
556 visitor.TraverseDecl(
const_cast<TranslationUnitDecl *
>(TUD));
559 void visitLambdaExpr(
const LambdaExpr *L,
bool shouldCheckThis,
561 bool ignoreParamVarDecl =
false)
const {
562 if (BR->getSourceManager().isInSystemHeader(L->
getBeginLoc()))
567 if (TFA.isTrivial(L->
getBody()))
569 for (
auto [
C, CaptureInit] :
571 if (
C.capturesVariable()) {
572 ValueDecl *CapturedVar =
C.getCapturedVar();
575 if (
auto *ImplicitParam = dyn_cast<ImplicitParamDecl>(CapturedVar)) {
576 auto kind = ImplicitParam->getParameterKind();
577 if ((
kind == ImplicitParamKind::ObjCSelf ||
578 kind == ImplicitParamKind::CXXThis) &&
582 QualType CapturedVarQualType = CapturedVar->
getType();
583 auto IsUncountedPtr = isUnsafePtr(CapturedVarQualType);
587 if (!IsUncountedPtr || !*IsUncountedPtr)
589 const Expr *Origin =
nullptr;
590 if (Model->checksForInteriorDestruction()) {
593 if (isCaptureOriginSafeForInteriorDestruction(CaptureInit, Origin))
596 reportBug(
C, CapturedVar, CapturedVarQualType, L, Origin);
597 }
else if (
C.capturesThis() && shouldCheckThis) {
598 if (ignoreParamVarDecl)
600 reportBugOnThisPtr(
C,
T);
605 bool isCaptureOriginSafeForInteriorDestruction(
const Expr *CaptureInit,
606 const Expr *&Origin)
const {
609 Model->checksForInteriorDestruction(),
610 [&](
const clang::CXXRecordDecl *
Record) {
611 return Model->isSafePtr(Record);
613 [&](
const clang::QualType
Type) { return Model->isSafePtrType(Type); },
614 [&](
const clang::Decl *D) {
615 return Model->isSafeDecl(D, BR->getSourceManager());
617 [&](
const clang::Expr *CaptureOrigin,
bool IsSafe,
619 bool PtrIsLifetimeBoundToOrigin) {
622 if (isa<CXXThisExpr>(CaptureOrigin))
626 QualType OriginType = pointeeType(CaptureOrigin->getType());
627 if (!OriginType.isNull() && isBorrowType(OriginType)) {
629 Origin = CaptureOrigin;
634 if (Model->isSafeExpr(CaptureOrigin, PtrIsLifetimeBoundToOrigin))
637 Origin = CaptureOrigin;
644 const Expr *Origin)
const {
652 llvm::raw_svector_ostream Os(Buf);
657 Os <<
"Implicitly captured ";
661 bool IsUnsafePtr = CapturedVar->
getType() ==
T;
665 Os <<
" contains a ";
666 if (Model->checksForInteriorDestruction())
667 Model->describeHazard(Os, Origin,
T);
669 printPointer(Os,
T.getTypePtrOrNull());
672 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
679 llvm::raw_svector_ostream Os(Buf);
684 Os <<
"Implicitly captured ";
687 Os <<
"variable 'this' is a raw pointer to " << Model->typeName();
688 if (
auto *RD =
T->getPointeeCXXRecordDecl()) {
694 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
698 void printPointer(llvm::raw_svector_ostream &Os,
const Type *
T)
const {
699 if (Model->retainTypeChecker()) {
702 if (
auto *ObjCPtr = dyn_cast<ObjCObjectPointerType>(
T)) {
704 if (
const auto *II = P->getIdentifier()) {
705 auto Name = II->getName();
706 if (Name.starts_with(
"OS_")) {
707 Os << Model->typeName() <<
" ";
719 Os << Model->typeName() <<
" ";
724 T =
T->getUnqualifiedDesugaredType();
726 Os << (IsPtr ?
"raw pointer" :
"raw reference") <<
" to ";
727 Os << Model->typeName();
729 if (
auto *RD =
T->getPointeeType()->getAsRecordDecl()) {
739class UncountedLambdaCapturesChecker :
public RawPtrRefLambdaCapturesChecker {
741 UncountedLambdaCapturesChecker()
742 : RawPtrRefLambdaCapturesChecker(
"Lambda capture of uncounted variable",
746class UncheckedLambdaCapturesChecker :
public RawPtrRefLambdaCapturesChecker {
748 UncheckedLambdaCapturesChecker()
749 : RawPtrRefLambdaCapturesChecker(
"Lambda capture of unchecked variable",
753class UnretainedLambdaCapturesChecker :
public RawPtrRefLambdaCapturesChecker {
755 UnretainedLambdaCapturesChecker()
756 : RawPtrRefLambdaCapturesChecker(
"Lambda capture of unretained "
761class UnborrowedLambdaCapturesChecker :
public RawPtrRefLambdaCapturesChecker {
763 UnborrowedLambdaCapturesChecker()
764 : RawPtrRefLambdaCapturesChecker(
"Lambda capture of a loan on a "
771void ento::registerUncountedLambdaCapturesChecker(
CheckerManager &Mgr) {
775bool ento::shouldRegisterUncountedLambdaCapturesChecker(
780void ento::registerUncheckedLambdaCapturesChecker(
CheckerManager &Mgr) {
784bool ento::shouldRegisterUncheckedLambdaCapturesChecker(
789void ento::registerUnretainedLambdaCapturesChecker(
CheckerManager &Mgr) {
793bool ento::shouldRegisterUnretainedLambdaCapturesChecker(
798void ento::registerUnborrowedLambdaCapturesChecker(
CheckerManager &Mgr) {
802bool ento::shouldRegisterUnborrowedLambdaCapturesChecker(
llvm::MachO::Record Record
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
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.
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)
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Describes the capture of a variable or of this, or of a C++1y init-capture.
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
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
Represents an Objective-C protocol declaration.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
const Type * getTypePtrOrNull() const
The base class of the type hierarchy.
bool isReferenceType() const
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
const Expr * getInit() const
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
const SourceManager & getSourceManager()
virtual void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
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.
SourceLocation getLocation() const
Retrieve the location at which this variable was captured.
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()
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
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()