xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //=======- RawPtrRefCallArgsChecker.cpp --------------------------*- C++ -*-==//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric 
9*700637cbSDimitry Andric #include "ASTUtils.h"
10*700637cbSDimitry Andric #include "DiagOutputUtils.h"
11*700637cbSDimitry Andric #include "PtrTypesSemantics.h"
12*700637cbSDimitry Andric #include "clang/AST/Decl.h"
13*700637cbSDimitry Andric #include "clang/AST/DeclCXX.h"
14*700637cbSDimitry Andric #include "clang/AST/DynamicRecursiveASTVisitor.h"
15*700637cbSDimitry Andric #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
16*700637cbSDimitry Andric #include "clang/Basic/SourceLocation.h"
17*700637cbSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
18*700637cbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
19*700637cbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
20*700637cbSDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
21*700637cbSDimitry Andric #include "llvm/Support/SaveAndRestore.h"
22*700637cbSDimitry Andric #include <optional>
23*700637cbSDimitry Andric 
24*700637cbSDimitry Andric using namespace clang;
25*700637cbSDimitry Andric using namespace ento;
26*700637cbSDimitry Andric 
27*700637cbSDimitry Andric namespace {
28*700637cbSDimitry Andric 
29*700637cbSDimitry Andric class RawPtrRefCallArgsChecker
30*700637cbSDimitry Andric     : public Checker<check::ASTDecl<TranslationUnitDecl>> {
31*700637cbSDimitry Andric   BugType Bug;
32*700637cbSDimitry Andric   mutable BugReporter *BR;
33*700637cbSDimitry Andric 
34*700637cbSDimitry Andric   TrivialFunctionAnalysis TFA;
35*700637cbSDimitry Andric   EnsureFunctionAnalysis EFA;
36*700637cbSDimitry Andric 
37*700637cbSDimitry Andric protected:
38*700637cbSDimitry Andric   mutable std::optional<RetainTypeChecker> RTC;
39*700637cbSDimitry Andric 
40*700637cbSDimitry Andric public:
RawPtrRefCallArgsChecker(const char * description)41*700637cbSDimitry Andric   RawPtrRefCallArgsChecker(const char *description)
42*700637cbSDimitry Andric       : Bug(this, description, "WebKit coding guidelines") {}
43*700637cbSDimitry Andric 
44*700637cbSDimitry Andric   virtual std::optional<bool> isUnsafeType(QualType) const = 0;
45*700637cbSDimitry Andric   virtual std::optional<bool> isUnsafePtr(QualType) const = 0;
46*700637cbSDimitry Andric   virtual bool isSafePtr(const CXXRecordDecl *Record) const = 0;
47*700637cbSDimitry Andric   virtual bool isSafePtrType(const QualType type) const = 0;
isSafeExpr(const Expr *) const48*700637cbSDimitry Andric   virtual bool isSafeExpr(const Expr *) const { return false; }
49*700637cbSDimitry Andric   virtual const char *ptrKind() const = 0;
50*700637cbSDimitry Andric 
checkASTDecl(const TranslationUnitDecl * TUD,AnalysisManager & MGR,BugReporter & BRArg) const51*700637cbSDimitry Andric   void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
52*700637cbSDimitry Andric                     BugReporter &BRArg) const {
53*700637cbSDimitry Andric     BR = &BRArg;
54*700637cbSDimitry Andric 
55*700637cbSDimitry Andric     // The calls to checkAST* from AnalysisConsumer don't
56*700637cbSDimitry Andric     // visit template instantiations or lambda classes. We
57*700637cbSDimitry Andric     // want to visit those, so we make our own RecursiveASTVisitor.
58*700637cbSDimitry Andric     struct LocalVisitor : DynamicRecursiveASTVisitor {
59*700637cbSDimitry Andric       const RawPtrRefCallArgsChecker *Checker;
60*700637cbSDimitry Andric       Decl *DeclWithIssue{nullptr};
61*700637cbSDimitry Andric 
62*700637cbSDimitry Andric       explicit LocalVisitor(const RawPtrRefCallArgsChecker *Checker)
63*700637cbSDimitry Andric           : Checker(Checker) {
64*700637cbSDimitry Andric         assert(Checker);
65*700637cbSDimitry Andric         ShouldVisitTemplateInstantiations = true;
66*700637cbSDimitry Andric         ShouldVisitImplicitCode = false;
67*700637cbSDimitry Andric       }
68*700637cbSDimitry Andric 
69*700637cbSDimitry Andric       bool TraverseClassTemplateDecl(ClassTemplateDecl *Decl) override {
70*700637cbSDimitry Andric         if (isSmartPtrClass(safeGetName(Decl)))
71*700637cbSDimitry Andric           return true;
72*700637cbSDimitry Andric         return DynamicRecursiveASTVisitor::TraverseClassTemplateDecl(Decl);
73*700637cbSDimitry Andric       }
74*700637cbSDimitry Andric 
75*700637cbSDimitry Andric       bool TraverseDecl(Decl *D) override {
76*700637cbSDimitry Andric         llvm::SaveAndRestore SavedDecl(DeclWithIssue);
77*700637cbSDimitry Andric         if (D && (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)))
78*700637cbSDimitry Andric           DeclWithIssue = D;
79*700637cbSDimitry Andric         return DynamicRecursiveASTVisitor::TraverseDecl(D);
80*700637cbSDimitry Andric       }
81*700637cbSDimitry Andric 
82*700637cbSDimitry Andric       bool VisitCallExpr(CallExpr *CE) override {
83*700637cbSDimitry Andric         Checker->visitCallExpr(CE, DeclWithIssue);
84*700637cbSDimitry Andric         return true;
85*700637cbSDimitry Andric       }
86*700637cbSDimitry Andric 
87*700637cbSDimitry Andric       bool VisitTypedefDecl(TypedefDecl *TD) override {
88*700637cbSDimitry Andric         if (Checker->RTC)
89*700637cbSDimitry Andric           Checker->RTC->visitTypedef(TD);
90*700637cbSDimitry Andric         return true;
91*700637cbSDimitry Andric       }
92*700637cbSDimitry Andric 
93*700637cbSDimitry Andric       bool VisitObjCMessageExpr(ObjCMessageExpr *ObjCMsgExpr) override {
94*700637cbSDimitry Andric         Checker->visitObjCMessageExpr(ObjCMsgExpr, DeclWithIssue);
95*700637cbSDimitry Andric         return true;
96*700637cbSDimitry Andric       }
97*700637cbSDimitry Andric     };
98*700637cbSDimitry Andric 
99*700637cbSDimitry Andric     LocalVisitor visitor(this);
100*700637cbSDimitry Andric     if (RTC)
101*700637cbSDimitry Andric       RTC->visitTranslationUnitDecl(TUD);
102*700637cbSDimitry Andric     visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
103*700637cbSDimitry Andric   }
104*700637cbSDimitry Andric 
visitCallExpr(const CallExpr * CE,const Decl * D) const105*700637cbSDimitry Andric   void visitCallExpr(const CallExpr *CE, const Decl *D) const {
106*700637cbSDimitry Andric     if (shouldSkipCall(CE))
107*700637cbSDimitry Andric       return;
108*700637cbSDimitry Andric 
109*700637cbSDimitry Andric     if (auto *F = CE->getDirectCallee()) {
110*700637cbSDimitry Andric       // Skip the first argument for overloaded member operators (e. g. lambda
111*700637cbSDimitry Andric       // or std::function call operator).
112*700637cbSDimitry Andric       unsigned ArgIdx =
113*700637cbSDimitry Andric           isa<CXXOperatorCallExpr>(CE) && isa_and_nonnull<CXXMethodDecl>(F);
114*700637cbSDimitry Andric 
115*700637cbSDimitry Andric       if (auto *MemberCallExpr = dyn_cast<CXXMemberCallExpr>(CE)) {
116*700637cbSDimitry Andric         if (auto *MD = MemberCallExpr->getMethodDecl()) {
117*700637cbSDimitry Andric           auto name = safeGetName(MD);
118*700637cbSDimitry Andric           if (name == "ref" || name == "deref")
119*700637cbSDimitry Andric             return;
120*700637cbSDimitry Andric           if (name == "incrementCheckedPtrCount" ||
121*700637cbSDimitry Andric               name == "decrementCheckedPtrCount")
122*700637cbSDimitry Andric             return;
123*700637cbSDimitry Andric         }
124*700637cbSDimitry Andric         auto *E = MemberCallExpr->getImplicitObjectArgument();
125*700637cbSDimitry Andric         QualType ArgType = MemberCallExpr->getObjectType().getCanonicalType();
126*700637cbSDimitry Andric         std::optional<bool> IsUnsafe = isUnsafeType(ArgType);
127*700637cbSDimitry Andric         if (IsUnsafe && *IsUnsafe && !isPtrOriginSafe(E))
128*700637cbSDimitry Andric           reportBugOnThis(E, D);
129*700637cbSDimitry Andric       }
130*700637cbSDimitry Andric 
131*700637cbSDimitry Andric       for (auto P = F->param_begin();
132*700637cbSDimitry Andric            // FIXME: Also check variadic function parameters.
133*700637cbSDimitry Andric            // FIXME: Also check default function arguments. Probably a different
134*700637cbSDimitry Andric            // checker. In case there are default arguments the call can have
135*700637cbSDimitry Andric            // fewer arguments than the callee has parameters.
136*700637cbSDimitry Andric            P < F->param_end() && ArgIdx < CE->getNumArgs(); ++P, ++ArgIdx) {
137*700637cbSDimitry Andric         // TODO: attributes.
138*700637cbSDimitry Andric         // if ((*P)->hasAttr<SafeRefCntblRawPtrAttr>())
139*700637cbSDimitry Andric         //  continue;
140*700637cbSDimitry Andric 
141*700637cbSDimitry Andric         QualType ArgType = (*P)->getType();
142*700637cbSDimitry Andric         // FIXME: more complex types (arrays, references to raw pointers, etc)
143*700637cbSDimitry Andric         std::optional<bool> IsUncounted = isUnsafePtr(ArgType);
144*700637cbSDimitry Andric         if (!IsUncounted || !(*IsUncounted))
145*700637cbSDimitry Andric           continue;
146*700637cbSDimitry Andric 
147*700637cbSDimitry Andric         const auto *Arg = CE->getArg(ArgIdx);
148*700637cbSDimitry Andric 
149*700637cbSDimitry Andric         if (auto *defaultArg = dyn_cast<CXXDefaultArgExpr>(Arg))
150*700637cbSDimitry Andric           Arg = defaultArg->getExpr();
151*700637cbSDimitry Andric 
152*700637cbSDimitry Andric         if (isPtrOriginSafe(Arg))
153*700637cbSDimitry Andric           continue;
154*700637cbSDimitry Andric 
155*700637cbSDimitry Andric         reportBug(Arg, *P, D);
156*700637cbSDimitry Andric       }
157*700637cbSDimitry Andric       for (; ArgIdx < CE->getNumArgs(); ++ArgIdx) {
158*700637cbSDimitry Andric         const auto *Arg = CE->getArg(ArgIdx);
159*700637cbSDimitry Andric         auto ArgType = Arg->getType();
160*700637cbSDimitry Andric         std::optional<bool> IsUncounted = isUnsafePtr(ArgType);
161*700637cbSDimitry Andric         if (!IsUncounted || !(*IsUncounted))
162*700637cbSDimitry Andric           continue;
163*700637cbSDimitry Andric 
164*700637cbSDimitry Andric         if (auto *defaultArg = dyn_cast<CXXDefaultArgExpr>(Arg))
165*700637cbSDimitry Andric           Arg = defaultArg->getExpr();
166*700637cbSDimitry Andric 
167*700637cbSDimitry Andric         if (isPtrOriginSafe(Arg))
168*700637cbSDimitry Andric           continue;
169*700637cbSDimitry Andric 
170*700637cbSDimitry Andric         reportBug(Arg, nullptr, D);
171*700637cbSDimitry Andric       }
172*700637cbSDimitry Andric     }
173*700637cbSDimitry Andric   }
174*700637cbSDimitry Andric 
visitObjCMessageExpr(const ObjCMessageExpr * E,const Decl * D) const175*700637cbSDimitry Andric   void visitObjCMessageExpr(const ObjCMessageExpr *E, const Decl *D) const {
176*700637cbSDimitry Andric     if (BR->getSourceManager().isInSystemHeader(E->getExprLoc()))
177*700637cbSDimitry Andric       return;
178*700637cbSDimitry Andric 
179*700637cbSDimitry Andric     auto Selector = E->getSelector();
180*700637cbSDimitry Andric     if (auto *Receiver = E->getInstanceReceiver()) {
181*700637cbSDimitry Andric       std::optional<bool> IsUnsafe = isUnsafePtr(E->getReceiverType());
182*700637cbSDimitry Andric       if (IsUnsafe && *IsUnsafe && !isPtrOriginSafe(Receiver)) {
183*700637cbSDimitry Andric         if (auto *InnerMsg = dyn_cast<ObjCMessageExpr>(Receiver)) {
184*700637cbSDimitry Andric           auto InnerSelector = InnerMsg->getSelector();
185*700637cbSDimitry Andric           if (InnerSelector.getNameForSlot(0) == "alloc" &&
186*700637cbSDimitry Andric               Selector.getNameForSlot(0).starts_with("init"))
187*700637cbSDimitry Andric             return;
188*700637cbSDimitry Andric         }
189*700637cbSDimitry Andric         reportBugOnReceiver(Receiver, D);
190*700637cbSDimitry Andric       }
191*700637cbSDimitry Andric     }
192*700637cbSDimitry Andric 
193*700637cbSDimitry Andric     auto *MethodDecl = E->getMethodDecl();
194*700637cbSDimitry Andric     if (!MethodDecl)
195*700637cbSDimitry Andric       return;
196*700637cbSDimitry Andric 
197*700637cbSDimitry Andric     auto ArgCount = E->getNumArgs();
198*700637cbSDimitry Andric     for (unsigned i = 0; i < ArgCount; ++i) {
199*700637cbSDimitry Andric       auto *Arg = E->getArg(i);
200*700637cbSDimitry Andric       bool hasParam = i < MethodDecl->param_size();
201*700637cbSDimitry Andric       auto *Param = hasParam ? MethodDecl->getParamDecl(i) : nullptr;
202*700637cbSDimitry Andric       auto ArgType = Arg->getType();
203*700637cbSDimitry Andric       std::optional<bool> IsUnsafe = isUnsafePtr(ArgType);
204*700637cbSDimitry Andric       if (!IsUnsafe || !(*IsUnsafe))
205*700637cbSDimitry Andric         continue;
206*700637cbSDimitry Andric       if (isPtrOriginSafe(Arg))
207*700637cbSDimitry Andric         continue;
208*700637cbSDimitry Andric       reportBug(Arg, Param, D);
209*700637cbSDimitry Andric     }
210*700637cbSDimitry Andric   }
211*700637cbSDimitry Andric 
isPtrOriginSafe(const Expr * Arg) const212*700637cbSDimitry Andric   bool isPtrOriginSafe(const Expr *Arg) const {
213*700637cbSDimitry Andric     return tryToFindPtrOrigin(
214*700637cbSDimitry Andric         Arg, /*StopAtFirstRefCountedObj=*/true,
215*700637cbSDimitry Andric         [&](const clang::CXXRecordDecl *Record) { return isSafePtr(Record); },
216*700637cbSDimitry Andric         [&](const clang::QualType T) { return isSafePtrType(T); },
217*700637cbSDimitry Andric         [&](const clang::Expr *ArgOrigin, bool IsSafe) {
218*700637cbSDimitry Andric           if (IsSafe)
219*700637cbSDimitry Andric             return true;
220*700637cbSDimitry Andric           if (isa<CXXNullPtrLiteralExpr>(ArgOrigin)) {
221*700637cbSDimitry Andric             // foo(nullptr)
222*700637cbSDimitry Andric             return true;
223*700637cbSDimitry Andric           }
224*700637cbSDimitry Andric           if (isa<IntegerLiteral>(ArgOrigin)) {
225*700637cbSDimitry Andric             // FIXME: Check the value.
226*700637cbSDimitry Andric             // foo(NULL)
227*700637cbSDimitry Andric             return true;
228*700637cbSDimitry Andric           }
229*700637cbSDimitry Andric           if (isa<ObjCStringLiteral>(ArgOrigin))
230*700637cbSDimitry Andric             return true;
231*700637cbSDimitry Andric           if (isASafeCallArg(ArgOrigin))
232*700637cbSDimitry Andric             return true;
233*700637cbSDimitry Andric           if (EFA.isACallToEnsureFn(ArgOrigin))
234*700637cbSDimitry Andric             return true;
235*700637cbSDimitry Andric           if (isSafeExpr(ArgOrigin))
236*700637cbSDimitry Andric             return true;
237*700637cbSDimitry Andric           return false;
238*700637cbSDimitry Andric         });
239*700637cbSDimitry Andric   }
240*700637cbSDimitry Andric 
shouldSkipCall(const CallExpr * CE) const241*700637cbSDimitry Andric   bool shouldSkipCall(const CallExpr *CE) const {
242*700637cbSDimitry Andric     const auto *Callee = CE->getDirectCallee();
243*700637cbSDimitry Andric 
244*700637cbSDimitry Andric     if (BR->getSourceManager().isInSystemHeader(CE->getExprLoc()))
245*700637cbSDimitry Andric       return true;
246*700637cbSDimitry Andric 
247*700637cbSDimitry Andric     if (Callee && TFA.isTrivial(Callee) && !Callee->isVirtualAsWritten())
248*700637cbSDimitry Andric       return true;
249*700637cbSDimitry Andric 
250*700637cbSDimitry Andric     if (isTrivialBuiltinFunction(Callee))
251*700637cbSDimitry Andric       return true;
252*700637cbSDimitry Andric 
253*700637cbSDimitry Andric     if (CE->getNumArgs() == 0)
254*700637cbSDimitry Andric       return false;
255*700637cbSDimitry Andric 
256*700637cbSDimitry Andric     // If an assignment is problematic we should warn about the sole existence
257*700637cbSDimitry Andric     // of object on LHS.
258*700637cbSDimitry Andric     if (auto *MemberOp = dyn_cast<CXXOperatorCallExpr>(CE)) {
259*700637cbSDimitry Andric       // Note: assignemnt to built-in type isn't derived from CallExpr.
260*700637cbSDimitry Andric       if (MemberOp->getOperator() ==
261*700637cbSDimitry Andric           OO_Equal) { // Ignore assignment to Ref/RefPtr.
262*700637cbSDimitry Andric         auto *callee = MemberOp->getDirectCallee();
263*700637cbSDimitry Andric         if (auto *calleeDecl = dyn_cast<CXXMethodDecl>(callee)) {
264*700637cbSDimitry Andric           if (const CXXRecordDecl *classDecl = calleeDecl->getParent()) {
265*700637cbSDimitry Andric             if (isSafePtr(classDecl))
266*700637cbSDimitry Andric               return true;
267*700637cbSDimitry Andric           }
268*700637cbSDimitry Andric         }
269*700637cbSDimitry Andric       }
270*700637cbSDimitry Andric       if (MemberOp->isAssignmentOp())
271*700637cbSDimitry Andric         return false;
272*700637cbSDimitry Andric     }
273*700637cbSDimitry Andric 
274*700637cbSDimitry Andric     if (!Callee)
275*700637cbSDimitry Andric       return false;
276*700637cbSDimitry Andric 
277*700637cbSDimitry Andric     if (isMethodOnWTFContainerType(Callee))
278*700637cbSDimitry Andric       return true;
279*700637cbSDimitry Andric 
280*700637cbSDimitry Andric     auto overloadedOperatorType = Callee->getOverloadedOperator();
281*700637cbSDimitry Andric     if (overloadedOperatorType == OO_EqualEqual ||
282*700637cbSDimitry Andric         overloadedOperatorType == OO_ExclaimEqual ||
283*700637cbSDimitry Andric         overloadedOperatorType == OO_LessEqual ||
284*700637cbSDimitry Andric         overloadedOperatorType == OO_GreaterEqual ||
285*700637cbSDimitry Andric         overloadedOperatorType == OO_Spaceship ||
286*700637cbSDimitry Andric         overloadedOperatorType == OO_AmpAmp ||
287*700637cbSDimitry Andric         overloadedOperatorType == OO_PipePipe)
288*700637cbSDimitry Andric       return true;
289*700637cbSDimitry Andric 
290*700637cbSDimitry Andric     if (isCtorOfSafePtr(Callee) || isPtrConversion(Callee))
291*700637cbSDimitry Andric       return true;
292*700637cbSDimitry Andric 
293*700637cbSDimitry Andric     auto name = safeGetName(Callee);
294*700637cbSDimitry Andric     if (name == "adoptRef" || name == "getPtr" || name == "WeakPtr" ||
295*700637cbSDimitry Andric         name == "is" || name == "equal" || name == "hash" || name == "isType" ||
296*700637cbSDimitry Andric         // FIXME: Most/all of these should be implemented via attributes.
297*700637cbSDimitry Andric         name == "CFEqual" || name == "equalIgnoringASCIICase" ||
298*700637cbSDimitry Andric         name == "equalIgnoringASCIICaseCommon" ||
299*700637cbSDimitry Andric         name == "equalIgnoringNullity" || name == "toString")
300*700637cbSDimitry Andric       return true;
301*700637cbSDimitry Andric 
302*700637cbSDimitry Andric     return false;
303*700637cbSDimitry Andric   }
304*700637cbSDimitry Andric 
isMethodOnWTFContainerType(const FunctionDecl * Decl) const305*700637cbSDimitry Andric   bool isMethodOnWTFContainerType(const FunctionDecl *Decl) const {
306*700637cbSDimitry Andric     if (!isa<CXXMethodDecl>(Decl))
307*700637cbSDimitry Andric       return false;
308*700637cbSDimitry Andric     auto *ClassDecl = Decl->getParent();
309*700637cbSDimitry Andric     if (!ClassDecl || !isa<CXXRecordDecl>(ClassDecl))
310*700637cbSDimitry Andric       return false;
311*700637cbSDimitry Andric 
312*700637cbSDimitry Andric     auto *NsDecl = ClassDecl->getParent();
313*700637cbSDimitry Andric     if (!NsDecl || !isa<NamespaceDecl>(NsDecl))
314*700637cbSDimitry Andric       return false;
315*700637cbSDimitry Andric 
316*700637cbSDimitry Andric     auto MethodName = safeGetName(Decl);
317*700637cbSDimitry Andric     auto ClsNameStr = safeGetName(ClassDecl);
318*700637cbSDimitry Andric     StringRef ClsName = ClsNameStr; // FIXME: Make safeGetName return StringRef.
319*700637cbSDimitry Andric     auto NamespaceName = safeGetName(NsDecl);
320*700637cbSDimitry Andric     // FIXME: These should be implemented via attributes.
321*700637cbSDimitry Andric     return NamespaceName == "WTF" &&
322*700637cbSDimitry Andric            (MethodName == "find" || MethodName == "findIf" ||
323*700637cbSDimitry Andric             MethodName == "reverseFind" || MethodName == "reverseFindIf" ||
324*700637cbSDimitry Andric             MethodName == "findIgnoringASCIICase" || MethodName == "get" ||
325*700637cbSDimitry Andric             MethodName == "inlineGet" || MethodName == "contains" ||
326*700637cbSDimitry Andric             MethodName == "containsIf" ||
327*700637cbSDimitry Andric             MethodName == "containsIgnoringASCIICase" ||
328*700637cbSDimitry Andric             MethodName == "startsWith" || MethodName == "endsWith" ||
329*700637cbSDimitry Andric             MethodName == "startsWithIgnoringASCIICase" ||
330*700637cbSDimitry Andric             MethodName == "endsWithIgnoringASCIICase" ||
331*700637cbSDimitry Andric             MethodName == "substring") &&
332*700637cbSDimitry Andric            (ClsName.ends_with("Vector") || ClsName.ends_with("Set") ||
333*700637cbSDimitry Andric             ClsName.ends_with("Map") || ClsName == "StringImpl" ||
334*700637cbSDimitry Andric             ClsName.ends_with("String"));
335*700637cbSDimitry Andric   }
336*700637cbSDimitry Andric 
reportBug(const Expr * CallArg,const ParmVarDecl * Param,const Decl * DeclWithIssue) const337*700637cbSDimitry Andric   void reportBug(const Expr *CallArg, const ParmVarDecl *Param,
338*700637cbSDimitry Andric                  const Decl *DeclWithIssue) const {
339*700637cbSDimitry Andric     assert(CallArg);
340*700637cbSDimitry Andric 
341*700637cbSDimitry Andric     SmallString<100> Buf;
342*700637cbSDimitry Andric     llvm::raw_svector_ostream Os(Buf);
343*700637cbSDimitry Andric 
344*700637cbSDimitry Andric     const std::string paramName = safeGetName(Param);
345*700637cbSDimitry Andric     Os << "Call argument";
346*700637cbSDimitry Andric     if (!paramName.empty()) {
347*700637cbSDimitry Andric       Os << " for parameter ";
348*700637cbSDimitry Andric       printQuotedQualifiedName(Os, Param);
349*700637cbSDimitry Andric     }
350*700637cbSDimitry Andric     Os << " is " << ptrKind() << " and unsafe.";
351*700637cbSDimitry Andric 
352*700637cbSDimitry Andric     bool usesDefaultArgValue = isa<CXXDefaultArgExpr>(CallArg) && Param;
353*700637cbSDimitry Andric     const SourceLocation SrcLocToReport =
354*700637cbSDimitry Andric         usesDefaultArgValue ? Param->getDefaultArg()->getExprLoc()
355*700637cbSDimitry Andric                             : CallArg->getSourceRange().getBegin();
356*700637cbSDimitry Andric 
357*700637cbSDimitry Andric     PathDiagnosticLocation BSLoc(SrcLocToReport, BR->getSourceManager());
358*700637cbSDimitry Andric     auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
359*700637cbSDimitry Andric     Report->addRange(CallArg->getSourceRange());
360*700637cbSDimitry Andric     Report->setDeclWithIssue(DeclWithIssue);
361*700637cbSDimitry Andric     BR->emitReport(std::move(Report));
362*700637cbSDimitry Andric   }
363*700637cbSDimitry Andric 
reportBugOnThis(const Expr * CallArg,const Decl * DeclWithIssue) const364*700637cbSDimitry Andric   void reportBugOnThis(const Expr *CallArg, const Decl *DeclWithIssue) const {
365*700637cbSDimitry Andric     assert(CallArg);
366*700637cbSDimitry Andric 
367*700637cbSDimitry Andric     const SourceLocation SrcLocToReport = CallArg->getSourceRange().getBegin();
368*700637cbSDimitry Andric 
369*700637cbSDimitry Andric     SmallString<100> Buf;
370*700637cbSDimitry Andric     llvm::raw_svector_ostream Os(Buf);
371*700637cbSDimitry Andric     Os << "Call argument for 'this' parameter is " << ptrKind();
372*700637cbSDimitry Andric     Os << " and unsafe.";
373*700637cbSDimitry Andric 
374*700637cbSDimitry Andric     PathDiagnosticLocation BSLoc(SrcLocToReport, BR->getSourceManager());
375*700637cbSDimitry Andric     auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
376*700637cbSDimitry Andric     Report->addRange(CallArg->getSourceRange());
377*700637cbSDimitry Andric     Report->setDeclWithIssue(DeclWithIssue);
378*700637cbSDimitry Andric     BR->emitReport(std::move(Report));
379*700637cbSDimitry Andric   }
380*700637cbSDimitry Andric 
reportBugOnReceiver(const Expr * CallArg,const Decl * DeclWithIssue) const381*700637cbSDimitry Andric   void reportBugOnReceiver(const Expr *CallArg,
382*700637cbSDimitry Andric                            const Decl *DeclWithIssue) const {
383*700637cbSDimitry Andric     assert(CallArg);
384*700637cbSDimitry Andric 
385*700637cbSDimitry Andric     const SourceLocation SrcLocToReport = CallArg->getSourceRange().getBegin();
386*700637cbSDimitry Andric 
387*700637cbSDimitry Andric     SmallString<100> Buf;
388*700637cbSDimitry Andric     llvm::raw_svector_ostream Os(Buf);
389*700637cbSDimitry Andric     Os << "Reciever is " << ptrKind() << " and unsafe.";
390*700637cbSDimitry Andric 
391*700637cbSDimitry Andric     PathDiagnosticLocation BSLoc(SrcLocToReport, BR->getSourceManager());
392*700637cbSDimitry Andric     auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
393*700637cbSDimitry Andric     Report->addRange(CallArg->getSourceRange());
394*700637cbSDimitry Andric     Report->setDeclWithIssue(DeclWithIssue);
395*700637cbSDimitry Andric     BR->emitReport(std::move(Report));
396*700637cbSDimitry Andric   }
397*700637cbSDimitry Andric };
398*700637cbSDimitry Andric 
399*700637cbSDimitry Andric class UncountedCallArgsChecker final : public RawPtrRefCallArgsChecker {
400*700637cbSDimitry Andric public:
UncountedCallArgsChecker()401*700637cbSDimitry Andric   UncountedCallArgsChecker()
402*700637cbSDimitry Andric       : RawPtrRefCallArgsChecker("Uncounted call argument for a raw "
403*700637cbSDimitry Andric                                  "pointer/reference parameter") {}
404*700637cbSDimitry Andric 
isUnsafeType(QualType QT) const405*700637cbSDimitry Andric   std::optional<bool> isUnsafeType(QualType QT) const final {
406*700637cbSDimitry Andric     return isUncounted(QT);
407*700637cbSDimitry Andric   }
408*700637cbSDimitry Andric 
isUnsafePtr(QualType QT) const409*700637cbSDimitry Andric   std::optional<bool> isUnsafePtr(QualType QT) const final {
410*700637cbSDimitry Andric     return isUncountedPtr(QT.getCanonicalType());
411*700637cbSDimitry Andric   }
412*700637cbSDimitry Andric 
isSafePtr(const CXXRecordDecl * Record) const413*700637cbSDimitry Andric   bool isSafePtr(const CXXRecordDecl *Record) const final {
414*700637cbSDimitry Andric     return isRefCounted(Record) || isCheckedPtr(Record);
415*700637cbSDimitry Andric   }
416*700637cbSDimitry Andric 
isSafePtrType(const QualType type) const417*700637cbSDimitry Andric   bool isSafePtrType(const QualType type) const final {
418*700637cbSDimitry Andric     return isRefOrCheckedPtrType(type);
419*700637cbSDimitry Andric   }
420*700637cbSDimitry Andric 
ptrKind() const421*700637cbSDimitry Andric   const char *ptrKind() const final { return "uncounted"; }
422*700637cbSDimitry Andric };
423*700637cbSDimitry Andric 
424*700637cbSDimitry Andric class UncheckedCallArgsChecker final : public RawPtrRefCallArgsChecker {
425*700637cbSDimitry Andric public:
UncheckedCallArgsChecker()426*700637cbSDimitry Andric   UncheckedCallArgsChecker()
427*700637cbSDimitry Andric       : RawPtrRefCallArgsChecker("Unchecked call argument for a raw "
428*700637cbSDimitry Andric                                  "pointer/reference parameter") {}
429*700637cbSDimitry Andric 
isUnsafeType(QualType QT) const430*700637cbSDimitry Andric   std::optional<bool> isUnsafeType(QualType QT) const final {
431*700637cbSDimitry Andric     return isUnchecked(QT);
432*700637cbSDimitry Andric   }
433*700637cbSDimitry Andric 
isUnsafePtr(QualType QT) const434*700637cbSDimitry Andric   std::optional<bool> isUnsafePtr(QualType QT) const final {
435*700637cbSDimitry Andric     return isUncheckedPtr(QT.getCanonicalType());
436*700637cbSDimitry Andric   }
437*700637cbSDimitry Andric 
isSafePtr(const CXXRecordDecl * Record) const438*700637cbSDimitry Andric   bool isSafePtr(const CXXRecordDecl *Record) const final {
439*700637cbSDimitry Andric     return isRefCounted(Record) || isCheckedPtr(Record);
440*700637cbSDimitry Andric   }
441*700637cbSDimitry Andric 
isSafePtrType(const QualType type) const442*700637cbSDimitry Andric   bool isSafePtrType(const QualType type) const final {
443*700637cbSDimitry Andric     return isRefOrCheckedPtrType(type);
444*700637cbSDimitry Andric   }
445*700637cbSDimitry Andric 
isSafeExpr(const Expr * E) const446*700637cbSDimitry Andric   bool isSafeExpr(const Expr *E) const final {
447*700637cbSDimitry Andric     return isExprToGetCheckedPtrCapableMember(E);
448*700637cbSDimitry Andric   }
449*700637cbSDimitry Andric 
ptrKind() const450*700637cbSDimitry Andric   const char *ptrKind() const final { return "unchecked"; }
451*700637cbSDimitry Andric };
452*700637cbSDimitry Andric 
453*700637cbSDimitry Andric class UnretainedCallArgsChecker final : public RawPtrRefCallArgsChecker {
454*700637cbSDimitry Andric public:
UnretainedCallArgsChecker()455*700637cbSDimitry Andric   UnretainedCallArgsChecker()
456*700637cbSDimitry Andric       : RawPtrRefCallArgsChecker("Unretained call argument for a raw "
457*700637cbSDimitry Andric                                  "pointer/reference parameter") {
458*700637cbSDimitry Andric     RTC = RetainTypeChecker();
459*700637cbSDimitry Andric   }
460*700637cbSDimitry Andric 
isUnsafeType(QualType QT) const461*700637cbSDimitry Andric   std::optional<bool> isUnsafeType(QualType QT) const final {
462*700637cbSDimitry Andric     return RTC->isUnretained(QT);
463*700637cbSDimitry Andric   }
464*700637cbSDimitry Andric 
isUnsafePtr(QualType QT) const465*700637cbSDimitry Andric   std::optional<bool> isUnsafePtr(QualType QT) const final {
466*700637cbSDimitry Andric     return RTC->isUnretained(QT);
467*700637cbSDimitry Andric   }
468*700637cbSDimitry Andric 
isSafePtr(const CXXRecordDecl * Record) const469*700637cbSDimitry Andric   bool isSafePtr(const CXXRecordDecl *Record) const final {
470*700637cbSDimitry Andric     return isRetainPtr(Record);
471*700637cbSDimitry Andric   }
472*700637cbSDimitry Andric 
isSafePtrType(const QualType type) const473*700637cbSDimitry Andric   bool isSafePtrType(const QualType type) const final {
474*700637cbSDimitry Andric     return isRetainPtrType(type);
475*700637cbSDimitry Andric   }
476*700637cbSDimitry Andric 
isSafeExpr(const Expr * E) const477*700637cbSDimitry Andric   bool isSafeExpr(const Expr *E) const final {
478*700637cbSDimitry Andric     return ento::cocoa::isCocoaObjectRef(E->getType()) &&
479*700637cbSDimitry Andric            isa<ObjCMessageExpr>(E);
480*700637cbSDimitry Andric   }
481*700637cbSDimitry Andric 
ptrKind() const482*700637cbSDimitry Andric   const char *ptrKind() const final { return "unretained"; }
483*700637cbSDimitry Andric };
484*700637cbSDimitry Andric 
485*700637cbSDimitry Andric } // namespace
486*700637cbSDimitry Andric 
registerUncountedCallArgsChecker(CheckerManager & Mgr)487*700637cbSDimitry Andric void ento::registerUncountedCallArgsChecker(CheckerManager &Mgr) {
488*700637cbSDimitry Andric   Mgr.registerChecker<UncountedCallArgsChecker>();
489*700637cbSDimitry Andric }
490*700637cbSDimitry Andric 
shouldRegisterUncountedCallArgsChecker(const CheckerManager &)491*700637cbSDimitry Andric bool ento::shouldRegisterUncountedCallArgsChecker(const CheckerManager &) {
492*700637cbSDimitry Andric   return true;
493*700637cbSDimitry Andric }
494*700637cbSDimitry Andric 
registerUncheckedCallArgsChecker(CheckerManager & Mgr)495*700637cbSDimitry Andric void ento::registerUncheckedCallArgsChecker(CheckerManager &Mgr) {
496*700637cbSDimitry Andric   Mgr.registerChecker<UncheckedCallArgsChecker>();
497*700637cbSDimitry Andric }
498*700637cbSDimitry Andric 
shouldRegisterUncheckedCallArgsChecker(const CheckerManager &)499*700637cbSDimitry Andric bool ento::shouldRegisterUncheckedCallArgsChecker(const CheckerManager &) {
500*700637cbSDimitry Andric   return true;
501*700637cbSDimitry Andric }
502*700637cbSDimitry Andric 
registerUnretainedCallArgsChecker(CheckerManager & Mgr)503*700637cbSDimitry Andric void ento::registerUnretainedCallArgsChecker(CheckerManager &Mgr) {
504*700637cbSDimitry Andric   Mgr.registerChecker<UnretainedCallArgsChecker>();
505*700637cbSDimitry Andric }
506*700637cbSDimitry Andric 
shouldRegisterUnretainedCallArgsChecker(const CheckerManager &)507*700637cbSDimitry Andric bool ento::shouldRegisterUnretainedCallArgsChecker(const CheckerManager &) {
508*700637cbSDimitry Andric   return true;
509*700637cbSDimitry Andric }
510