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 (isCaptureOriginSafeToEscape(CaptureInit, Origin,
594 CapturedVarQualType))
597 reportBug(
C, CapturedVar, CapturedVarQualType, L, Origin);
598 }
else if (
C.capturesThis() && shouldCheckThis) {
599 if (ignoreParamVarDecl)
601 reportBugOnThisPtr(
C,
T);
606 bool isCaptureOriginSafeToEscape(
const Expr *CaptureInit,
const Expr *&Origin,
607 QualType SinkType)
const {
610 Model->checksForInteriorDestruction(),
614 [](
const clang::CXXRecordDecl *) { return false; },
615 [](
const clang::QualType) { return false; },
619 [&](
const clang::Decl *D) {
620 return Model->isSafeDecl(D, BR->getSourceManager());
623 [&](
const clang::Expr *CaptureOrigin,
bool IsSafe,
625 bool PtrIsLifetimeBoundToOrigin) {
628 if (isa<CXXThisExpr>(CaptureOrigin))
632 if (Model->isSafeExpr(CaptureOrigin, PtrIsLifetimeBoundToOrigin,
636 Origin = CaptureOrigin;
641 void reportBug(
const LambdaCapture &
Capture, ValueDecl *CapturedVar,
643 const Expr *Origin)
const {
646 auto Location =
Capture.getLocation();
650 SmallString<100> Buf;
651 llvm::raw_svector_ostream Os(Buf);
656 Os <<
"Implicitly captured ";
660 bool IsUnsafePtr = CapturedVar->
getType() ==
T;
664 Os <<
" contains a ";
665 if (Model->checksForInteriorDestruction())
666 Model->describeHazard(Os, Origin,
T);
668 printPointer(Os,
T.getTypePtrOrNull());
670 PathDiagnosticLocation BSLoc(Location, BR->getSourceManager());
671 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
672 BR->emitReport(std::move(
Report));
675 void reportBugOnThisPtr(
const LambdaCapture &
Capture,
676 const QualType
T)
const {
677 SmallString<100> Buf;
678 llvm::raw_svector_ostream Os(Buf);
683 Os <<
"Implicitly captured ";
686 Os <<
"variable 'this' is a raw pointer to " << Model->typeName();
692 PathDiagnosticLocation BSLoc(
Capture.getLocation(), BR->getSourceManager());
693 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
694 BR->emitReport(std::move(
Report));
697 void printPointer(llvm::raw_svector_ostream &Os,
const Type *
T)
const {
698 if (Model->retainTypeChecker()) {
701 if (
auto *ObjCPtr = dyn_cast<ObjCObjectPointerType>(
T)) {
702 for (ObjCProtocolDecl *P : ObjCPtr->quals()) {
703 if (
const auto *II = P->getIdentifier()) {
704 auto Name = II->getName();
705 if (Name.starts_with(
"OS_")) {
706 Os << Model->typeName() <<
" ";
718 Os << Model->typeName() <<
" ";
725 Os << (IsPtr ?
"raw pointer" :
"raw reference") <<
" to ";
726 Os << Model->typeName();
738class UncountedLambdaCapturesChecker :
public RawPtrRefLambdaCapturesChecker {
740 UncountedLambdaCapturesChecker()
741 : RawPtrRefLambdaCapturesChecker(
"Lambda capture of uncounted variable",
745class UncheckedLambdaCapturesChecker :
public RawPtrRefLambdaCapturesChecker {
747 UncheckedLambdaCapturesChecker()
748 : RawPtrRefLambdaCapturesChecker(
"Lambda capture of unchecked variable",
752class UnretainedLambdaCapturesChecker :
public RawPtrRefLambdaCapturesChecker {
754 UnretainedLambdaCapturesChecker()
755 : RawPtrRefLambdaCapturesChecker(
"Lambda capture of unretained "
760class UnborrowedLambdaCapturesChecker :
public RawPtrRefLambdaCapturesChecker {
762 UnborrowedLambdaCapturesChecker()
763 : RawPtrRefLambdaCapturesChecker(
"Lambda capture of a loan on a "
770void ento::registerUncountedLambdaCapturesChecker(
CheckerManager &Mgr) {
774bool ento::shouldRegisterUncountedLambdaCapturesChecker(
779void ento::registerUncheckedLambdaCapturesChecker(
CheckerManager &Mgr) {
783bool ento::shouldRegisterUncheckedLambdaCapturesChecker(
788void ento::registerUnretainedLambdaCapturesChecker(
CheckerManager &Mgr) {
792bool ento::shouldRegisterUnretainedLambdaCapturesChecker(
797void ento::registerUnborrowedLambdaCapturesChecker(
CheckerManager &Mgr) {
801bool ento::shouldRegisterUnborrowedLambdaCapturesChecker(
*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)
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts 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()