1e5dd7070Spatrick //===- CallEvent.cpp - Wrapper for all function and method calls ----------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick /// \file This file defines CallEvent and its subclasses, which represent path-
10e5dd7070Spatrick /// sensitive instances of different kinds of function and method calls
11e5dd7070Spatrick /// (C, C++, and Objective-C).
12e5dd7070Spatrick //
13e5dd7070Spatrick //===----------------------------------------------------------------------===//
14e5dd7070Spatrick
15e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
16e5dd7070Spatrick #include "clang/AST/ASTContext.h"
17e5dd7070Spatrick #include "clang/AST/Attr.h"
18e5dd7070Spatrick #include "clang/AST/Decl.h"
19e5dd7070Spatrick #include "clang/AST/DeclBase.h"
20e5dd7070Spatrick #include "clang/AST/DeclCXX.h"
21e5dd7070Spatrick #include "clang/AST/DeclObjC.h"
22e5dd7070Spatrick #include "clang/AST/Expr.h"
23e5dd7070Spatrick #include "clang/AST/ExprCXX.h"
24e5dd7070Spatrick #include "clang/AST/ExprObjC.h"
25e5dd7070Spatrick #include "clang/AST/ParentMap.h"
26e5dd7070Spatrick #include "clang/AST/Stmt.h"
27e5dd7070Spatrick #include "clang/AST/Type.h"
28e5dd7070Spatrick #include "clang/Analysis/AnalysisDeclContext.h"
29e5dd7070Spatrick #include "clang/Analysis/CFG.h"
30e5dd7070Spatrick #include "clang/Analysis/CFGStmtMap.h"
31e5dd7070Spatrick #include "clang/Analysis/PathDiagnostic.h"
32e5dd7070Spatrick #include "clang/Analysis/ProgramPoint.h"
33e5dd7070Spatrick #include "clang/Basic/IdentifierTable.h"
34e5dd7070Spatrick #include "clang/Basic/LLVM.h"
35e5dd7070Spatrick #include "clang/Basic/SourceLocation.h"
36e5dd7070Spatrick #include "clang/Basic/SourceManager.h"
37e5dd7070Spatrick #include "clang/Basic/Specifiers.h"
38e5dd7070Spatrick #include "clang/CrossTU/CrossTranslationUnit.h"
39*12c85518Srobert #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
40e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
41e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
42e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h"
43e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
44e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
45e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
46e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
47e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
48e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
49e5dd7070Spatrick #include "llvm/ADT/ArrayRef.h"
50e5dd7070Spatrick #include "llvm/ADT/DenseMap.h"
51a9ac8606Spatrick #include "llvm/ADT/ImmutableList.h"
52e5dd7070Spatrick #include "llvm/ADT/PointerIntPair.h"
53e5dd7070Spatrick #include "llvm/ADT/SmallSet.h"
54e5dd7070Spatrick #include "llvm/ADT/SmallVector.h"
55e5dd7070Spatrick #include "llvm/ADT/StringExtras.h"
56e5dd7070Spatrick #include "llvm/ADT/StringRef.h"
57e5dd7070Spatrick #include "llvm/Support/Casting.h"
58e5dd7070Spatrick #include "llvm/Support/Compiler.h"
59e5dd7070Spatrick #include "llvm/Support/Debug.h"
60e5dd7070Spatrick #include "llvm/Support/ErrorHandling.h"
61e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
62e5dd7070Spatrick #include <cassert>
63*12c85518Srobert #include <optional>
64e5dd7070Spatrick #include <utility>
65e5dd7070Spatrick
66e5dd7070Spatrick #define DEBUG_TYPE "static-analyzer-call-event"
67e5dd7070Spatrick
68e5dd7070Spatrick using namespace clang;
69e5dd7070Spatrick using namespace ento;
70e5dd7070Spatrick
getResultType() const71e5dd7070Spatrick QualType CallEvent::getResultType() const {
72e5dd7070Spatrick ASTContext &Ctx = getState()->getStateManager().getContext();
73e5dd7070Spatrick const Expr *E = getOriginExpr();
74e5dd7070Spatrick if (!E)
75e5dd7070Spatrick return Ctx.VoidTy;
76*12c85518Srobert return Ctx.getReferenceQualifiedType(E);
77e5dd7070Spatrick }
78e5dd7070Spatrick
isCallback(QualType T)79e5dd7070Spatrick static bool isCallback(QualType T) {
80e5dd7070Spatrick // If a parameter is a block or a callback, assume it can modify pointer.
81e5dd7070Spatrick if (T->isBlockPointerType() ||
82e5dd7070Spatrick T->isFunctionPointerType() ||
83e5dd7070Spatrick T->isObjCSelType())
84e5dd7070Spatrick return true;
85e5dd7070Spatrick
86e5dd7070Spatrick // Check if a callback is passed inside a struct (for both, struct passed by
87e5dd7070Spatrick // reference and by value). Dig just one level into the struct for now.
88e5dd7070Spatrick
89e5dd7070Spatrick if (T->isAnyPointerType() || T->isReferenceType())
90e5dd7070Spatrick T = T->getPointeeType();
91e5dd7070Spatrick
92e5dd7070Spatrick if (const RecordType *RT = T->getAsStructureType()) {
93e5dd7070Spatrick const RecordDecl *RD = RT->getDecl();
94e5dd7070Spatrick for (const auto *I : RD->fields()) {
95e5dd7070Spatrick QualType FieldT = I->getType();
96e5dd7070Spatrick if (FieldT->isBlockPointerType() || FieldT->isFunctionPointerType())
97e5dd7070Spatrick return true;
98e5dd7070Spatrick }
99e5dd7070Spatrick }
100e5dd7070Spatrick return false;
101e5dd7070Spatrick }
102e5dd7070Spatrick
isVoidPointerToNonConst(QualType T)103e5dd7070Spatrick static bool isVoidPointerToNonConst(QualType T) {
104e5dd7070Spatrick if (const auto *PT = T->getAs<PointerType>()) {
105e5dd7070Spatrick QualType PointeeTy = PT->getPointeeType();
106e5dd7070Spatrick if (PointeeTy.isConstQualified())
107e5dd7070Spatrick return false;
108e5dd7070Spatrick return PointeeTy->isVoidType();
109e5dd7070Spatrick } else
110e5dd7070Spatrick return false;
111e5dd7070Spatrick }
112e5dd7070Spatrick
hasNonNullArgumentsWithType(bool (* Condition)(QualType)) const113e5dd7070Spatrick bool CallEvent::hasNonNullArgumentsWithType(bool (*Condition)(QualType)) const {
114e5dd7070Spatrick unsigned NumOfArgs = getNumArgs();
115e5dd7070Spatrick
116e5dd7070Spatrick // If calling using a function pointer, assume the function does not
117e5dd7070Spatrick // satisfy the callback.
118e5dd7070Spatrick // TODO: We could check the types of the arguments here.
119e5dd7070Spatrick if (!getDecl())
120e5dd7070Spatrick return false;
121e5dd7070Spatrick
122e5dd7070Spatrick unsigned Idx = 0;
123e5dd7070Spatrick for (CallEvent::param_type_iterator I = param_type_begin(),
124e5dd7070Spatrick E = param_type_end();
125e5dd7070Spatrick I != E && Idx < NumOfArgs; ++I, ++Idx) {
126e5dd7070Spatrick // If the parameter is 0, it's harmless.
127e5dd7070Spatrick if (getArgSVal(Idx).isZeroConstant())
128e5dd7070Spatrick continue;
129e5dd7070Spatrick
130e5dd7070Spatrick if (Condition(*I))
131e5dd7070Spatrick return true;
132e5dd7070Spatrick }
133e5dd7070Spatrick return false;
134e5dd7070Spatrick }
135e5dd7070Spatrick
hasNonZeroCallbackArg() const136e5dd7070Spatrick bool CallEvent::hasNonZeroCallbackArg() const {
137e5dd7070Spatrick return hasNonNullArgumentsWithType(isCallback);
138e5dd7070Spatrick }
139e5dd7070Spatrick
hasVoidPointerToNonConstArg() const140e5dd7070Spatrick bool CallEvent::hasVoidPointerToNonConstArg() const {
141e5dd7070Spatrick return hasNonNullArgumentsWithType(isVoidPointerToNonConst);
142e5dd7070Spatrick }
143e5dd7070Spatrick
isGlobalCFunction(StringRef FunctionName) const144e5dd7070Spatrick bool CallEvent::isGlobalCFunction(StringRef FunctionName) const {
145e5dd7070Spatrick const auto *FD = dyn_cast_or_null<FunctionDecl>(getDecl());
146e5dd7070Spatrick if (!FD)
147e5dd7070Spatrick return false;
148e5dd7070Spatrick
149e5dd7070Spatrick return CheckerContext::isCLibraryFunction(FD, FunctionName);
150e5dd7070Spatrick }
151e5dd7070Spatrick
getCalleeAnalysisDeclContext() const152e5dd7070Spatrick AnalysisDeclContext *CallEvent::getCalleeAnalysisDeclContext() const {
153e5dd7070Spatrick const Decl *D = getDecl();
154e5dd7070Spatrick if (!D)
155e5dd7070Spatrick return nullptr;
156e5dd7070Spatrick
157e5dd7070Spatrick AnalysisDeclContext *ADC =
158e5dd7070Spatrick LCtx->getAnalysisDeclContext()->getManager()->getContext(D);
159e5dd7070Spatrick
160e5dd7070Spatrick return ADC;
161e5dd7070Spatrick }
162e5dd7070Spatrick
163e5dd7070Spatrick const StackFrameContext *
getCalleeStackFrame(unsigned BlockCount) const164e5dd7070Spatrick CallEvent::getCalleeStackFrame(unsigned BlockCount) const {
165e5dd7070Spatrick AnalysisDeclContext *ADC = getCalleeAnalysisDeclContext();
166e5dd7070Spatrick if (!ADC)
167e5dd7070Spatrick return nullptr;
168e5dd7070Spatrick
169e5dd7070Spatrick const Expr *E = getOriginExpr();
170e5dd7070Spatrick if (!E)
171e5dd7070Spatrick return nullptr;
172e5dd7070Spatrick
173e5dd7070Spatrick // Recover CFG block via reverse lookup.
174e5dd7070Spatrick // TODO: If we were to keep CFG element information as part of the CallEvent
175e5dd7070Spatrick // instead of doing this reverse lookup, we would be able to build the stack
176e5dd7070Spatrick // frame for non-expression-based calls, and also we wouldn't need the reverse
177e5dd7070Spatrick // lookup.
178e5dd7070Spatrick CFGStmtMap *Map = LCtx->getAnalysisDeclContext()->getCFGStmtMap();
179e5dd7070Spatrick const CFGBlock *B = Map->getBlock(E);
180e5dd7070Spatrick assert(B);
181e5dd7070Spatrick
182e5dd7070Spatrick // Also recover CFG index by scanning the CFG block.
183e5dd7070Spatrick unsigned Idx = 0, Sz = B->size();
184e5dd7070Spatrick for (; Idx < Sz; ++Idx)
185e5dd7070Spatrick if (auto StmtElem = (*B)[Idx].getAs<CFGStmt>())
186e5dd7070Spatrick if (StmtElem->getStmt() == E)
187e5dd7070Spatrick break;
188e5dd7070Spatrick assert(Idx < Sz);
189e5dd7070Spatrick
190e5dd7070Spatrick return ADC->getManager()->getStackFrame(ADC, LCtx, E, B, BlockCount, Idx);
191e5dd7070Spatrick }
192e5dd7070Spatrick
193ec727ea7Spatrick const ParamVarRegion
getParameterLocation(unsigned Index,unsigned BlockCount) const194ec727ea7Spatrick *CallEvent::getParameterLocation(unsigned Index, unsigned BlockCount) const {
195e5dd7070Spatrick const StackFrameContext *SFC = getCalleeStackFrame(BlockCount);
196e5dd7070Spatrick // We cannot construct a VarRegion without a stack frame.
197e5dd7070Spatrick if (!SFC)
198e5dd7070Spatrick return nullptr;
199e5dd7070Spatrick
200ec727ea7Spatrick const ParamVarRegion *PVR =
201ec727ea7Spatrick State->getStateManager().getRegionManager().getParamVarRegion(
202ec727ea7Spatrick getOriginExpr(), Index, SFC);
203ec727ea7Spatrick return PVR;
204e5dd7070Spatrick }
205e5dd7070Spatrick
206e5dd7070Spatrick /// Returns true if a type is a pointer-to-const or reference-to-const
207e5dd7070Spatrick /// with no further indirection.
isPointerToConst(QualType Ty)208e5dd7070Spatrick static bool isPointerToConst(QualType Ty) {
209e5dd7070Spatrick QualType PointeeTy = Ty->getPointeeType();
210e5dd7070Spatrick if (PointeeTy == QualType())
211e5dd7070Spatrick return false;
212e5dd7070Spatrick if (!PointeeTy.isConstQualified())
213e5dd7070Spatrick return false;
214e5dd7070Spatrick if (PointeeTy->isAnyPointerType())
215e5dd7070Spatrick return false;
216e5dd7070Spatrick return true;
217e5dd7070Spatrick }
218e5dd7070Spatrick
219e5dd7070Spatrick // Try to retrieve the function declaration and find the function parameter
220e5dd7070Spatrick // types which are pointers/references to a non-pointer const.
221e5dd7070Spatrick // We will not invalidate the corresponding argument regions.
findPtrToConstParams(llvm::SmallSet<unsigned,4> & PreserveArgs,const CallEvent & Call)222e5dd7070Spatrick static void findPtrToConstParams(llvm::SmallSet<unsigned, 4> &PreserveArgs,
223e5dd7070Spatrick const CallEvent &Call) {
224e5dd7070Spatrick unsigned Idx = 0;
225e5dd7070Spatrick for (CallEvent::param_type_iterator I = Call.param_type_begin(),
226e5dd7070Spatrick E = Call.param_type_end();
227e5dd7070Spatrick I != E; ++I, ++Idx) {
228e5dd7070Spatrick if (isPointerToConst(*I))
229e5dd7070Spatrick PreserveArgs.insert(Idx);
230e5dd7070Spatrick }
231e5dd7070Spatrick }
232e5dd7070Spatrick
invalidateRegions(unsigned BlockCount,ProgramStateRef Orig) const233e5dd7070Spatrick ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
234e5dd7070Spatrick ProgramStateRef Orig) const {
235e5dd7070Spatrick ProgramStateRef Result = (Orig ? Orig : getState());
236e5dd7070Spatrick
237e5dd7070Spatrick // Don't invalidate anything if the callee is marked pure/const.
238e5dd7070Spatrick if (const Decl *callee = getDecl())
239e5dd7070Spatrick if (callee->hasAttr<PureAttr>() || callee->hasAttr<ConstAttr>())
240e5dd7070Spatrick return Result;
241e5dd7070Spatrick
242e5dd7070Spatrick SmallVector<SVal, 8> ValuesToInvalidate;
243e5dd7070Spatrick RegionAndSymbolInvalidationTraits ETraits;
244e5dd7070Spatrick
245e5dd7070Spatrick getExtraInvalidatedValues(ValuesToInvalidate, &ETraits);
246e5dd7070Spatrick
247e5dd7070Spatrick // Indexes of arguments whose values will be preserved by the call.
248e5dd7070Spatrick llvm::SmallSet<unsigned, 4> PreserveArgs;
249e5dd7070Spatrick if (!argumentsMayEscape())
250e5dd7070Spatrick findPtrToConstParams(PreserveArgs, *this);
251e5dd7070Spatrick
252e5dd7070Spatrick for (unsigned Idx = 0, Count = getNumArgs(); Idx != Count; ++Idx) {
253e5dd7070Spatrick // Mark this region for invalidation. We batch invalidate regions
254e5dd7070Spatrick // below for efficiency.
255e5dd7070Spatrick if (PreserveArgs.count(Idx))
256e5dd7070Spatrick if (const MemRegion *MR = getArgSVal(Idx).getAsRegion())
257e5dd7070Spatrick ETraits.setTrait(MR->getBaseRegion(),
258e5dd7070Spatrick RegionAndSymbolInvalidationTraits::TK_PreserveContents);
259e5dd7070Spatrick // TODO: Factor this out + handle the lower level const pointers.
260e5dd7070Spatrick
261e5dd7070Spatrick ValuesToInvalidate.push_back(getArgSVal(Idx));
262e5dd7070Spatrick
263e5dd7070Spatrick // If a function accepts an object by argument (which would of course be a
264e5dd7070Spatrick // temporary that isn't lifetime-extended), invalidate the object itself,
265e5dd7070Spatrick // not only other objects reachable from it. This is necessary because the
266e5dd7070Spatrick // destructor has access to the temporary object after the call.
267e5dd7070Spatrick // TODO: Support placement arguments once we start
268e5dd7070Spatrick // constructing them directly.
269e5dd7070Spatrick // TODO: This is unnecessary when there's no destructor, but that's
270e5dd7070Spatrick // currently hard to figure out.
271e5dd7070Spatrick if (getKind() != CE_CXXAllocator)
272e5dd7070Spatrick if (isArgumentConstructedDirectly(Idx))
273e5dd7070Spatrick if (auto AdjIdx = getAdjustedParameterIndex(Idx))
274ec727ea7Spatrick if (const TypedValueRegion *TVR =
275ec727ea7Spatrick getParameterLocation(*AdjIdx, BlockCount))
276ec727ea7Spatrick ValuesToInvalidate.push_back(loc::MemRegionVal(TVR));
277e5dd7070Spatrick }
278e5dd7070Spatrick
279e5dd7070Spatrick // Invalidate designated regions using the batch invalidation API.
280e5dd7070Spatrick // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate
281e5dd7070Spatrick // global variables.
282e5dd7070Spatrick return Result->invalidateRegions(ValuesToInvalidate, getOriginExpr(),
283e5dd7070Spatrick BlockCount, getLocationContext(),
284e5dd7070Spatrick /*CausedByPointerEscape*/ true,
285e5dd7070Spatrick /*Symbols=*/nullptr, this, &ETraits);
286e5dd7070Spatrick }
287e5dd7070Spatrick
getProgramPoint(bool IsPreVisit,const ProgramPointTag * Tag) const288e5dd7070Spatrick ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
289e5dd7070Spatrick const ProgramPointTag *Tag) const {
290e5dd7070Spatrick if (const Expr *E = getOriginExpr()) {
291e5dd7070Spatrick if (IsPreVisit)
292e5dd7070Spatrick return PreStmt(E, getLocationContext(), Tag);
293e5dd7070Spatrick return PostStmt(E, getLocationContext(), Tag);
294e5dd7070Spatrick }
295e5dd7070Spatrick
296e5dd7070Spatrick const Decl *D = getDecl();
297e5dd7070Spatrick assert(D && "Cannot get a program point without a statement or decl");
298e5dd7070Spatrick
299e5dd7070Spatrick SourceLocation Loc = getSourceRange().getBegin();
300e5dd7070Spatrick if (IsPreVisit)
301e5dd7070Spatrick return PreImplicitCall(D, Loc, getLocationContext(), Tag);
302e5dd7070Spatrick return PostImplicitCall(D, Loc, getLocationContext(), Tag);
303e5dd7070Spatrick }
304e5dd7070Spatrick
getArgSVal(unsigned Index) const305e5dd7070Spatrick SVal CallEvent::getArgSVal(unsigned Index) const {
306e5dd7070Spatrick const Expr *ArgE = getArgExpr(Index);
307e5dd7070Spatrick if (!ArgE)
308e5dd7070Spatrick return UnknownVal();
309e5dd7070Spatrick return getSVal(ArgE);
310e5dd7070Spatrick }
311e5dd7070Spatrick
getArgSourceRange(unsigned Index) const312e5dd7070Spatrick SourceRange CallEvent::getArgSourceRange(unsigned Index) const {
313e5dd7070Spatrick const Expr *ArgE = getArgExpr(Index);
314e5dd7070Spatrick if (!ArgE)
315e5dd7070Spatrick return {};
316e5dd7070Spatrick return ArgE->getSourceRange();
317e5dd7070Spatrick }
318e5dd7070Spatrick
getReturnValue() const319e5dd7070Spatrick SVal CallEvent::getReturnValue() const {
320e5dd7070Spatrick const Expr *E = getOriginExpr();
321e5dd7070Spatrick if (!E)
322e5dd7070Spatrick return UndefinedVal();
323e5dd7070Spatrick return getSVal(E);
324e5dd7070Spatrick }
325e5dd7070Spatrick
dump() const326e5dd7070Spatrick LLVM_DUMP_METHOD void CallEvent::dump() const { dump(llvm::errs()); }
327e5dd7070Spatrick
dump(raw_ostream & Out) const328e5dd7070Spatrick void CallEvent::dump(raw_ostream &Out) const {
329e5dd7070Spatrick ASTContext &Ctx = getState()->getStateManager().getContext();
330e5dd7070Spatrick if (const Expr *E = getOriginExpr()) {
331e5dd7070Spatrick E->printPretty(Out, nullptr, Ctx.getPrintingPolicy());
332e5dd7070Spatrick return;
333e5dd7070Spatrick }
334e5dd7070Spatrick
335e5dd7070Spatrick if (const Decl *D = getDecl()) {
336e5dd7070Spatrick Out << "Call to ";
337e5dd7070Spatrick D->print(Out, Ctx.getPrintingPolicy());
338e5dd7070Spatrick return;
339e5dd7070Spatrick }
340e5dd7070Spatrick
341ec727ea7Spatrick Out << "Unknown call (type " << getKindAsString() << ")";
342e5dd7070Spatrick }
343e5dd7070Spatrick
isCallStmt(const Stmt * S)344e5dd7070Spatrick bool CallEvent::isCallStmt(const Stmt *S) {
345*12c85518Srobert return isa<CallExpr, ObjCMessageExpr, CXXConstructExpr, CXXNewExpr>(S);
346e5dd7070Spatrick }
347e5dd7070Spatrick
getDeclaredResultType(const Decl * D)348e5dd7070Spatrick QualType CallEvent::getDeclaredResultType(const Decl *D) {
349e5dd7070Spatrick assert(D);
350e5dd7070Spatrick if (const auto *FD = dyn_cast<FunctionDecl>(D))
351e5dd7070Spatrick return FD->getReturnType();
352e5dd7070Spatrick if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
353e5dd7070Spatrick return MD->getReturnType();
354e5dd7070Spatrick if (const auto *BD = dyn_cast<BlockDecl>(D)) {
355e5dd7070Spatrick // Blocks are difficult because the return type may not be stored in the
356e5dd7070Spatrick // BlockDecl itself. The AST should probably be enhanced, but for now we
357e5dd7070Spatrick // just do what we can.
358e5dd7070Spatrick // If the block is declared without an explicit argument list, the
359e5dd7070Spatrick // signature-as-written just includes the return type, not the entire
360e5dd7070Spatrick // function type.
361e5dd7070Spatrick // FIXME: All blocks should have signatures-as-written, even if the return
362e5dd7070Spatrick // type is inferred. (That's signified with a dependent result type.)
363e5dd7070Spatrick if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten()) {
364e5dd7070Spatrick QualType Ty = TSI->getType();
365e5dd7070Spatrick if (const FunctionType *FT = Ty->getAs<FunctionType>())
366e5dd7070Spatrick Ty = FT->getReturnType();
367e5dd7070Spatrick if (!Ty->isDependentType())
368e5dd7070Spatrick return Ty;
369e5dd7070Spatrick }
370e5dd7070Spatrick
371e5dd7070Spatrick return {};
372e5dd7070Spatrick }
373e5dd7070Spatrick
374e5dd7070Spatrick llvm_unreachable("unknown callable kind");
375e5dd7070Spatrick }
376e5dd7070Spatrick
isVariadic(const Decl * D)377e5dd7070Spatrick bool CallEvent::isVariadic(const Decl *D) {
378e5dd7070Spatrick assert(D);
379e5dd7070Spatrick
380e5dd7070Spatrick if (const auto *FD = dyn_cast<FunctionDecl>(D))
381e5dd7070Spatrick return FD->isVariadic();
382e5dd7070Spatrick if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
383e5dd7070Spatrick return MD->isVariadic();
384e5dd7070Spatrick if (const auto *BD = dyn_cast<BlockDecl>(D))
385e5dd7070Spatrick return BD->isVariadic();
386e5dd7070Spatrick
387e5dd7070Spatrick llvm_unreachable("unknown callable kind");
388e5dd7070Spatrick }
389e5dd7070Spatrick
isTransparentUnion(QualType T)390a9ac8606Spatrick static bool isTransparentUnion(QualType T) {
391a9ac8606Spatrick const RecordType *UT = T->getAsUnionType();
392a9ac8606Spatrick return UT && UT->getDecl()->hasAttr<TransparentUnionAttr>();
393a9ac8606Spatrick }
394a9ac8606Spatrick
395a9ac8606Spatrick // In some cases, symbolic cases should be transformed before we associate
396a9ac8606Spatrick // them with parameters. This function incapsulates such cases.
processArgument(SVal Value,const Expr * ArgumentExpr,const ParmVarDecl * Parameter,SValBuilder & SVB)397a9ac8606Spatrick static SVal processArgument(SVal Value, const Expr *ArgumentExpr,
398a9ac8606Spatrick const ParmVarDecl *Parameter, SValBuilder &SVB) {
399a9ac8606Spatrick QualType ParamType = Parameter->getType();
400a9ac8606Spatrick QualType ArgumentType = ArgumentExpr->getType();
401a9ac8606Spatrick
402a9ac8606Spatrick // Transparent unions allow users to easily convert values of union field
403a9ac8606Spatrick // types into union-typed objects.
404a9ac8606Spatrick //
405a9ac8606Spatrick // Also, more importantly, they allow users to define functions with different
406a9ac8606Spatrick // different parameter types, substituting types matching transparent union
407a9ac8606Spatrick // field types with the union type itself.
408a9ac8606Spatrick //
409a9ac8606Spatrick // Here, we check specifically for latter cases and prevent binding
410a9ac8606Spatrick // field-typed values to union-typed regions.
411a9ac8606Spatrick if (isTransparentUnion(ParamType) &&
412a9ac8606Spatrick // Let's check that we indeed trying to bind different types.
413a9ac8606Spatrick !isTransparentUnion(ArgumentType)) {
414a9ac8606Spatrick BasicValueFactory &BVF = SVB.getBasicValueFactory();
415a9ac8606Spatrick
416a9ac8606Spatrick llvm::ImmutableList<SVal> CompoundSVals = BVF.getEmptySValList();
417a9ac8606Spatrick CompoundSVals = BVF.prependSVal(Value, CompoundSVals);
418a9ac8606Spatrick
419a9ac8606Spatrick // Wrap it with compound value.
420a9ac8606Spatrick return SVB.makeCompoundVal(ParamType, CompoundSVals);
421a9ac8606Spatrick }
422a9ac8606Spatrick
423a9ac8606Spatrick return Value;
424a9ac8606Spatrick }
425a9ac8606Spatrick
426*12c85518Srobert /// Cast the argument value to the type of the parameter at the function
427*12c85518Srobert /// declaration.
428*12c85518Srobert /// Returns the argument value if it didn't need a cast.
429*12c85518Srobert /// Or returns the cast argument if it needed a cast.
430*12c85518Srobert /// Or returns 'Unknown' if it would need a cast but the callsite and the
431*12c85518Srobert /// runtime definition don't match in terms of argument and parameter count.
castArgToParamTypeIfNeeded(const CallEvent & Call,unsigned ArgIdx,SVal ArgVal,SValBuilder & SVB)432*12c85518Srobert static SVal castArgToParamTypeIfNeeded(const CallEvent &Call, unsigned ArgIdx,
433*12c85518Srobert SVal ArgVal, SValBuilder &SVB) {
434*12c85518Srobert const FunctionDecl *RTDecl =
435*12c85518Srobert Call.getRuntimeDefinition().getDecl()->getAsFunction();
436*12c85518Srobert const auto *CallExprDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
437*12c85518Srobert
438*12c85518Srobert if (!RTDecl || !CallExprDecl)
439*12c85518Srobert return ArgVal;
440*12c85518Srobert
441*12c85518Srobert // The function decl of the Call (in the AST) will not have any parameter
442*12c85518Srobert // declarations, if it was 'only' declared without a prototype. However, the
443*12c85518Srobert // engine will find the appropriate runtime definition - basically a
444*12c85518Srobert // redeclaration, which has a function body (and a function prototype).
445*12c85518Srobert if (CallExprDecl->hasPrototype() || !RTDecl->hasPrototype())
446*12c85518Srobert return ArgVal;
447*12c85518Srobert
448*12c85518Srobert // Only do this cast if the number arguments at the callsite matches with
449*12c85518Srobert // the parameters at the runtime definition.
450*12c85518Srobert if (Call.getNumArgs() != RTDecl->getNumParams())
451*12c85518Srobert return UnknownVal();
452*12c85518Srobert
453*12c85518Srobert const Expr *ArgExpr = Call.getArgExpr(ArgIdx);
454*12c85518Srobert const ParmVarDecl *Param = RTDecl->getParamDecl(ArgIdx);
455*12c85518Srobert return SVB.evalCast(ArgVal, Param->getType(), ArgExpr->getType());
456*12c85518Srobert }
457*12c85518Srobert
addParameterValuesToBindings(const StackFrameContext * CalleeCtx,CallEvent::BindingsTy & Bindings,SValBuilder & SVB,const CallEvent & Call,ArrayRef<ParmVarDecl * > parameters)458e5dd7070Spatrick static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx,
459e5dd7070Spatrick CallEvent::BindingsTy &Bindings,
460e5dd7070Spatrick SValBuilder &SVB,
461e5dd7070Spatrick const CallEvent &Call,
462e5dd7070Spatrick ArrayRef<ParmVarDecl*> parameters) {
463e5dd7070Spatrick MemRegionManager &MRMgr = SVB.getRegionManager();
464e5dd7070Spatrick
465e5dd7070Spatrick // If the function has fewer parameters than the call has arguments, we simply
466e5dd7070Spatrick // do not bind any values to them.
467e5dd7070Spatrick unsigned NumArgs = Call.getNumArgs();
468e5dd7070Spatrick unsigned Idx = 0;
469e5dd7070Spatrick ArrayRef<ParmVarDecl*>::iterator I = parameters.begin(), E = parameters.end();
470e5dd7070Spatrick for (; I != E && Idx < NumArgs; ++I, ++Idx) {
471ec727ea7Spatrick assert(*I && "Formal parameter has no decl?");
472e5dd7070Spatrick
473e5dd7070Spatrick // TODO: Support allocator calls.
474e5dd7070Spatrick if (Call.getKind() != CE_CXXAllocator)
475e5dd7070Spatrick if (Call.isArgumentConstructedDirectly(Call.getASTArgumentIndex(Idx)))
476e5dd7070Spatrick continue;
477e5dd7070Spatrick
478e5dd7070Spatrick // TODO: Allocators should receive the correct size and possibly alignment,
479e5dd7070Spatrick // determined in compile-time but not represented as arg-expressions,
480e5dd7070Spatrick // which makes getArgSVal() fail and return UnknownVal.
481e5dd7070Spatrick SVal ArgVal = Call.getArgSVal(Idx);
482a9ac8606Spatrick const Expr *ArgExpr = Call.getArgExpr(Idx);
483*12c85518Srobert
484*12c85518Srobert if (ArgVal.isUnknown())
485*12c85518Srobert continue;
486*12c85518Srobert
487*12c85518Srobert // Cast the argument value to match the type of the parameter in some
488*12c85518Srobert // edge-cases.
489*12c85518Srobert ArgVal = castArgToParamTypeIfNeeded(Call, Idx, ArgVal, SVB);
490*12c85518Srobert
491ec727ea7Spatrick Loc ParamLoc = SVB.makeLoc(
492ec727ea7Spatrick MRMgr.getParamVarRegion(Call.getOriginExpr(), Idx, CalleeCtx));
493a9ac8606Spatrick Bindings.push_back(
494a9ac8606Spatrick std::make_pair(ParamLoc, processArgument(ArgVal, ArgExpr, *I, SVB)));
495e5dd7070Spatrick }
496e5dd7070Spatrick
497e5dd7070Spatrick // FIXME: Variadic arguments are not handled at all right now.
498e5dd7070Spatrick }
499e5dd7070Spatrick
getConstructionContext() const500ec727ea7Spatrick const ConstructionContext *CallEvent::getConstructionContext() const {
501ec727ea7Spatrick const StackFrameContext *StackFrame = getCalleeStackFrame(0);
502ec727ea7Spatrick if (!StackFrame)
503ec727ea7Spatrick return nullptr;
504ec727ea7Spatrick
505ec727ea7Spatrick const CFGElement Element = StackFrame->getCallSiteCFGElement();
506ec727ea7Spatrick if (const auto Ctor = Element.getAs<CFGConstructor>()) {
507ec727ea7Spatrick return Ctor->getConstructionContext();
508ec727ea7Spatrick }
509ec727ea7Spatrick
510ec727ea7Spatrick if (const auto RecCall = Element.getAs<CFGCXXRecordTypedCall>()) {
511ec727ea7Spatrick return RecCall->getConstructionContext();
512ec727ea7Spatrick }
513ec727ea7Spatrick
514ec727ea7Spatrick return nullptr;
515ec727ea7Spatrick }
516ec727ea7Spatrick
getReturnValueUnderConstruction() const517*12c85518Srobert std::optional<SVal> CallEvent::getReturnValueUnderConstruction() const {
518ec727ea7Spatrick const auto *CC = getConstructionContext();
519ec727ea7Spatrick if (!CC)
520*12c85518Srobert return std::nullopt;
521ec727ea7Spatrick
522ec727ea7Spatrick EvalCallOptions CallOpts;
523ec727ea7Spatrick ExprEngine &Engine = getState()->getStateManager().getOwningEngine();
524*12c85518Srobert SVal RetVal = Engine.computeObjectUnderConstruction(
525*12c85518Srobert getOriginExpr(), getState(), &Engine.getBuilderContext(),
526ec727ea7Spatrick getLocationContext(), CC, CallOpts);
527ec727ea7Spatrick return RetVal;
528ec727ea7Spatrick }
529ec727ea7Spatrick
parameters() const530e5dd7070Spatrick ArrayRef<ParmVarDecl*> AnyFunctionCall::parameters() const {
531e5dd7070Spatrick const FunctionDecl *D = getDecl();
532e5dd7070Spatrick if (!D)
533*12c85518Srobert return std::nullopt;
534e5dd7070Spatrick return D->parameters();
535e5dd7070Spatrick }
536e5dd7070Spatrick
getRuntimeDefinition() const537e5dd7070Spatrick RuntimeDefinition AnyFunctionCall::getRuntimeDefinition() const {
538e5dd7070Spatrick const FunctionDecl *FD = getDecl();
539e5dd7070Spatrick if (!FD)
540e5dd7070Spatrick return {};
541e5dd7070Spatrick
542e5dd7070Spatrick // Note that the AnalysisDeclContext will have the FunctionDecl with
543e5dd7070Spatrick // the definition (if one exists).
544e5dd7070Spatrick AnalysisDeclContext *AD =
545e5dd7070Spatrick getLocationContext()->getAnalysisDeclContext()->
546e5dd7070Spatrick getManager()->getContext(FD);
547e5dd7070Spatrick bool IsAutosynthesized;
548e5dd7070Spatrick Stmt* Body = AD->getBody(IsAutosynthesized);
549e5dd7070Spatrick LLVM_DEBUG({
550e5dd7070Spatrick if (IsAutosynthesized)
551e5dd7070Spatrick llvm::dbgs() << "Using autosynthesized body for " << FD->getName()
552e5dd7070Spatrick << "\n";
553e5dd7070Spatrick });
554e5dd7070Spatrick
555ec727ea7Spatrick ExprEngine &Engine = getState()->getStateManager().getOwningEngine();
556*12c85518Srobert cross_tu::CrossTranslationUnitContext &CTUCtx =
557*12c85518Srobert *Engine.getCrossTranslationUnitContext();
558*12c85518Srobert
559e5dd7070Spatrick AnalyzerOptions &Opts = Engine.getAnalysisManager().options;
560e5dd7070Spatrick
561*12c85518Srobert if (Body) {
562*12c85518Srobert const Decl* Decl = AD->getDecl();
563*12c85518Srobert if (Opts.IsNaiveCTUEnabled && CTUCtx.isImportedAsNew(Decl)) {
564*12c85518Srobert // A newly created definition, but we had error(s) during the import.
565*12c85518Srobert if (CTUCtx.hasError(Decl))
566*12c85518Srobert return {};
567*12c85518Srobert return RuntimeDefinition(Decl, /*Foreign=*/true);
568*12c85518Srobert }
569*12c85518Srobert return RuntimeDefinition(Decl, /*Foreign=*/false);
570*12c85518Srobert }
571*12c85518Srobert
572e5dd7070Spatrick // Try to get CTU definition only if CTUDir is provided.
573e5dd7070Spatrick if (!Opts.IsNaiveCTUEnabled)
574e5dd7070Spatrick return {};
575e5dd7070Spatrick
576e5dd7070Spatrick llvm::Expected<const FunctionDecl *> CTUDeclOrError =
577e5dd7070Spatrick CTUCtx.getCrossTUDefinition(FD, Opts.CTUDir, Opts.CTUIndexName,
578e5dd7070Spatrick Opts.DisplayCTUProgress);
579e5dd7070Spatrick
580e5dd7070Spatrick if (!CTUDeclOrError) {
581e5dd7070Spatrick handleAllErrors(CTUDeclOrError.takeError(),
582e5dd7070Spatrick [&](const cross_tu::IndexError &IE) {
583e5dd7070Spatrick CTUCtx.emitCrossTUDiagnostics(IE);
584e5dd7070Spatrick });
585e5dd7070Spatrick return {};
586e5dd7070Spatrick }
587e5dd7070Spatrick
588*12c85518Srobert return RuntimeDefinition(*CTUDeclOrError, /*Foreign=*/true);
589e5dd7070Spatrick }
590e5dd7070Spatrick
getInitialStackFrameContents(const StackFrameContext * CalleeCtx,BindingsTy & Bindings) const591e5dd7070Spatrick void AnyFunctionCall::getInitialStackFrameContents(
592e5dd7070Spatrick const StackFrameContext *CalleeCtx,
593e5dd7070Spatrick BindingsTy &Bindings) const {
594e5dd7070Spatrick const auto *D = cast<FunctionDecl>(CalleeCtx->getDecl());
595e5dd7070Spatrick SValBuilder &SVB = getState()->getStateManager().getSValBuilder();
596e5dd7070Spatrick addParameterValuesToBindings(CalleeCtx, Bindings, SVB, *this,
597e5dd7070Spatrick D->parameters());
598e5dd7070Spatrick }
599e5dd7070Spatrick
argumentsMayEscape() const600e5dd7070Spatrick bool AnyFunctionCall::argumentsMayEscape() const {
601e5dd7070Spatrick if (CallEvent::argumentsMayEscape() || hasVoidPointerToNonConstArg())
602e5dd7070Spatrick return true;
603e5dd7070Spatrick
604e5dd7070Spatrick const FunctionDecl *D = getDecl();
605e5dd7070Spatrick if (!D)
606e5dd7070Spatrick return true;
607e5dd7070Spatrick
608e5dd7070Spatrick const IdentifierInfo *II = D->getIdentifier();
609e5dd7070Spatrick if (!II)
610e5dd7070Spatrick return false;
611e5dd7070Spatrick
612e5dd7070Spatrick // This set of "escaping" APIs is
613e5dd7070Spatrick
614e5dd7070Spatrick // - 'int pthread_setspecific(ptheread_key k, const void *)' stores a
615e5dd7070Spatrick // value into thread local storage. The value can later be retrieved with
616e5dd7070Spatrick // 'void *ptheread_getspecific(pthread_key)'. So even thought the
617e5dd7070Spatrick // parameter is 'const void *', the region escapes through the call.
618e5dd7070Spatrick if (II->isStr("pthread_setspecific"))
619e5dd7070Spatrick return true;
620e5dd7070Spatrick
621e5dd7070Spatrick // - xpc_connection_set_context stores a value which can be retrieved later
622e5dd7070Spatrick // with xpc_connection_get_context.
623e5dd7070Spatrick if (II->isStr("xpc_connection_set_context"))
624e5dd7070Spatrick return true;
625e5dd7070Spatrick
626e5dd7070Spatrick // - funopen - sets a buffer for future IO calls.
627e5dd7070Spatrick if (II->isStr("funopen"))
628e5dd7070Spatrick return true;
629e5dd7070Spatrick
630e5dd7070Spatrick // - __cxa_demangle - can reallocate memory and can return the pointer to
631e5dd7070Spatrick // the input buffer.
632e5dd7070Spatrick if (II->isStr("__cxa_demangle"))
633e5dd7070Spatrick return true;
634e5dd7070Spatrick
635e5dd7070Spatrick StringRef FName = II->getName();
636e5dd7070Spatrick
637e5dd7070Spatrick // - CoreFoundation functions that end with "NoCopy" can free a passed-in
638e5dd7070Spatrick // buffer even if it is const.
639e5dd7070Spatrick if (FName.endswith("NoCopy"))
640e5dd7070Spatrick return true;
641e5dd7070Spatrick
642e5dd7070Spatrick // - NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
643e5dd7070Spatrick // be deallocated by NSMapRemove.
644*12c85518Srobert if (FName.startswith("NS") && FName.contains("Insert"))
645e5dd7070Spatrick return true;
646e5dd7070Spatrick
647e5dd7070Spatrick // - Many CF containers allow objects to escape through custom
648e5dd7070Spatrick // allocators/deallocators upon container construction. (PR12101)
649e5dd7070Spatrick if (FName.startswith("CF") || FName.startswith("CG")) {
650e5dd7070Spatrick return StrInStrNoCase(FName, "InsertValue") != StringRef::npos ||
651e5dd7070Spatrick StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
652e5dd7070Spatrick StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
653e5dd7070Spatrick StrInStrNoCase(FName, "WithData") != StringRef::npos ||
654e5dd7070Spatrick StrInStrNoCase(FName, "AppendValue") != StringRef::npos ||
655e5dd7070Spatrick StrInStrNoCase(FName, "SetAttribute") != StringRef::npos;
656e5dd7070Spatrick }
657e5dd7070Spatrick
658e5dd7070Spatrick return false;
659e5dd7070Spatrick }
660e5dd7070Spatrick
getDecl() const661e5dd7070Spatrick const FunctionDecl *SimpleFunctionCall::getDecl() const {
662e5dd7070Spatrick const FunctionDecl *D = getOriginExpr()->getDirectCallee();
663e5dd7070Spatrick if (D)
664e5dd7070Spatrick return D;
665e5dd7070Spatrick
666e5dd7070Spatrick return getSVal(getOriginExpr()->getCallee()).getAsFunctionDecl();
667e5dd7070Spatrick }
668e5dd7070Spatrick
getDecl() const669e5dd7070Spatrick const FunctionDecl *CXXInstanceCall::getDecl() const {
670e5dd7070Spatrick const auto *CE = cast_or_null<CallExpr>(getOriginExpr());
671e5dd7070Spatrick if (!CE)
672e5dd7070Spatrick return AnyFunctionCall::getDecl();
673e5dd7070Spatrick
674e5dd7070Spatrick const FunctionDecl *D = CE->getDirectCallee();
675e5dd7070Spatrick if (D)
676e5dd7070Spatrick return D;
677e5dd7070Spatrick
678e5dd7070Spatrick return getSVal(CE->getCallee()).getAsFunctionDecl();
679e5dd7070Spatrick }
680e5dd7070Spatrick
getExtraInvalidatedValues(ValueList & Values,RegionAndSymbolInvalidationTraits * ETraits) const681e5dd7070Spatrick void CXXInstanceCall::getExtraInvalidatedValues(
682e5dd7070Spatrick ValueList &Values, RegionAndSymbolInvalidationTraits *ETraits) const {
683e5dd7070Spatrick SVal ThisVal = getCXXThisVal();
684e5dd7070Spatrick Values.push_back(ThisVal);
685e5dd7070Spatrick
686e5dd7070Spatrick // Don't invalidate if the method is const and there are no mutable fields.
687e5dd7070Spatrick if (const auto *D = cast_or_null<CXXMethodDecl>(getDecl())) {
688e5dd7070Spatrick if (!D->isConst())
689e5dd7070Spatrick return;
690e5dd7070Spatrick // Get the record decl for the class of 'This'. D->getParent() may return a
691e5dd7070Spatrick // base class decl, rather than the class of the instance which needs to be
692e5dd7070Spatrick // checked for mutable fields.
693e5dd7070Spatrick // TODO: We might as well look at the dynamic type of the object.
694a9ac8606Spatrick const Expr *Ex = getCXXThisExpr()->IgnoreParenBaseCasts();
695e5dd7070Spatrick QualType T = Ex->getType();
696e5dd7070Spatrick if (T->isPointerType()) // Arrow or implicit-this syntax?
697e5dd7070Spatrick T = T->getPointeeType();
698e5dd7070Spatrick const CXXRecordDecl *ParentRecord = T->getAsCXXRecordDecl();
699e5dd7070Spatrick assert(ParentRecord);
700e5dd7070Spatrick if (ParentRecord->hasMutableFields())
701e5dd7070Spatrick return;
702e5dd7070Spatrick // Preserve CXXThis.
703e5dd7070Spatrick const MemRegion *ThisRegion = ThisVal.getAsRegion();
704e5dd7070Spatrick if (!ThisRegion)
705e5dd7070Spatrick return;
706e5dd7070Spatrick
707e5dd7070Spatrick ETraits->setTrait(ThisRegion->getBaseRegion(),
708e5dd7070Spatrick RegionAndSymbolInvalidationTraits::TK_PreserveContents);
709e5dd7070Spatrick }
710e5dd7070Spatrick }
711e5dd7070Spatrick
getCXXThisVal() const712e5dd7070Spatrick SVal CXXInstanceCall::getCXXThisVal() const {
713e5dd7070Spatrick const Expr *Base = getCXXThisExpr();
714e5dd7070Spatrick // FIXME: This doesn't handle an overloaded ->* operator.
715e5dd7070Spatrick if (!Base)
716e5dd7070Spatrick return UnknownVal();
717e5dd7070Spatrick
718e5dd7070Spatrick SVal ThisVal = getSVal(Base);
719*12c85518Srobert assert(ThisVal.isUnknownOrUndef() || isa<Loc>(ThisVal));
720e5dd7070Spatrick return ThisVal;
721e5dd7070Spatrick }
722e5dd7070Spatrick
getRuntimeDefinition() const723e5dd7070Spatrick RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const {
724e5dd7070Spatrick // Do we have a decl at all?
725e5dd7070Spatrick const Decl *D = getDecl();
726e5dd7070Spatrick if (!D)
727e5dd7070Spatrick return {};
728e5dd7070Spatrick
729e5dd7070Spatrick // If the method is non-virtual, we know we can inline it.
730e5dd7070Spatrick const auto *MD = cast<CXXMethodDecl>(D);
731e5dd7070Spatrick if (!MD->isVirtual())
732e5dd7070Spatrick return AnyFunctionCall::getRuntimeDefinition();
733e5dd7070Spatrick
734e5dd7070Spatrick // Do we know the implicit 'this' object being called?
735e5dd7070Spatrick const MemRegion *R = getCXXThisVal().getAsRegion();
736e5dd7070Spatrick if (!R)
737e5dd7070Spatrick return {};
738e5dd7070Spatrick
739e5dd7070Spatrick // Do we know anything about the type of 'this'?
740e5dd7070Spatrick DynamicTypeInfo DynType = getDynamicTypeInfo(getState(), R);
741e5dd7070Spatrick if (!DynType.isValid())
742e5dd7070Spatrick return {};
743e5dd7070Spatrick
744e5dd7070Spatrick // Is the type a C++ class? (This is mostly a defensive check.)
745e5dd7070Spatrick QualType RegionType = DynType.getType()->getPointeeType();
746e5dd7070Spatrick assert(!RegionType.isNull() && "DynamicTypeInfo should always be a pointer.");
747e5dd7070Spatrick
748e5dd7070Spatrick const CXXRecordDecl *RD = RegionType->getAsCXXRecordDecl();
749e5dd7070Spatrick if (!RD || !RD->hasDefinition())
750e5dd7070Spatrick return {};
751e5dd7070Spatrick
752e5dd7070Spatrick // Find the decl for this method in that class.
753e5dd7070Spatrick const CXXMethodDecl *Result = MD->getCorrespondingMethodInClass(RD, true);
754e5dd7070Spatrick if (!Result) {
755e5dd7070Spatrick // We might not even get the original statically-resolved method due to
756e5dd7070Spatrick // some particularly nasty casting (e.g. casts to sister classes).
757e5dd7070Spatrick // However, we should at least be able to search up and down our own class
758e5dd7070Spatrick // hierarchy, and some real bugs have been caught by checking this.
759e5dd7070Spatrick assert(!RD->isDerivedFrom(MD->getParent()) && "Couldn't find known method");
760e5dd7070Spatrick
761e5dd7070Spatrick // FIXME: This is checking that our DynamicTypeInfo is at least as good as
762e5dd7070Spatrick // the static type. However, because we currently don't update
763e5dd7070Spatrick // DynamicTypeInfo when an object is cast, we can't actually be sure the
764e5dd7070Spatrick // DynamicTypeInfo is up to date. This assert should be re-enabled once
765e5dd7070Spatrick // this is fixed. <rdar://problem/12287087>
766e5dd7070Spatrick //assert(!MD->getParent()->isDerivedFrom(RD) && "Bad DynamicTypeInfo");
767e5dd7070Spatrick
768e5dd7070Spatrick return {};
769e5dd7070Spatrick }
770e5dd7070Spatrick
771e5dd7070Spatrick // Does the decl that we found have an implementation?
772e5dd7070Spatrick const FunctionDecl *Definition;
773e5dd7070Spatrick if (!Result->hasBody(Definition)) {
774e5dd7070Spatrick if (!DynType.canBeASubClass())
775e5dd7070Spatrick return AnyFunctionCall::getRuntimeDefinition();
776e5dd7070Spatrick return {};
777e5dd7070Spatrick }
778e5dd7070Spatrick
779e5dd7070Spatrick // We found a definition. If we're not sure that this devirtualization is
780e5dd7070Spatrick // actually what will happen at runtime, make sure to provide the region so
781e5dd7070Spatrick // that ExprEngine can decide what to do with it.
782e5dd7070Spatrick if (DynType.canBeASubClass())
783e5dd7070Spatrick return RuntimeDefinition(Definition, R->StripCasts());
784e5dd7070Spatrick return RuntimeDefinition(Definition, /*DispatchRegion=*/nullptr);
785e5dd7070Spatrick }
786e5dd7070Spatrick
getInitialStackFrameContents(const StackFrameContext * CalleeCtx,BindingsTy & Bindings) const787e5dd7070Spatrick void CXXInstanceCall::getInitialStackFrameContents(
788e5dd7070Spatrick const StackFrameContext *CalleeCtx,
789e5dd7070Spatrick BindingsTy &Bindings) const {
790e5dd7070Spatrick AnyFunctionCall::getInitialStackFrameContents(CalleeCtx, Bindings);
791e5dd7070Spatrick
792e5dd7070Spatrick // Handle the binding of 'this' in the new stack frame.
793e5dd7070Spatrick SVal ThisVal = getCXXThisVal();
794e5dd7070Spatrick if (!ThisVal.isUnknown()) {
795e5dd7070Spatrick ProgramStateManager &StateMgr = getState()->getStateManager();
796e5dd7070Spatrick SValBuilder &SVB = StateMgr.getSValBuilder();
797e5dd7070Spatrick
798e5dd7070Spatrick const auto *MD = cast<CXXMethodDecl>(CalleeCtx->getDecl());
799e5dd7070Spatrick Loc ThisLoc = SVB.getCXXThis(MD, CalleeCtx);
800e5dd7070Spatrick
801e5dd7070Spatrick // If we devirtualized to a different member function, we need to make sure
802e5dd7070Spatrick // we have the proper layering of CXXBaseObjectRegions.
803e5dd7070Spatrick if (MD->getCanonicalDecl() != getDecl()->getCanonicalDecl()) {
804e5dd7070Spatrick ASTContext &Ctx = SVB.getContext();
805e5dd7070Spatrick const CXXRecordDecl *Class = MD->getParent();
806e5dd7070Spatrick QualType Ty = Ctx.getPointerType(Ctx.getRecordType(Class));
807e5dd7070Spatrick
808e5dd7070Spatrick // FIXME: CallEvent maybe shouldn't be directly accessing StoreManager.
809*12c85518Srobert std::optional<SVal> V =
810*12c85518Srobert StateMgr.getStoreManager().evalBaseToDerived(ThisVal, Ty);
811*12c85518Srobert if (!V) {
812e5dd7070Spatrick // We might have suffered some sort of placement new earlier, so
813e5dd7070Spatrick // we're constructing in a completely unexpected storage.
814e5dd7070Spatrick // Fall back to a generic pointer cast for this-value.
815e5dd7070Spatrick const CXXMethodDecl *StaticMD = cast<CXXMethodDecl>(getDecl());
816e5dd7070Spatrick const CXXRecordDecl *StaticClass = StaticMD->getParent();
817e5dd7070Spatrick QualType StaticTy = Ctx.getPointerType(Ctx.getRecordType(StaticClass));
818e5dd7070Spatrick ThisVal = SVB.evalCast(ThisVal, Ty, StaticTy);
819*12c85518Srobert } else
820*12c85518Srobert ThisVal = *V;
821e5dd7070Spatrick }
822e5dd7070Spatrick
823e5dd7070Spatrick if (!ThisVal.isUnknown())
824e5dd7070Spatrick Bindings.push_back(std::make_pair(ThisLoc, ThisVal));
825e5dd7070Spatrick }
826e5dd7070Spatrick }
827e5dd7070Spatrick
getCXXThisExpr() const828e5dd7070Spatrick const Expr *CXXMemberCall::getCXXThisExpr() const {
829e5dd7070Spatrick return getOriginExpr()->getImplicitObjectArgument();
830e5dd7070Spatrick }
831e5dd7070Spatrick
getRuntimeDefinition() const832e5dd7070Spatrick RuntimeDefinition CXXMemberCall::getRuntimeDefinition() const {
833e5dd7070Spatrick // C++11 [expr.call]p1: ...If the selected function is non-virtual, or if the
834e5dd7070Spatrick // id-expression in the class member access expression is a qualified-id,
835e5dd7070Spatrick // that function is called. Otherwise, its final overrider in the dynamic type
836e5dd7070Spatrick // of the object expression is called.
837e5dd7070Spatrick if (const auto *ME = dyn_cast<MemberExpr>(getOriginExpr()->getCallee()))
838e5dd7070Spatrick if (ME->hasQualifier())
839e5dd7070Spatrick return AnyFunctionCall::getRuntimeDefinition();
840e5dd7070Spatrick
841e5dd7070Spatrick return CXXInstanceCall::getRuntimeDefinition();
842e5dd7070Spatrick }
843e5dd7070Spatrick
getCXXThisExpr() const844e5dd7070Spatrick const Expr *CXXMemberOperatorCall::getCXXThisExpr() const {
845e5dd7070Spatrick return getOriginExpr()->getArg(0);
846e5dd7070Spatrick }
847e5dd7070Spatrick
getBlockRegion() const848e5dd7070Spatrick const BlockDataRegion *BlockCall::getBlockRegion() const {
849e5dd7070Spatrick const Expr *Callee = getOriginExpr()->getCallee();
850e5dd7070Spatrick const MemRegion *DataReg = getSVal(Callee).getAsRegion();
851e5dd7070Spatrick
852e5dd7070Spatrick return dyn_cast_or_null<BlockDataRegion>(DataReg);
853e5dd7070Spatrick }
854e5dd7070Spatrick
parameters() const855e5dd7070Spatrick ArrayRef<ParmVarDecl*> BlockCall::parameters() const {
856e5dd7070Spatrick const BlockDecl *D = getDecl();
857e5dd7070Spatrick if (!D)
858*12c85518Srobert return std::nullopt;
859e5dd7070Spatrick return D->parameters();
860e5dd7070Spatrick }
861e5dd7070Spatrick
getExtraInvalidatedValues(ValueList & Values,RegionAndSymbolInvalidationTraits * ETraits) const862e5dd7070Spatrick void BlockCall::getExtraInvalidatedValues(ValueList &Values,
863e5dd7070Spatrick RegionAndSymbolInvalidationTraits *ETraits) const {
864e5dd7070Spatrick // FIXME: This also needs to invalidate captured globals.
865e5dd7070Spatrick if (const MemRegion *R = getBlockRegion())
866e5dd7070Spatrick Values.push_back(loc::MemRegionVal(R));
867e5dd7070Spatrick }
868e5dd7070Spatrick
getInitialStackFrameContents(const StackFrameContext * CalleeCtx,BindingsTy & Bindings) const869e5dd7070Spatrick void BlockCall::getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
870e5dd7070Spatrick BindingsTy &Bindings) const {
871e5dd7070Spatrick SValBuilder &SVB = getState()->getStateManager().getSValBuilder();
872e5dd7070Spatrick ArrayRef<ParmVarDecl*> Params;
873e5dd7070Spatrick if (isConversionFromLambda()) {
874e5dd7070Spatrick auto *LambdaOperatorDecl = cast<CXXMethodDecl>(CalleeCtx->getDecl());
875e5dd7070Spatrick Params = LambdaOperatorDecl->parameters();
876e5dd7070Spatrick
877e5dd7070Spatrick // For blocks converted from a C++ lambda, the callee declaration is the
878e5dd7070Spatrick // operator() method on the lambda so we bind "this" to
879e5dd7070Spatrick // the lambda captured by the block.
880e5dd7070Spatrick const VarRegion *CapturedLambdaRegion = getRegionStoringCapturedLambda();
881e5dd7070Spatrick SVal ThisVal = loc::MemRegionVal(CapturedLambdaRegion);
882e5dd7070Spatrick Loc ThisLoc = SVB.getCXXThis(LambdaOperatorDecl, CalleeCtx);
883e5dd7070Spatrick Bindings.push_back(std::make_pair(ThisLoc, ThisVal));
884e5dd7070Spatrick } else {
885e5dd7070Spatrick Params = cast<BlockDecl>(CalleeCtx->getDecl())->parameters();
886e5dd7070Spatrick }
887e5dd7070Spatrick
888e5dd7070Spatrick addParameterValuesToBindings(CalleeCtx, Bindings, SVB, *this,
889e5dd7070Spatrick Params);
890e5dd7070Spatrick }
891e5dd7070Spatrick
getCXXThisVal() const892ec727ea7Spatrick SVal AnyCXXConstructorCall::getCXXThisVal() const {
893e5dd7070Spatrick if (Data)
894e5dd7070Spatrick return loc::MemRegionVal(static_cast<const MemRegion *>(Data));
895e5dd7070Spatrick return UnknownVal();
896e5dd7070Spatrick }
897e5dd7070Spatrick
getExtraInvalidatedValues(ValueList & Values,RegionAndSymbolInvalidationTraits * ETraits) const898ec727ea7Spatrick void AnyCXXConstructorCall::getExtraInvalidatedValues(ValueList &Values,
899e5dd7070Spatrick RegionAndSymbolInvalidationTraits *ETraits) const {
900ec727ea7Spatrick SVal V = getCXXThisVal();
901ec727ea7Spatrick if (SymbolRef Sym = V.getAsSymbol(true))
902e5dd7070Spatrick ETraits->setTrait(Sym,
903e5dd7070Spatrick RegionAndSymbolInvalidationTraits::TK_SuppressEscape);
904ec727ea7Spatrick Values.push_back(V);
905e5dd7070Spatrick }
906e5dd7070Spatrick
getInitialStackFrameContents(const StackFrameContext * CalleeCtx,BindingsTy & Bindings) const907ec727ea7Spatrick void AnyCXXConstructorCall::getInitialStackFrameContents(
908e5dd7070Spatrick const StackFrameContext *CalleeCtx,
909e5dd7070Spatrick BindingsTy &Bindings) const {
910e5dd7070Spatrick AnyFunctionCall::getInitialStackFrameContents(CalleeCtx, Bindings);
911e5dd7070Spatrick
912e5dd7070Spatrick SVal ThisVal = getCXXThisVal();
913e5dd7070Spatrick if (!ThisVal.isUnknown()) {
914e5dd7070Spatrick SValBuilder &SVB = getState()->getStateManager().getSValBuilder();
915e5dd7070Spatrick const auto *MD = cast<CXXMethodDecl>(CalleeCtx->getDecl());
916e5dd7070Spatrick Loc ThisLoc = SVB.getCXXThis(MD, CalleeCtx);
917e5dd7070Spatrick Bindings.push_back(std::make_pair(ThisLoc, ThisVal));
918e5dd7070Spatrick }
919e5dd7070Spatrick }
920e5dd7070Spatrick
921ec727ea7Spatrick const StackFrameContext *
getInheritingStackFrame() const922ec727ea7Spatrick CXXInheritedConstructorCall::getInheritingStackFrame() const {
923ec727ea7Spatrick const StackFrameContext *SFC = getLocationContext()->getStackFrame();
924ec727ea7Spatrick while (isa<CXXInheritedCtorInitExpr>(SFC->getCallSite()))
925ec727ea7Spatrick SFC = SFC->getParent()->getStackFrame();
926ec727ea7Spatrick return SFC;
927ec727ea7Spatrick }
928ec727ea7Spatrick
getCXXThisVal() const929e5dd7070Spatrick SVal CXXDestructorCall::getCXXThisVal() const {
930e5dd7070Spatrick if (Data)
931e5dd7070Spatrick return loc::MemRegionVal(DtorDataTy::getFromOpaqueValue(Data).getPointer());
932e5dd7070Spatrick return UnknownVal();
933e5dd7070Spatrick }
934e5dd7070Spatrick
getRuntimeDefinition() const935e5dd7070Spatrick RuntimeDefinition CXXDestructorCall::getRuntimeDefinition() const {
936e5dd7070Spatrick // Base destructors are always called non-virtually.
937e5dd7070Spatrick // Skip CXXInstanceCall's devirtualization logic in this case.
938e5dd7070Spatrick if (isBaseDestructor())
939e5dd7070Spatrick return AnyFunctionCall::getRuntimeDefinition();
940e5dd7070Spatrick
941e5dd7070Spatrick return CXXInstanceCall::getRuntimeDefinition();
942e5dd7070Spatrick }
943e5dd7070Spatrick
parameters() const944e5dd7070Spatrick ArrayRef<ParmVarDecl*> ObjCMethodCall::parameters() const {
945e5dd7070Spatrick const ObjCMethodDecl *D = getDecl();
946e5dd7070Spatrick if (!D)
947*12c85518Srobert return std::nullopt;
948e5dd7070Spatrick return D->parameters();
949e5dd7070Spatrick }
950e5dd7070Spatrick
getExtraInvalidatedValues(ValueList & Values,RegionAndSymbolInvalidationTraits * ETraits) const951e5dd7070Spatrick void ObjCMethodCall::getExtraInvalidatedValues(
952e5dd7070Spatrick ValueList &Values, RegionAndSymbolInvalidationTraits *ETraits) const {
953e5dd7070Spatrick
954e5dd7070Spatrick // If the method call is a setter for property known to be backed by
955e5dd7070Spatrick // an instance variable, don't invalidate the entire receiver, just
956e5dd7070Spatrick // the storage for that instance variable.
957e5dd7070Spatrick if (const ObjCPropertyDecl *PropDecl = getAccessedProperty()) {
958e5dd7070Spatrick if (const ObjCIvarDecl *PropIvar = PropDecl->getPropertyIvarDecl()) {
959e5dd7070Spatrick SVal IvarLVal = getState()->getLValue(PropIvar, getReceiverSVal());
960e5dd7070Spatrick if (const MemRegion *IvarRegion = IvarLVal.getAsRegion()) {
961e5dd7070Spatrick ETraits->setTrait(
962e5dd7070Spatrick IvarRegion,
963e5dd7070Spatrick RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion);
964e5dd7070Spatrick ETraits->setTrait(
965e5dd7070Spatrick IvarRegion,
966e5dd7070Spatrick RegionAndSymbolInvalidationTraits::TK_SuppressEscape);
967e5dd7070Spatrick Values.push_back(IvarLVal);
968e5dd7070Spatrick }
969e5dd7070Spatrick return;
970e5dd7070Spatrick }
971e5dd7070Spatrick }
972e5dd7070Spatrick
973e5dd7070Spatrick Values.push_back(getReceiverSVal());
974e5dd7070Spatrick }
975e5dd7070Spatrick
getReceiverSVal() const976e5dd7070Spatrick SVal ObjCMethodCall::getReceiverSVal() const {
977e5dd7070Spatrick // FIXME: Is this the best way to handle class receivers?
978e5dd7070Spatrick if (!isInstanceMessage())
979e5dd7070Spatrick return UnknownVal();
980e5dd7070Spatrick
981e5dd7070Spatrick if (const Expr *RecE = getOriginExpr()->getInstanceReceiver())
982e5dd7070Spatrick return getSVal(RecE);
983e5dd7070Spatrick
984e5dd7070Spatrick // An instance message with no expression means we are sending to super.
985e5dd7070Spatrick // In this case the object reference is the same as 'self'.
986e5dd7070Spatrick assert(getOriginExpr()->getReceiverKind() == ObjCMessageExpr::SuperInstance);
987ec727ea7Spatrick SVal SelfVal = getState()->getSelfSVal(getLocationContext());
988e5dd7070Spatrick assert(SelfVal.isValid() && "Calling super but not in ObjC method");
989e5dd7070Spatrick return SelfVal;
990e5dd7070Spatrick }
991e5dd7070Spatrick
isReceiverSelfOrSuper() const992e5dd7070Spatrick bool ObjCMethodCall::isReceiverSelfOrSuper() const {
993e5dd7070Spatrick if (getOriginExpr()->getReceiverKind() == ObjCMessageExpr::SuperInstance ||
994e5dd7070Spatrick getOriginExpr()->getReceiverKind() == ObjCMessageExpr::SuperClass)
995e5dd7070Spatrick return true;
996e5dd7070Spatrick
997e5dd7070Spatrick if (!isInstanceMessage())
998e5dd7070Spatrick return false;
999e5dd7070Spatrick
1000e5dd7070Spatrick SVal RecVal = getSVal(getOriginExpr()->getInstanceReceiver());
1001ec727ea7Spatrick SVal SelfVal = getState()->getSelfSVal(getLocationContext());
1002e5dd7070Spatrick
1003ec727ea7Spatrick return (RecVal == SelfVal);
1004e5dd7070Spatrick }
1005e5dd7070Spatrick
getSourceRange() const1006e5dd7070Spatrick SourceRange ObjCMethodCall::getSourceRange() const {
1007e5dd7070Spatrick switch (getMessageKind()) {
1008e5dd7070Spatrick case OCM_Message:
1009e5dd7070Spatrick return getOriginExpr()->getSourceRange();
1010e5dd7070Spatrick case OCM_PropertyAccess:
1011e5dd7070Spatrick case OCM_Subscript:
1012e5dd7070Spatrick return getContainingPseudoObjectExpr()->getSourceRange();
1013e5dd7070Spatrick }
1014e5dd7070Spatrick llvm_unreachable("unknown message kind");
1015e5dd7070Spatrick }
1016e5dd7070Spatrick
1017e5dd7070Spatrick using ObjCMessageDataTy = llvm::PointerIntPair<const PseudoObjectExpr *, 2>;
1018e5dd7070Spatrick
getContainingPseudoObjectExpr() const1019e5dd7070Spatrick const PseudoObjectExpr *ObjCMethodCall::getContainingPseudoObjectExpr() const {
1020e5dd7070Spatrick assert(Data && "Lazy lookup not yet performed.");
1021e5dd7070Spatrick assert(getMessageKind() != OCM_Message && "Explicit message send.");
1022e5dd7070Spatrick return ObjCMessageDataTy::getFromOpaqueValue(Data).getPointer();
1023e5dd7070Spatrick }
1024e5dd7070Spatrick
1025e5dd7070Spatrick static const Expr *
getSyntacticFromForPseudoObjectExpr(const PseudoObjectExpr * POE)1026e5dd7070Spatrick getSyntacticFromForPseudoObjectExpr(const PseudoObjectExpr *POE) {
1027*12c85518Srobert const Expr *Syntactic = POE->getSyntacticForm()->IgnoreParens();
1028e5dd7070Spatrick
1029e5dd7070Spatrick // This handles the funny case of assigning to the result of a getter.
1030e5dd7070Spatrick // This can happen if the getter returns a non-const reference.
1031e5dd7070Spatrick if (const auto *BO = dyn_cast<BinaryOperator>(Syntactic))
1032*12c85518Srobert Syntactic = BO->getLHS()->IgnoreParens();
1033e5dd7070Spatrick
1034e5dd7070Spatrick return Syntactic;
1035e5dd7070Spatrick }
1036e5dd7070Spatrick
getMessageKind() const1037e5dd7070Spatrick ObjCMessageKind ObjCMethodCall::getMessageKind() const {
1038e5dd7070Spatrick if (!Data) {
1039e5dd7070Spatrick // Find the parent, ignoring implicit casts.
1040e5dd7070Spatrick const ParentMap &PM = getLocationContext()->getParentMap();
1041e5dd7070Spatrick const Stmt *S = PM.getParentIgnoreParenCasts(getOriginExpr());
1042e5dd7070Spatrick
1043e5dd7070Spatrick // Check if parent is a PseudoObjectExpr.
1044e5dd7070Spatrick if (const auto *POE = dyn_cast_or_null<PseudoObjectExpr>(S)) {
1045e5dd7070Spatrick const Expr *Syntactic = getSyntacticFromForPseudoObjectExpr(POE);
1046e5dd7070Spatrick
1047e5dd7070Spatrick ObjCMessageKind K;
1048e5dd7070Spatrick switch (Syntactic->getStmtClass()) {
1049e5dd7070Spatrick case Stmt::ObjCPropertyRefExprClass:
1050e5dd7070Spatrick K = OCM_PropertyAccess;
1051e5dd7070Spatrick break;
1052e5dd7070Spatrick case Stmt::ObjCSubscriptRefExprClass:
1053e5dd7070Spatrick K = OCM_Subscript;
1054e5dd7070Spatrick break;
1055e5dd7070Spatrick default:
1056e5dd7070Spatrick // FIXME: Can this ever happen?
1057e5dd7070Spatrick K = OCM_Message;
1058e5dd7070Spatrick break;
1059e5dd7070Spatrick }
1060e5dd7070Spatrick
1061e5dd7070Spatrick if (K != OCM_Message) {
1062e5dd7070Spatrick const_cast<ObjCMethodCall *>(this)->Data
1063e5dd7070Spatrick = ObjCMessageDataTy(POE, K).getOpaqueValue();
1064e5dd7070Spatrick assert(getMessageKind() == K);
1065e5dd7070Spatrick return K;
1066e5dd7070Spatrick }
1067e5dd7070Spatrick }
1068e5dd7070Spatrick
1069e5dd7070Spatrick const_cast<ObjCMethodCall *>(this)->Data
1070e5dd7070Spatrick = ObjCMessageDataTy(nullptr, 1).getOpaqueValue();
1071e5dd7070Spatrick assert(getMessageKind() == OCM_Message);
1072e5dd7070Spatrick return OCM_Message;
1073e5dd7070Spatrick }
1074e5dd7070Spatrick
1075e5dd7070Spatrick ObjCMessageDataTy Info = ObjCMessageDataTy::getFromOpaqueValue(Data);
1076e5dd7070Spatrick if (!Info.getPointer())
1077e5dd7070Spatrick return OCM_Message;
1078e5dd7070Spatrick return static_cast<ObjCMessageKind>(Info.getInt());
1079e5dd7070Spatrick }
1080e5dd7070Spatrick
getAccessedProperty() const1081e5dd7070Spatrick const ObjCPropertyDecl *ObjCMethodCall::getAccessedProperty() const {
1082e5dd7070Spatrick // Look for properties accessed with property syntax (foo.bar = ...)
1083e5dd7070Spatrick if (getMessageKind() == OCM_PropertyAccess) {
1084e5dd7070Spatrick const PseudoObjectExpr *POE = getContainingPseudoObjectExpr();
1085e5dd7070Spatrick assert(POE && "Property access without PseudoObjectExpr?");
1086e5dd7070Spatrick
1087e5dd7070Spatrick const Expr *Syntactic = getSyntacticFromForPseudoObjectExpr(POE);
1088e5dd7070Spatrick auto *RefExpr = cast<ObjCPropertyRefExpr>(Syntactic);
1089e5dd7070Spatrick
1090e5dd7070Spatrick if (RefExpr->isExplicitProperty())
1091e5dd7070Spatrick return RefExpr->getExplicitProperty();
1092e5dd7070Spatrick }
1093e5dd7070Spatrick
1094e5dd7070Spatrick // Look for properties accessed with method syntax ([foo setBar:...]).
1095e5dd7070Spatrick const ObjCMethodDecl *MD = getDecl();
1096e5dd7070Spatrick if (!MD || !MD->isPropertyAccessor())
1097e5dd7070Spatrick return nullptr;
1098e5dd7070Spatrick
1099e5dd7070Spatrick // Note: This is potentially quite slow.
1100e5dd7070Spatrick return MD->findPropertyDecl();
1101e5dd7070Spatrick }
1102e5dd7070Spatrick
canBeOverridenInSubclass(ObjCInterfaceDecl * IDecl,Selector Sel) const1103e5dd7070Spatrick bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl,
1104e5dd7070Spatrick Selector Sel) const {
1105e5dd7070Spatrick assert(IDecl);
1106e5dd7070Spatrick AnalysisManager &AMgr =
1107e5dd7070Spatrick getState()->getStateManager().getOwningEngine().getAnalysisManager();
1108e5dd7070Spatrick // If the class interface is declared inside the main file, assume it is not
1109e5dd7070Spatrick // subcassed.
1110e5dd7070Spatrick // TODO: It could actually be subclassed if the subclass is private as well.
1111e5dd7070Spatrick // This is probably very rare.
1112e5dd7070Spatrick SourceLocation InterfLoc = IDecl->getEndOfDefinitionLoc();
1113e5dd7070Spatrick if (InterfLoc.isValid() && AMgr.isInCodeFile(InterfLoc))
1114e5dd7070Spatrick return false;
1115e5dd7070Spatrick
1116e5dd7070Spatrick // Assume that property accessors are not overridden.
1117e5dd7070Spatrick if (getMessageKind() == OCM_PropertyAccess)
1118e5dd7070Spatrick return false;
1119e5dd7070Spatrick
1120e5dd7070Spatrick // We assume that if the method is public (declared outside of main file) or
1121e5dd7070Spatrick // has a parent which publicly declares the method, the method could be
1122e5dd7070Spatrick // overridden in a subclass.
1123e5dd7070Spatrick
1124e5dd7070Spatrick // Find the first declaration in the class hierarchy that declares
1125e5dd7070Spatrick // the selector.
1126e5dd7070Spatrick ObjCMethodDecl *D = nullptr;
1127e5dd7070Spatrick while (true) {
1128e5dd7070Spatrick D = IDecl->lookupMethod(Sel, true);
1129e5dd7070Spatrick
1130e5dd7070Spatrick // Cannot find a public definition.
1131e5dd7070Spatrick if (!D)
1132e5dd7070Spatrick return false;
1133e5dd7070Spatrick
1134e5dd7070Spatrick // If outside the main file,
1135e5dd7070Spatrick if (D->getLocation().isValid() && !AMgr.isInCodeFile(D->getLocation()))
1136e5dd7070Spatrick return true;
1137e5dd7070Spatrick
1138e5dd7070Spatrick if (D->isOverriding()) {
1139e5dd7070Spatrick // Search in the superclass on the next iteration.
1140e5dd7070Spatrick IDecl = D->getClassInterface();
1141e5dd7070Spatrick if (!IDecl)
1142e5dd7070Spatrick return false;
1143e5dd7070Spatrick
1144e5dd7070Spatrick IDecl = IDecl->getSuperClass();
1145e5dd7070Spatrick if (!IDecl)
1146e5dd7070Spatrick return false;
1147e5dd7070Spatrick
1148e5dd7070Spatrick continue;
1149e5dd7070Spatrick }
1150e5dd7070Spatrick
1151e5dd7070Spatrick return false;
1152e5dd7070Spatrick };
1153e5dd7070Spatrick
1154e5dd7070Spatrick llvm_unreachable("The while loop should always terminate.");
1155e5dd7070Spatrick }
1156e5dd7070Spatrick
findDefiningRedecl(const ObjCMethodDecl * MD)1157e5dd7070Spatrick static const ObjCMethodDecl *findDefiningRedecl(const ObjCMethodDecl *MD) {
1158e5dd7070Spatrick if (!MD)
1159e5dd7070Spatrick return MD;
1160e5dd7070Spatrick
1161e5dd7070Spatrick // Find the redeclaration that defines the method.
1162e5dd7070Spatrick if (!MD->hasBody()) {
1163*12c85518Srobert for (auto *I : MD->redecls())
1164e5dd7070Spatrick if (I->hasBody())
1165e5dd7070Spatrick MD = cast<ObjCMethodDecl>(I);
1166e5dd7070Spatrick }
1167e5dd7070Spatrick return MD;
1168e5dd7070Spatrick }
1169e5dd7070Spatrick
1170ec727ea7Spatrick struct PrivateMethodKey {
1171ec727ea7Spatrick const ObjCInterfaceDecl *Interface;
1172ec727ea7Spatrick Selector LookupSelector;
1173ec727ea7Spatrick bool IsClassMethod;
1174ec727ea7Spatrick };
1175e5dd7070Spatrick
1176ec727ea7Spatrick namespace llvm {
1177ec727ea7Spatrick template <> struct DenseMapInfo<PrivateMethodKey> {
1178ec727ea7Spatrick using InterfaceInfo = DenseMapInfo<const ObjCInterfaceDecl *>;
1179ec727ea7Spatrick using SelectorInfo = DenseMapInfo<Selector>;
1180e5dd7070Spatrick
getEmptyKeyllvm::DenseMapInfo1181ec727ea7Spatrick static inline PrivateMethodKey getEmptyKey() {
1182ec727ea7Spatrick return {InterfaceInfo::getEmptyKey(), SelectorInfo::getEmptyKey(), false};
1183e5dd7070Spatrick }
1184e5dd7070Spatrick
getTombstoneKeyllvm::DenseMapInfo1185ec727ea7Spatrick static inline PrivateMethodKey getTombstoneKey() {
1186ec727ea7Spatrick return {InterfaceInfo::getTombstoneKey(), SelectorInfo::getTombstoneKey(),
1187ec727ea7Spatrick true};
1188e5dd7070Spatrick }
1189e5dd7070Spatrick
getHashValuellvm::DenseMapInfo1190ec727ea7Spatrick static unsigned getHashValue(const PrivateMethodKey &Key) {
1191ec727ea7Spatrick return llvm::hash_combine(
1192ec727ea7Spatrick llvm::hash_code(InterfaceInfo::getHashValue(Key.Interface)),
1193ec727ea7Spatrick llvm::hash_code(SelectorInfo::getHashValue(Key.LookupSelector)),
1194ec727ea7Spatrick Key.IsClassMethod);
1195e5dd7070Spatrick }
1196e5dd7070Spatrick
isEqualllvm::DenseMapInfo1197ec727ea7Spatrick static bool isEqual(const PrivateMethodKey &LHS,
1198ec727ea7Spatrick const PrivateMethodKey &RHS) {
1199ec727ea7Spatrick return InterfaceInfo::isEqual(LHS.Interface, RHS.Interface) &&
1200ec727ea7Spatrick SelectorInfo::isEqual(LHS.LookupSelector, RHS.LookupSelector) &&
1201ec727ea7Spatrick LHS.IsClassMethod == RHS.IsClassMethod;
1202e5dd7070Spatrick }
1203ec727ea7Spatrick };
1204ec727ea7Spatrick } // end namespace llvm
1205e5dd7070Spatrick
1206ec727ea7Spatrick static const ObjCMethodDecl *
lookupRuntimeDefinition(const ObjCInterfaceDecl * Interface,Selector LookupSelector,bool InstanceMethod)1207ec727ea7Spatrick lookupRuntimeDefinition(const ObjCInterfaceDecl *Interface,
1208ec727ea7Spatrick Selector LookupSelector, bool InstanceMethod) {
1209e5dd7070Spatrick // Repeatedly calling lookupPrivateMethod() is expensive, especially
1210e5dd7070Spatrick // when in many cases it returns null. We cache the results so
1211e5dd7070Spatrick // that repeated queries on the same ObjCIntefaceDecl and Selector
1212e5dd7070Spatrick // don't incur the same cost. On some test cases, we can see the
1213e5dd7070Spatrick // same query being issued thousands of times.
1214e5dd7070Spatrick //
1215e5dd7070Spatrick // NOTE: This cache is essentially a "global" variable, but it
1216e5dd7070Spatrick // only gets lazily created when we get here. The value of the
1217e5dd7070Spatrick // cache probably comes from it being global across ExprEngines,
1218e5dd7070Spatrick // where the same queries may get issued. If we are worried about
1219e5dd7070Spatrick // concurrency, or possibly loading/unloading ASTs, etc., we may
1220e5dd7070Spatrick // need to revisit this someday. In terms of memory, this table
1221e5dd7070Spatrick // stays around until clang quits, which also may be bad if we
1222e5dd7070Spatrick // need to release memory.
1223e5dd7070Spatrick using PrivateMethodCache =
1224*12c85518Srobert llvm::DenseMap<PrivateMethodKey, std::optional<const ObjCMethodDecl *>>;
1225e5dd7070Spatrick
1226e5dd7070Spatrick static PrivateMethodCache PMC;
1227*12c85518Srobert std::optional<const ObjCMethodDecl *> &Val =
1228ec727ea7Spatrick PMC[{Interface, LookupSelector, InstanceMethod}];
1229e5dd7070Spatrick
1230e5dd7070Spatrick // Query lookupPrivateMethod() if the cache does not hit.
1231*12c85518Srobert if (!Val) {
1232ec727ea7Spatrick Val = Interface->lookupPrivateMethod(LookupSelector, InstanceMethod);
1233e5dd7070Spatrick
1234ec727ea7Spatrick if (!*Val) {
1235ec727ea7Spatrick // Query 'lookupMethod' as a backup.
1236ec727ea7Spatrick Val = Interface->lookupMethod(LookupSelector, InstanceMethod);
1237e5dd7070Spatrick }
1238e5dd7070Spatrick }
1239e5dd7070Spatrick
1240*12c85518Srobert return *Val;
1241ec727ea7Spatrick }
1242ec727ea7Spatrick
getRuntimeDefinition() const1243ec727ea7Spatrick RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
1244ec727ea7Spatrick const ObjCMessageExpr *E = getOriginExpr();
1245ec727ea7Spatrick assert(E);
1246ec727ea7Spatrick Selector Sel = E->getSelector();
1247ec727ea7Spatrick
1248ec727ea7Spatrick if (E->isInstanceMessage()) {
1249ec727ea7Spatrick // Find the receiver type.
1250ec727ea7Spatrick const ObjCObjectType *ReceiverT = nullptr;
1251ec727ea7Spatrick bool CanBeSubClassed = false;
1252ec727ea7Spatrick bool LookingForInstanceMethod = true;
1253ec727ea7Spatrick QualType SupersType = E->getSuperType();
1254ec727ea7Spatrick const MemRegion *Receiver = nullptr;
1255ec727ea7Spatrick
1256ec727ea7Spatrick if (!SupersType.isNull()) {
1257ec727ea7Spatrick // The receiver is guaranteed to be 'super' in this case.
1258ec727ea7Spatrick // Super always means the type of immediate predecessor to the method
1259ec727ea7Spatrick // where the call occurs.
1260ec727ea7Spatrick ReceiverT = cast<ObjCObjectPointerType>(SupersType)->getObjectType();
1261ec727ea7Spatrick } else {
1262ec727ea7Spatrick Receiver = getReceiverSVal().getAsRegion();
1263ec727ea7Spatrick if (!Receiver)
1264ec727ea7Spatrick return {};
1265ec727ea7Spatrick
1266ec727ea7Spatrick DynamicTypeInfo DTI = getDynamicTypeInfo(getState(), Receiver);
1267ec727ea7Spatrick if (!DTI.isValid()) {
1268ec727ea7Spatrick assert(isa<AllocaRegion>(Receiver) &&
1269ec727ea7Spatrick "Unhandled untyped region class!");
1270ec727ea7Spatrick return {};
1271ec727ea7Spatrick }
1272ec727ea7Spatrick
1273ec727ea7Spatrick QualType DynType = DTI.getType();
1274ec727ea7Spatrick CanBeSubClassed = DTI.canBeASubClass();
1275ec727ea7Spatrick
1276ec727ea7Spatrick const auto *ReceiverDynT =
1277ec727ea7Spatrick dyn_cast<ObjCObjectPointerType>(DynType.getCanonicalType());
1278ec727ea7Spatrick
1279ec727ea7Spatrick if (ReceiverDynT) {
1280ec727ea7Spatrick ReceiverT = ReceiverDynT->getObjectType();
1281ec727ea7Spatrick
1282ec727ea7Spatrick // It can be actually class methods called with Class object as a
1283ec727ea7Spatrick // receiver. This type of messages is treated by the compiler as
1284ec727ea7Spatrick // instance (not class).
1285ec727ea7Spatrick if (ReceiverT->isObjCClass()) {
1286ec727ea7Spatrick
1287ec727ea7Spatrick SVal SelfVal = getState()->getSelfSVal(getLocationContext());
1288ec727ea7Spatrick // For [self classMethod], return compiler visible declaration.
1289ec727ea7Spatrick if (Receiver == SelfVal.getAsRegion()) {
1290ec727ea7Spatrick return RuntimeDefinition(findDefiningRedecl(E->getMethodDecl()));
1291ec727ea7Spatrick }
1292ec727ea7Spatrick
1293ec727ea7Spatrick // Otherwise, let's check if we know something about the type
1294ec727ea7Spatrick // inside of this class object.
1295ec727ea7Spatrick if (SymbolRef ReceiverSym = getReceiverSVal().getAsSymbol()) {
1296ec727ea7Spatrick DynamicTypeInfo DTI =
1297ec727ea7Spatrick getClassObjectDynamicTypeInfo(getState(), ReceiverSym);
1298ec727ea7Spatrick if (DTI.isValid()) {
1299ec727ea7Spatrick // Let's use this type for lookup.
1300ec727ea7Spatrick ReceiverT =
1301ec727ea7Spatrick cast<ObjCObjectType>(DTI.getType().getCanonicalType());
1302ec727ea7Spatrick
1303ec727ea7Spatrick CanBeSubClassed = DTI.canBeASubClass();
1304ec727ea7Spatrick // And it should be a class method instead.
1305ec727ea7Spatrick LookingForInstanceMethod = false;
1306ec727ea7Spatrick }
1307ec727ea7Spatrick }
1308ec727ea7Spatrick }
1309ec727ea7Spatrick
1310ec727ea7Spatrick if (CanBeSubClassed)
1311ec727ea7Spatrick if (ObjCInterfaceDecl *IDecl = ReceiverT->getInterface())
1312ec727ea7Spatrick // Even if `DynamicTypeInfo` told us that it can be
1313ec727ea7Spatrick // not necessarily this type, but its descendants, we still want
1314ec727ea7Spatrick // to check again if this selector can be actually overridden.
1315ec727ea7Spatrick CanBeSubClassed = canBeOverridenInSubclass(IDecl, Sel);
1316ec727ea7Spatrick }
1317ec727ea7Spatrick }
1318ec727ea7Spatrick
1319ec727ea7Spatrick // Lookup the instance method implementation.
1320ec727ea7Spatrick if (ReceiverT)
1321ec727ea7Spatrick if (ObjCInterfaceDecl *IDecl = ReceiverT->getInterface()) {
1322ec727ea7Spatrick const ObjCMethodDecl *MD =
1323ec727ea7Spatrick lookupRuntimeDefinition(IDecl, Sel, LookingForInstanceMethod);
1324ec727ea7Spatrick
1325e5dd7070Spatrick if (MD && !MD->hasBody())
1326e5dd7070Spatrick MD = MD->getCanonicalDecl();
1327ec727ea7Spatrick
1328e5dd7070Spatrick if (CanBeSubClassed)
1329e5dd7070Spatrick return RuntimeDefinition(MD, Receiver);
1330e5dd7070Spatrick else
1331e5dd7070Spatrick return RuntimeDefinition(MD, nullptr);
1332e5dd7070Spatrick }
1333e5dd7070Spatrick } else {
1334e5dd7070Spatrick // This is a class method.
1335e5dd7070Spatrick // If we have type info for the receiver class, we are calling via
1336e5dd7070Spatrick // class name.
1337e5dd7070Spatrick if (ObjCInterfaceDecl *IDecl = E->getReceiverInterface()) {
1338e5dd7070Spatrick // Find/Return the method implementation.
1339e5dd7070Spatrick return RuntimeDefinition(IDecl->lookupPrivateClassMethod(Sel));
1340e5dd7070Spatrick }
1341e5dd7070Spatrick }
1342e5dd7070Spatrick
1343e5dd7070Spatrick return {};
1344e5dd7070Spatrick }
1345e5dd7070Spatrick
argumentsMayEscape() const1346e5dd7070Spatrick bool ObjCMethodCall::argumentsMayEscape() const {
1347e5dd7070Spatrick if (isInSystemHeader() && !isInstanceMessage()) {
1348e5dd7070Spatrick Selector Sel = getSelector();
1349e5dd7070Spatrick if (Sel.getNumArgs() == 1 &&
1350e5dd7070Spatrick Sel.getIdentifierInfoForSlot(0)->isStr("valueWithPointer"))
1351e5dd7070Spatrick return true;
1352e5dd7070Spatrick }
1353e5dd7070Spatrick
1354e5dd7070Spatrick return CallEvent::argumentsMayEscape();
1355e5dd7070Spatrick }
1356e5dd7070Spatrick
getInitialStackFrameContents(const StackFrameContext * CalleeCtx,BindingsTy & Bindings) const1357e5dd7070Spatrick void ObjCMethodCall::getInitialStackFrameContents(
1358e5dd7070Spatrick const StackFrameContext *CalleeCtx,
1359e5dd7070Spatrick BindingsTy &Bindings) const {
1360e5dd7070Spatrick const auto *D = cast<ObjCMethodDecl>(CalleeCtx->getDecl());
1361e5dd7070Spatrick SValBuilder &SVB = getState()->getStateManager().getSValBuilder();
1362e5dd7070Spatrick addParameterValuesToBindings(CalleeCtx, Bindings, SVB, *this,
1363e5dd7070Spatrick D->parameters());
1364e5dd7070Spatrick
1365e5dd7070Spatrick SVal SelfVal = getReceiverSVal();
1366e5dd7070Spatrick if (!SelfVal.isUnknown()) {
1367e5dd7070Spatrick const VarDecl *SelfD = CalleeCtx->getAnalysisDeclContext()->getSelfDecl();
1368e5dd7070Spatrick MemRegionManager &MRMgr = SVB.getRegionManager();
1369e5dd7070Spatrick Loc SelfLoc = SVB.makeLoc(MRMgr.getVarRegion(SelfD, CalleeCtx));
1370e5dd7070Spatrick Bindings.push_back(std::make_pair(SelfLoc, SelfVal));
1371e5dd7070Spatrick }
1372e5dd7070Spatrick }
1373e5dd7070Spatrick
1374e5dd7070Spatrick CallEventRef<>
getSimpleCall(const CallExpr * CE,ProgramStateRef State,const LocationContext * LCtx)1375e5dd7070Spatrick CallEventManager::getSimpleCall(const CallExpr *CE, ProgramStateRef State,
1376e5dd7070Spatrick const LocationContext *LCtx) {
1377e5dd7070Spatrick if (const auto *MCE = dyn_cast<CXXMemberCallExpr>(CE))
1378e5dd7070Spatrick return create<CXXMemberCall>(MCE, State, LCtx);
1379e5dd7070Spatrick
1380e5dd7070Spatrick if (const auto *OpCE = dyn_cast<CXXOperatorCallExpr>(CE)) {
1381e5dd7070Spatrick const FunctionDecl *DirectCallee = OpCE->getDirectCallee();
1382e5dd7070Spatrick if (const auto *MD = dyn_cast<CXXMethodDecl>(DirectCallee))
1383e5dd7070Spatrick if (MD->isInstance())
1384e5dd7070Spatrick return create<CXXMemberOperatorCall>(OpCE, State, LCtx);
1385e5dd7070Spatrick
1386e5dd7070Spatrick } else if (CE->getCallee()->getType()->isBlockPointerType()) {
1387e5dd7070Spatrick return create<BlockCall>(CE, State, LCtx);
1388e5dd7070Spatrick }
1389e5dd7070Spatrick
1390e5dd7070Spatrick // Otherwise, it's a normal function call, static member function call, or
1391e5dd7070Spatrick // something we can't reason about.
1392e5dd7070Spatrick return create<SimpleFunctionCall>(CE, State, LCtx);
1393e5dd7070Spatrick }
1394e5dd7070Spatrick
1395e5dd7070Spatrick CallEventRef<>
getCaller(const StackFrameContext * CalleeCtx,ProgramStateRef State)1396e5dd7070Spatrick CallEventManager::getCaller(const StackFrameContext *CalleeCtx,
1397e5dd7070Spatrick ProgramStateRef State) {
1398e5dd7070Spatrick const LocationContext *ParentCtx = CalleeCtx->getParent();
1399e5dd7070Spatrick const LocationContext *CallerCtx = ParentCtx->getStackFrame();
1400e5dd7070Spatrick assert(CallerCtx && "This should not be used for top-level stack frames");
1401e5dd7070Spatrick
1402e5dd7070Spatrick const Stmt *CallSite = CalleeCtx->getCallSite();
1403e5dd7070Spatrick
1404e5dd7070Spatrick if (CallSite) {
1405e5dd7070Spatrick if (CallEventRef<> Out = getCall(CallSite, State, CallerCtx))
1406e5dd7070Spatrick return Out;
1407e5dd7070Spatrick
1408e5dd7070Spatrick SValBuilder &SVB = State->getStateManager().getSValBuilder();
1409e5dd7070Spatrick const auto *Ctor = cast<CXXMethodDecl>(CalleeCtx->getDecl());
1410e5dd7070Spatrick Loc ThisPtr = SVB.getCXXThis(Ctor, CalleeCtx);
1411e5dd7070Spatrick SVal ThisVal = State->getSVal(ThisPtr);
1412e5dd7070Spatrick
1413ec727ea7Spatrick if (const auto *CE = dyn_cast<CXXConstructExpr>(CallSite))
1414ec727ea7Spatrick return getCXXConstructorCall(CE, ThisVal.getAsRegion(), State, CallerCtx);
1415ec727ea7Spatrick else if (const auto *CIE = dyn_cast<CXXInheritedCtorInitExpr>(CallSite))
1416ec727ea7Spatrick return getCXXInheritedConstructorCall(CIE, ThisVal.getAsRegion(), State,
1417ec727ea7Spatrick CallerCtx);
1418ec727ea7Spatrick else {
1419ec727ea7Spatrick // All other cases are handled by getCall.
1420ec727ea7Spatrick llvm_unreachable("This is not an inlineable statement");
1421ec727ea7Spatrick }
1422e5dd7070Spatrick }
1423e5dd7070Spatrick
1424e5dd7070Spatrick // Fall back to the CFG. The only thing we haven't handled yet is
1425e5dd7070Spatrick // destructors, though this could change in the future.
1426e5dd7070Spatrick const CFGBlock *B = CalleeCtx->getCallSiteBlock();
1427e5dd7070Spatrick CFGElement E = (*B)[CalleeCtx->getIndex()];
1428e5dd7070Spatrick assert((E.getAs<CFGImplicitDtor>() || E.getAs<CFGTemporaryDtor>()) &&
1429e5dd7070Spatrick "All other CFG elements should have exprs");
1430e5dd7070Spatrick
1431e5dd7070Spatrick SValBuilder &SVB = State->getStateManager().getSValBuilder();
1432e5dd7070Spatrick const auto *Dtor = cast<CXXDestructorDecl>(CalleeCtx->getDecl());
1433e5dd7070Spatrick Loc ThisPtr = SVB.getCXXThis(Dtor, CalleeCtx);
1434e5dd7070Spatrick SVal ThisVal = State->getSVal(ThisPtr);
1435e5dd7070Spatrick
1436e5dd7070Spatrick const Stmt *Trigger;
1437*12c85518Srobert if (std::optional<CFGAutomaticObjDtor> AutoDtor =
1438*12c85518Srobert E.getAs<CFGAutomaticObjDtor>())
1439e5dd7070Spatrick Trigger = AutoDtor->getTriggerStmt();
1440*12c85518Srobert else if (std::optional<CFGDeleteDtor> DeleteDtor = E.getAs<CFGDeleteDtor>())
1441e5dd7070Spatrick Trigger = DeleteDtor->getDeleteExpr();
1442e5dd7070Spatrick else
1443e5dd7070Spatrick Trigger = Dtor->getBody();
1444e5dd7070Spatrick
1445e5dd7070Spatrick return getCXXDestructorCall(Dtor, Trigger, ThisVal.getAsRegion(),
1446*12c85518Srobert E.getAs<CFGBaseDtor>().has_value(), State,
1447e5dd7070Spatrick CallerCtx);
1448e5dd7070Spatrick }
1449e5dd7070Spatrick
getCall(const Stmt * S,ProgramStateRef State,const LocationContext * LC)1450e5dd7070Spatrick CallEventRef<> CallEventManager::getCall(const Stmt *S, ProgramStateRef State,
1451e5dd7070Spatrick const LocationContext *LC) {
1452e5dd7070Spatrick if (const auto *CE = dyn_cast<CallExpr>(S)) {
1453e5dd7070Spatrick return getSimpleCall(CE, State, LC);
1454e5dd7070Spatrick } else if (const auto *NE = dyn_cast<CXXNewExpr>(S)) {
1455e5dd7070Spatrick return getCXXAllocatorCall(NE, State, LC);
1456*12c85518Srobert } else if (const auto *DE = dyn_cast<CXXDeleteExpr>(S)) {
1457*12c85518Srobert return getCXXDeallocatorCall(DE, State, LC);
1458e5dd7070Spatrick } else if (const auto *ME = dyn_cast<ObjCMessageExpr>(S)) {
1459e5dd7070Spatrick return getObjCMethodCall(ME, State, LC);
1460e5dd7070Spatrick } else {
1461e5dd7070Spatrick return nullptr;
1462e5dd7070Spatrick }
1463e5dd7070Spatrick }
1464