1e5dd7070Spatrick //== BodyFarm.cpp - Factory for conjuring up fake bodies ----------*- C++ -*-//
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 // BodyFarm is a factory for creating faux implementations for functions/methods
10e5dd7070Spatrick // for analysis purposes.
11e5dd7070Spatrick //
12e5dd7070Spatrick //===----------------------------------------------------------------------===//
13e5dd7070Spatrick
14e5dd7070Spatrick #include "clang/Analysis/BodyFarm.h"
15e5dd7070Spatrick #include "clang/AST/ASTContext.h"
16e5dd7070Spatrick #include "clang/AST/CXXInheritance.h"
17e5dd7070Spatrick #include "clang/AST/Decl.h"
18e5dd7070Spatrick #include "clang/AST/Expr.h"
19e5dd7070Spatrick #include "clang/AST/ExprCXX.h"
20e5dd7070Spatrick #include "clang/AST/ExprObjC.h"
21e5dd7070Spatrick #include "clang/AST/NestedNameSpecifier.h"
22e5dd7070Spatrick #include "clang/Analysis/CodeInjector.h"
23*12c85518Srobert #include "clang/Basic/Builtins.h"
24e5dd7070Spatrick #include "clang/Basic/OperatorKinds.h"
25e5dd7070Spatrick #include "llvm/ADT/StringSwitch.h"
26e5dd7070Spatrick #include "llvm/Support/Debug.h"
27*12c85518Srobert #include <optional>
28e5dd7070Spatrick
29e5dd7070Spatrick #define DEBUG_TYPE "body-farm"
30e5dd7070Spatrick
31e5dd7070Spatrick using namespace clang;
32e5dd7070Spatrick
33e5dd7070Spatrick //===----------------------------------------------------------------------===//
34e5dd7070Spatrick // Helper creation functions for constructing faux ASTs.
35e5dd7070Spatrick //===----------------------------------------------------------------------===//
36e5dd7070Spatrick
isDispatchBlock(QualType Ty)37e5dd7070Spatrick static bool isDispatchBlock(QualType Ty) {
38e5dd7070Spatrick // Is it a block pointer?
39e5dd7070Spatrick const BlockPointerType *BPT = Ty->getAs<BlockPointerType>();
40e5dd7070Spatrick if (!BPT)
41e5dd7070Spatrick return false;
42e5dd7070Spatrick
43e5dd7070Spatrick // Check if the block pointer type takes no arguments and
44e5dd7070Spatrick // returns void.
45e5dd7070Spatrick const FunctionProtoType *FT =
46e5dd7070Spatrick BPT->getPointeeType()->getAs<FunctionProtoType>();
47e5dd7070Spatrick return FT && FT->getReturnType()->isVoidType() && FT->getNumParams() == 0;
48e5dd7070Spatrick }
49e5dd7070Spatrick
50e5dd7070Spatrick namespace {
51e5dd7070Spatrick class ASTMaker {
52e5dd7070Spatrick public:
ASTMaker(ASTContext & C)53e5dd7070Spatrick ASTMaker(ASTContext &C) : C(C) {}
54e5dd7070Spatrick
55e5dd7070Spatrick /// Create a new BinaryOperator representing a simple assignment.
56e5dd7070Spatrick BinaryOperator *makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty);
57e5dd7070Spatrick
58e5dd7070Spatrick /// Create a new BinaryOperator representing a comparison.
59e5dd7070Spatrick BinaryOperator *makeComparison(const Expr *LHS, const Expr *RHS,
60e5dd7070Spatrick BinaryOperator::Opcode Op);
61e5dd7070Spatrick
62e5dd7070Spatrick /// Create a new compound stmt using the provided statements.
63e5dd7070Spatrick CompoundStmt *makeCompound(ArrayRef<Stmt*>);
64e5dd7070Spatrick
65e5dd7070Spatrick /// Create a new DeclRefExpr for the referenced variable.
66e5dd7070Spatrick DeclRefExpr *makeDeclRefExpr(const VarDecl *D,
67e5dd7070Spatrick bool RefersToEnclosingVariableOrCapture = false);
68e5dd7070Spatrick
69e5dd7070Spatrick /// Create a new UnaryOperator representing a dereference.
70e5dd7070Spatrick UnaryOperator *makeDereference(const Expr *Arg, QualType Ty);
71e5dd7070Spatrick
72e5dd7070Spatrick /// Create an implicit cast for an integer conversion.
73e5dd7070Spatrick Expr *makeIntegralCast(const Expr *Arg, QualType Ty);
74e5dd7070Spatrick
75e5dd7070Spatrick /// Create an implicit cast to a builtin boolean type.
76e5dd7070Spatrick ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg);
77e5dd7070Spatrick
78e5dd7070Spatrick /// Create an implicit cast for lvalue-to-rvaluate conversions.
79e5dd7070Spatrick ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty);
80e5dd7070Spatrick
81e5dd7070Spatrick /// Make RValue out of variable declaration, creating a temporary
82e5dd7070Spatrick /// DeclRefExpr in the process.
83e5dd7070Spatrick ImplicitCastExpr *
84e5dd7070Spatrick makeLvalueToRvalue(const VarDecl *Decl,
85e5dd7070Spatrick bool RefersToEnclosingVariableOrCapture = false);
86e5dd7070Spatrick
87e5dd7070Spatrick /// Create an implicit cast of the given type.
88e5dd7070Spatrick ImplicitCastExpr *makeImplicitCast(const Expr *Arg, QualType Ty,
89e5dd7070Spatrick CastKind CK = CK_LValueToRValue);
90e5dd7070Spatrick
91*12c85518Srobert /// Create a cast to reference type.
92*12c85518Srobert CastExpr *makeReferenceCast(const Expr *Arg, QualType Ty);
93*12c85518Srobert
94e5dd7070Spatrick /// Create an Objective-C bool literal.
95e5dd7070Spatrick ObjCBoolLiteralExpr *makeObjCBool(bool Val);
96e5dd7070Spatrick
97e5dd7070Spatrick /// Create an Objective-C ivar reference.
98e5dd7070Spatrick ObjCIvarRefExpr *makeObjCIvarRef(const Expr *Base, const ObjCIvarDecl *IVar);
99e5dd7070Spatrick
100e5dd7070Spatrick /// Create a Return statement.
101e5dd7070Spatrick ReturnStmt *makeReturn(const Expr *RetVal);
102e5dd7070Spatrick
103e5dd7070Spatrick /// Create an integer literal expression of the given type.
104e5dd7070Spatrick IntegerLiteral *makeIntegerLiteral(uint64_t Value, QualType Ty);
105e5dd7070Spatrick
106e5dd7070Spatrick /// Create a member expression.
107e5dd7070Spatrick MemberExpr *makeMemberExpression(Expr *base, ValueDecl *MemberDecl,
108e5dd7070Spatrick bool IsArrow = false,
109e5dd7070Spatrick ExprValueKind ValueKind = VK_LValue);
110e5dd7070Spatrick
111e5dd7070Spatrick /// Returns a *first* member field of a record declaration with a given name.
112e5dd7070Spatrick /// \return an nullptr if no member with such a name exists.
113e5dd7070Spatrick ValueDecl *findMemberField(const RecordDecl *RD, StringRef Name);
114e5dd7070Spatrick
115e5dd7070Spatrick private:
116e5dd7070Spatrick ASTContext &C;
117e5dd7070Spatrick };
118e5dd7070Spatrick }
119e5dd7070Spatrick
makeAssignment(const Expr * LHS,const Expr * RHS,QualType Ty)120e5dd7070Spatrick BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS,
121e5dd7070Spatrick QualType Ty) {
122ec727ea7Spatrick return BinaryOperator::Create(
123ec727ea7Spatrick C, const_cast<Expr *>(LHS), const_cast<Expr *>(RHS), BO_Assign, Ty,
124a9ac8606Spatrick VK_PRValue, OK_Ordinary, SourceLocation(), FPOptionsOverride());
125e5dd7070Spatrick }
126e5dd7070Spatrick
makeComparison(const Expr * LHS,const Expr * RHS,BinaryOperator::Opcode Op)127e5dd7070Spatrick BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,
128e5dd7070Spatrick BinaryOperator::Opcode Op) {
129e5dd7070Spatrick assert(BinaryOperator::isLogicalOp(Op) ||
130e5dd7070Spatrick BinaryOperator::isComparisonOp(Op));
131ec727ea7Spatrick return BinaryOperator::Create(
132ec727ea7Spatrick C, const_cast<Expr *>(LHS), const_cast<Expr *>(RHS), Op,
133a9ac8606Spatrick C.getLogicalOperationType(), VK_PRValue, OK_Ordinary, SourceLocation(),
134ec727ea7Spatrick FPOptionsOverride());
135e5dd7070Spatrick }
136e5dd7070Spatrick
makeCompound(ArrayRef<Stmt * > Stmts)137e5dd7070Spatrick CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {
138*12c85518Srobert return CompoundStmt::Create(C, Stmts, FPOptionsOverride(), SourceLocation(),
139*12c85518Srobert SourceLocation());
140e5dd7070Spatrick }
141e5dd7070Spatrick
makeDeclRefExpr(const VarDecl * D,bool RefersToEnclosingVariableOrCapture)142e5dd7070Spatrick DeclRefExpr *ASTMaker::makeDeclRefExpr(
143e5dd7070Spatrick const VarDecl *D,
144e5dd7070Spatrick bool RefersToEnclosingVariableOrCapture) {
145e5dd7070Spatrick QualType Type = D->getType().getNonReferenceType();
146e5dd7070Spatrick
147e5dd7070Spatrick DeclRefExpr *DR = DeclRefExpr::Create(
148e5dd7070Spatrick C, NestedNameSpecifierLoc(), SourceLocation(), const_cast<VarDecl *>(D),
149e5dd7070Spatrick RefersToEnclosingVariableOrCapture, SourceLocation(), Type, VK_LValue);
150e5dd7070Spatrick return DR;
151e5dd7070Spatrick }
152e5dd7070Spatrick
makeDereference(const Expr * Arg,QualType Ty)153e5dd7070Spatrick UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {
154ec727ea7Spatrick return UnaryOperator::Create(C, const_cast<Expr *>(Arg), UO_Deref, Ty,
155e5dd7070Spatrick VK_LValue, OK_Ordinary, SourceLocation(),
156ec727ea7Spatrick /*CanOverflow*/ false, FPOptionsOverride());
157e5dd7070Spatrick }
158e5dd7070Spatrick
makeLvalueToRvalue(const Expr * Arg,QualType Ty)159e5dd7070Spatrick ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
160e5dd7070Spatrick return makeImplicitCast(Arg, Ty, CK_LValueToRValue);
161e5dd7070Spatrick }
162e5dd7070Spatrick
163e5dd7070Spatrick ImplicitCastExpr *
makeLvalueToRvalue(const VarDecl * Arg,bool RefersToEnclosingVariableOrCapture)164e5dd7070Spatrick ASTMaker::makeLvalueToRvalue(const VarDecl *Arg,
165e5dd7070Spatrick bool RefersToEnclosingVariableOrCapture) {
166e5dd7070Spatrick QualType Type = Arg->getType().getNonReferenceType();
167e5dd7070Spatrick return makeLvalueToRvalue(makeDeclRefExpr(Arg,
168e5dd7070Spatrick RefersToEnclosingVariableOrCapture),
169e5dd7070Spatrick Type);
170e5dd7070Spatrick }
171e5dd7070Spatrick
makeImplicitCast(const Expr * Arg,QualType Ty,CastKind CK)172e5dd7070Spatrick ImplicitCastExpr *ASTMaker::makeImplicitCast(const Expr *Arg, QualType Ty,
173e5dd7070Spatrick CastKind CK) {
174e5dd7070Spatrick return ImplicitCastExpr::Create(C, Ty,
175e5dd7070Spatrick /* CastKind=*/CK,
176e5dd7070Spatrick /* Expr=*/const_cast<Expr *>(Arg),
177e5dd7070Spatrick /* CXXCastPath=*/nullptr,
178a9ac8606Spatrick /* ExprValueKind=*/VK_PRValue,
179a9ac8606Spatrick /* FPFeatures */ FPOptionsOverride());
180e5dd7070Spatrick }
181e5dd7070Spatrick
makeReferenceCast(const Expr * Arg,QualType Ty)182*12c85518Srobert CastExpr *ASTMaker::makeReferenceCast(const Expr *Arg, QualType Ty) {
183*12c85518Srobert assert(Ty->isReferenceType());
184*12c85518Srobert return CXXStaticCastExpr::Create(
185*12c85518Srobert C, Ty.getNonReferenceType(),
186*12c85518Srobert Ty->isLValueReferenceType() ? VK_LValue : VK_XValue, CK_NoOp,
187*12c85518Srobert const_cast<Expr *>(Arg), /*CXXCastPath=*/nullptr,
188*12c85518Srobert /*Written=*/C.getTrivialTypeSourceInfo(Ty), FPOptionsOverride(),
189*12c85518Srobert SourceLocation(), SourceLocation(), SourceRange());
190*12c85518Srobert }
191*12c85518Srobert
makeIntegralCast(const Expr * Arg,QualType Ty)192e5dd7070Spatrick Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
193e5dd7070Spatrick if (Arg->getType() == Ty)
194e5dd7070Spatrick return const_cast<Expr*>(Arg);
195a9ac8606Spatrick return makeImplicitCast(Arg, Ty, CK_IntegralCast);
196e5dd7070Spatrick }
197e5dd7070Spatrick
makeIntegralCastToBoolean(const Expr * Arg)198e5dd7070Spatrick ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) {
199a9ac8606Spatrick return makeImplicitCast(Arg, C.BoolTy, CK_IntegralToBoolean);
200e5dd7070Spatrick }
201e5dd7070Spatrick
makeObjCBool(bool Val)202e5dd7070Spatrick ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) {
203e5dd7070Spatrick QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy;
204e5dd7070Spatrick return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation());
205e5dd7070Spatrick }
206e5dd7070Spatrick
makeObjCIvarRef(const Expr * Base,const ObjCIvarDecl * IVar)207e5dd7070Spatrick ObjCIvarRefExpr *ASTMaker::makeObjCIvarRef(const Expr *Base,
208e5dd7070Spatrick const ObjCIvarDecl *IVar) {
209e5dd7070Spatrick return new (C) ObjCIvarRefExpr(const_cast<ObjCIvarDecl*>(IVar),
210e5dd7070Spatrick IVar->getType(), SourceLocation(),
211e5dd7070Spatrick SourceLocation(), const_cast<Expr*>(Base),
212e5dd7070Spatrick /*arrow=*/true, /*free=*/false);
213e5dd7070Spatrick }
214e5dd7070Spatrick
makeReturn(const Expr * RetVal)215e5dd7070Spatrick ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) {
216e5dd7070Spatrick return ReturnStmt::Create(C, SourceLocation(), const_cast<Expr *>(RetVal),
217e5dd7070Spatrick /* NRVOCandidate=*/nullptr);
218e5dd7070Spatrick }
219e5dd7070Spatrick
makeIntegerLiteral(uint64_t Value,QualType Ty)220e5dd7070Spatrick IntegerLiteral *ASTMaker::makeIntegerLiteral(uint64_t Value, QualType Ty) {
221e5dd7070Spatrick llvm::APInt APValue = llvm::APInt(C.getTypeSize(Ty), Value);
222e5dd7070Spatrick return IntegerLiteral::Create(C, APValue, Ty, SourceLocation());
223e5dd7070Spatrick }
224e5dd7070Spatrick
makeMemberExpression(Expr * base,ValueDecl * MemberDecl,bool IsArrow,ExprValueKind ValueKind)225e5dd7070Spatrick MemberExpr *ASTMaker::makeMemberExpression(Expr *base, ValueDecl *MemberDecl,
226e5dd7070Spatrick bool IsArrow,
227e5dd7070Spatrick ExprValueKind ValueKind) {
228e5dd7070Spatrick
229e5dd7070Spatrick DeclAccessPair FoundDecl = DeclAccessPair::make(MemberDecl, AS_public);
230e5dd7070Spatrick return MemberExpr::Create(
231e5dd7070Spatrick C, base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(),
232e5dd7070Spatrick SourceLocation(), MemberDecl, FoundDecl,
233e5dd7070Spatrick DeclarationNameInfo(MemberDecl->getDeclName(), SourceLocation()),
234e5dd7070Spatrick /* TemplateArgumentListInfo=*/ nullptr, MemberDecl->getType(), ValueKind,
235e5dd7070Spatrick OK_Ordinary, NOUR_None);
236e5dd7070Spatrick }
237e5dd7070Spatrick
findMemberField(const RecordDecl * RD,StringRef Name)238e5dd7070Spatrick ValueDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) {
239e5dd7070Spatrick
240e5dd7070Spatrick CXXBasePaths Paths(
241e5dd7070Spatrick /* FindAmbiguities=*/false,
242e5dd7070Spatrick /* RecordPaths=*/false,
243e5dd7070Spatrick /* DetectVirtual=*/ false);
244e5dd7070Spatrick const IdentifierInfo &II = C.Idents.get(Name);
245e5dd7070Spatrick DeclarationName DeclName = C.DeclarationNames.getIdentifier(&II);
246e5dd7070Spatrick
247e5dd7070Spatrick DeclContextLookupResult Decls = RD->lookup(DeclName);
248e5dd7070Spatrick for (NamedDecl *FoundDecl : Decls)
249e5dd7070Spatrick if (!FoundDecl->getDeclContext()->isFunctionOrMethod())
250e5dd7070Spatrick return cast<ValueDecl>(FoundDecl);
251e5dd7070Spatrick
252e5dd7070Spatrick return nullptr;
253e5dd7070Spatrick }
254e5dd7070Spatrick
255e5dd7070Spatrick //===----------------------------------------------------------------------===//
256e5dd7070Spatrick // Creation functions for faux ASTs.
257e5dd7070Spatrick //===----------------------------------------------------------------------===//
258e5dd7070Spatrick
259e5dd7070Spatrick typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
260e5dd7070Spatrick
create_call_once_funcptr_call(ASTContext & C,ASTMaker M,const ParmVarDecl * Callback,ArrayRef<Expr * > CallArgs)261e5dd7070Spatrick static CallExpr *create_call_once_funcptr_call(ASTContext &C, ASTMaker M,
262e5dd7070Spatrick const ParmVarDecl *Callback,
263e5dd7070Spatrick ArrayRef<Expr *> CallArgs) {
264e5dd7070Spatrick
265e5dd7070Spatrick QualType Ty = Callback->getType();
266e5dd7070Spatrick DeclRefExpr *Call = M.makeDeclRefExpr(Callback);
267e5dd7070Spatrick Expr *SubExpr;
268e5dd7070Spatrick if (Ty->isRValueReferenceType()) {
269e5dd7070Spatrick SubExpr = M.makeImplicitCast(
270e5dd7070Spatrick Call, Ty.getNonReferenceType(), CK_LValueToRValue);
271e5dd7070Spatrick } else if (Ty->isLValueReferenceType() &&
272e5dd7070Spatrick Call->getType()->isFunctionType()) {
273e5dd7070Spatrick Ty = C.getPointerType(Ty.getNonReferenceType());
274e5dd7070Spatrick SubExpr = M.makeImplicitCast(Call, Ty, CK_FunctionToPointerDecay);
275e5dd7070Spatrick } else if (Ty->isLValueReferenceType()
276e5dd7070Spatrick && Call->getType()->isPointerType()
277e5dd7070Spatrick && Call->getType()->getPointeeType()->isFunctionType()){
278e5dd7070Spatrick SubExpr = Call;
279e5dd7070Spatrick } else {
280e5dd7070Spatrick llvm_unreachable("Unexpected state");
281e5dd7070Spatrick }
282e5dd7070Spatrick
283a9ac8606Spatrick return CallExpr::Create(C, SubExpr, CallArgs, C.VoidTy, VK_PRValue,
284a9ac8606Spatrick SourceLocation(), FPOptionsOverride());
285e5dd7070Spatrick }
286e5dd7070Spatrick
create_call_once_lambda_call(ASTContext & C,ASTMaker M,const ParmVarDecl * Callback,CXXRecordDecl * CallbackDecl,ArrayRef<Expr * > CallArgs)287e5dd7070Spatrick static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M,
288e5dd7070Spatrick const ParmVarDecl *Callback,
289e5dd7070Spatrick CXXRecordDecl *CallbackDecl,
290e5dd7070Spatrick ArrayRef<Expr *> CallArgs) {
291e5dd7070Spatrick assert(CallbackDecl != nullptr);
292e5dd7070Spatrick assert(CallbackDecl->isLambda());
293e5dd7070Spatrick FunctionDecl *callOperatorDecl = CallbackDecl->getLambdaCallOperator();
294e5dd7070Spatrick assert(callOperatorDecl != nullptr);
295e5dd7070Spatrick
296e5dd7070Spatrick DeclRefExpr *callOperatorDeclRef =
297e5dd7070Spatrick DeclRefExpr::Create(/* Ctx =*/ C,
298e5dd7070Spatrick /* QualifierLoc =*/ NestedNameSpecifierLoc(),
299e5dd7070Spatrick /* TemplateKWLoc =*/ SourceLocation(),
300e5dd7070Spatrick const_cast<FunctionDecl *>(callOperatorDecl),
301e5dd7070Spatrick /* RefersToEnclosingVariableOrCapture=*/ false,
302e5dd7070Spatrick /* NameLoc =*/ SourceLocation(),
303e5dd7070Spatrick /* T =*/ callOperatorDecl->getType(),
304e5dd7070Spatrick /* VK =*/ VK_LValue);
305e5dd7070Spatrick
306e5dd7070Spatrick return CXXOperatorCallExpr::Create(
307e5dd7070Spatrick /*AstContext=*/C, OO_Call, callOperatorDeclRef,
308e5dd7070Spatrick /*Args=*/CallArgs,
309e5dd7070Spatrick /*QualType=*/C.VoidTy,
310a9ac8606Spatrick /*ExprValueType=*/VK_PRValue,
311ec727ea7Spatrick /*SourceLocation=*/SourceLocation(),
312ec727ea7Spatrick /*FPFeatures=*/FPOptionsOverride());
313e5dd7070Spatrick }
314e5dd7070Spatrick
315*12c85518Srobert /// Create a fake body for 'std::move' or 'std::forward'. This is just:
316*12c85518Srobert ///
317*12c85518Srobert /// \code
318*12c85518Srobert /// return static_cast<return_type>(param);
319*12c85518Srobert /// \endcode
create_std_move_forward(ASTContext & C,const FunctionDecl * D)320*12c85518Srobert static Stmt *create_std_move_forward(ASTContext &C, const FunctionDecl *D) {
321*12c85518Srobert LLVM_DEBUG(llvm::dbgs() << "Generating body for std::move / std::forward\n");
322*12c85518Srobert
323*12c85518Srobert ASTMaker M(C);
324*12c85518Srobert
325*12c85518Srobert QualType ReturnType = D->getType()->castAs<FunctionType>()->getReturnType();
326*12c85518Srobert Expr *Param = M.makeDeclRefExpr(D->getParamDecl(0));
327*12c85518Srobert Expr *Cast = M.makeReferenceCast(Param, ReturnType);
328*12c85518Srobert return M.makeReturn(Cast);
329*12c85518Srobert }
330*12c85518Srobert
331e5dd7070Spatrick /// Create a fake body for std::call_once.
332e5dd7070Spatrick /// Emulates the following function body:
333e5dd7070Spatrick ///
334e5dd7070Spatrick /// \code
335e5dd7070Spatrick /// typedef struct once_flag_s {
336e5dd7070Spatrick /// unsigned long __state = 0;
337e5dd7070Spatrick /// } once_flag;
338e5dd7070Spatrick /// template<class Callable>
339e5dd7070Spatrick /// void call_once(once_flag& o, Callable func) {
340e5dd7070Spatrick /// if (!o.__state) {
341e5dd7070Spatrick /// func();
342e5dd7070Spatrick /// }
343e5dd7070Spatrick /// o.__state = 1;
344e5dd7070Spatrick /// }
345e5dd7070Spatrick /// \endcode
create_call_once(ASTContext & C,const FunctionDecl * D)346e5dd7070Spatrick static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) {
347e5dd7070Spatrick LLVM_DEBUG(llvm::dbgs() << "Generating body for call_once\n");
348e5dd7070Spatrick
349e5dd7070Spatrick // We need at least two parameters.
350e5dd7070Spatrick if (D->param_size() < 2)
351e5dd7070Spatrick return nullptr;
352e5dd7070Spatrick
353e5dd7070Spatrick ASTMaker M(C);
354e5dd7070Spatrick
355e5dd7070Spatrick const ParmVarDecl *Flag = D->getParamDecl(0);
356e5dd7070Spatrick const ParmVarDecl *Callback = D->getParamDecl(1);
357e5dd7070Spatrick
358e5dd7070Spatrick if (!Callback->getType()->isReferenceType()) {
359e5dd7070Spatrick llvm::dbgs() << "libcxx03 std::call_once implementation, skipping.\n";
360e5dd7070Spatrick return nullptr;
361e5dd7070Spatrick }
362e5dd7070Spatrick if (!Flag->getType()->isReferenceType()) {
363e5dd7070Spatrick llvm::dbgs() << "unknown std::call_once implementation, skipping.\n";
364e5dd7070Spatrick return nullptr;
365e5dd7070Spatrick }
366e5dd7070Spatrick
367e5dd7070Spatrick QualType CallbackType = Callback->getType().getNonReferenceType();
368e5dd7070Spatrick
369e5dd7070Spatrick // Nullable pointer, non-null iff function is a CXXRecordDecl.
370e5dd7070Spatrick CXXRecordDecl *CallbackRecordDecl = CallbackType->getAsCXXRecordDecl();
371e5dd7070Spatrick QualType FlagType = Flag->getType().getNonReferenceType();
372e5dd7070Spatrick auto *FlagRecordDecl = FlagType->getAsRecordDecl();
373e5dd7070Spatrick
374e5dd7070Spatrick if (!FlagRecordDecl) {
375e5dd7070Spatrick LLVM_DEBUG(llvm::dbgs() << "Flag field is not a record: "
376e5dd7070Spatrick << "unknown std::call_once implementation, "
377e5dd7070Spatrick << "ignoring the call.\n");
378e5dd7070Spatrick return nullptr;
379e5dd7070Spatrick }
380e5dd7070Spatrick
381e5dd7070Spatrick // We initially assume libc++ implementation of call_once,
382e5dd7070Spatrick // where the once_flag struct has a field `__state_`.
383e5dd7070Spatrick ValueDecl *FlagFieldDecl = M.findMemberField(FlagRecordDecl, "__state_");
384e5dd7070Spatrick
385e5dd7070Spatrick // Otherwise, try libstdc++ implementation, with a field
386e5dd7070Spatrick // `_M_once`
387e5dd7070Spatrick if (!FlagFieldDecl) {
388e5dd7070Spatrick FlagFieldDecl = M.findMemberField(FlagRecordDecl, "_M_once");
389e5dd7070Spatrick }
390e5dd7070Spatrick
391e5dd7070Spatrick if (!FlagFieldDecl) {
392e5dd7070Spatrick LLVM_DEBUG(llvm::dbgs() << "No field _M_once or __state_ found on "
393e5dd7070Spatrick << "std::once_flag struct: unknown std::call_once "
394e5dd7070Spatrick << "implementation, ignoring the call.");
395e5dd7070Spatrick return nullptr;
396e5dd7070Spatrick }
397e5dd7070Spatrick
398e5dd7070Spatrick bool isLambdaCall = CallbackRecordDecl && CallbackRecordDecl->isLambda();
399e5dd7070Spatrick if (CallbackRecordDecl && !isLambdaCall) {
400e5dd7070Spatrick LLVM_DEBUG(llvm::dbgs()
401e5dd7070Spatrick << "Not supported: synthesizing body for functors when "
402e5dd7070Spatrick << "body farming std::call_once, ignoring the call.");
403e5dd7070Spatrick return nullptr;
404e5dd7070Spatrick }
405e5dd7070Spatrick
406e5dd7070Spatrick SmallVector<Expr *, 5> CallArgs;
407e5dd7070Spatrick const FunctionProtoType *CallbackFunctionType;
408e5dd7070Spatrick if (isLambdaCall) {
409e5dd7070Spatrick
410e5dd7070Spatrick // Lambda requires callback itself inserted as a first parameter.
411e5dd7070Spatrick CallArgs.push_back(
412e5dd7070Spatrick M.makeDeclRefExpr(Callback,
413e5dd7070Spatrick /* RefersToEnclosingVariableOrCapture=*/ true));
414e5dd7070Spatrick CallbackFunctionType = CallbackRecordDecl->getLambdaCallOperator()
415e5dd7070Spatrick ->getType()
416e5dd7070Spatrick ->getAs<FunctionProtoType>();
417e5dd7070Spatrick } else if (!CallbackType->getPointeeType().isNull()) {
418e5dd7070Spatrick CallbackFunctionType =
419e5dd7070Spatrick CallbackType->getPointeeType()->getAs<FunctionProtoType>();
420e5dd7070Spatrick } else {
421e5dd7070Spatrick CallbackFunctionType = CallbackType->getAs<FunctionProtoType>();
422e5dd7070Spatrick }
423e5dd7070Spatrick
424e5dd7070Spatrick if (!CallbackFunctionType)
425e5dd7070Spatrick return nullptr;
426e5dd7070Spatrick
427e5dd7070Spatrick // First two arguments are used for the flag and for the callback.
428e5dd7070Spatrick if (D->getNumParams() != CallbackFunctionType->getNumParams() + 2) {
429e5dd7070Spatrick LLVM_DEBUG(llvm::dbgs() << "Types of params of the callback do not match "
430e5dd7070Spatrick << "params passed to std::call_once, "
431e5dd7070Spatrick << "ignoring the call\n");
432e5dd7070Spatrick return nullptr;
433e5dd7070Spatrick }
434e5dd7070Spatrick
435e5dd7070Spatrick // All arguments past first two ones are passed to the callback,
436e5dd7070Spatrick // and we turn lvalues into rvalues if the argument is not passed by
437e5dd7070Spatrick // reference.
438e5dd7070Spatrick for (unsigned int ParamIdx = 2; ParamIdx < D->getNumParams(); ParamIdx++) {
439e5dd7070Spatrick const ParmVarDecl *PDecl = D->getParamDecl(ParamIdx);
440e5dd7070Spatrick assert(PDecl);
441e5dd7070Spatrick if (CallbackFunctionType->getParamType(ParamIdx - 2)
442e5dd7070Spatrick .getNonReferenceType()
443e5dd7070Spatrick .getCanonicalType() !=
444e5dd7070Spatrick PDecl->getType().getNonReferenceType().getCanonicalType()) {
445e5dd7070Spatrick LLVM_DEBUG(llvm::dbgs() << "Types of params of the callback do not match "
446e5dd7070Spatrick << "params passed to std::call_once, "
447e5dd7070Spatrick << "ignoring the call\n");
448e5dd7070Spatrick return nullptr;
449e5dd7070Spatrick }
450e5dd7070Spatrick Expr *ParamExpr = M.makeDeclRefExpr(PDecl);
451e5dd7070Spatrick if (!CallbackFunctionType->getParamType(ParamIdx - 2)->isReferenceType()) {
452e5dd7070Spatrick QualType PTy = PDecl->getType().getNonReferenceType();
453e5dd7070Spatrick ParamExpr = M.makeLvalueToRvalue(ParamExpr, PTy);
454e5dd7070Spatrick }
455e5dd7070Spatrick CallArgs.push_back(ParamExpr);
456e5dd7070Spatrick }
457e5dd7070Spatrick
458e5dd7070Spatrick CallExpr *CallbackCall;
459e5dd7070Spatrick if (isLambdaCall) {
460e5dd7070Spatrick
461e5dd7070Spatrick CallbackCall = create_call_once_lambda_call(C, M, Callback,
462e5dd7070Spatrick CallbackRecordDecl, CallArgs);
463e5dd7070Spatrick } else {
464e5dd7070Spatrick
465e5dd7070Spatrick // Function pointer case.
466e5dd7070Spatrick CallbackCall = create_call_once_funcptr_call(C, M, Callback, CallArgs);
467e5dd7070Spatrick }
468e5dd7070Spatrick
469e5dd7070Spatrick DeclRefExpr *FlagDecl =
470e5dd7070Spatrick M.makeDeclRefExpr(Flag,
471e5dd7070Spatrick /* RefersToEnclosingVariableOrCapture=*/true);
472e5dd7070Spatrick
473e5dd7070Spatrick
474e5dd7070Spatrick MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FlagFieldDecl);
475e5dd7070Spatrick assert(Deref->isLValue());
476e5dd7070Spatrick QualType DerefType = Deref->getType();
477e5dd7070Spatrick
478e5dd7070Spatrick // Negation predicate.
479ec727ea7Spatrick UnaryOperator *FlagCheck = UnaryOperator::Create(
480ec727ea7Spatrick C,
481e5dd7070Spatrick /* input=*/
482e5dd7070Spatrick M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType,
483e5dd7070Spatrick CK_IntegralToBoolean),
484e5dd7070Spatrick /* opc=*/UO_LNot,
485e5dd7070Spatrick /* QualType=*/C.IntTy,
486a9ac8606Spatrick /* ExprValueKind=*/VK_PRValue,
487e5dd7070Spatrick /* ExprObjectKind=*/OK_Ordinary, SourceLocation(),
488ec727ea7Spatrick /* CanOverflow*/ false, FPOptionsOverride());
489e5dd7070Spatrick
490e5dd7070Spatrick // Create assignment.
491e5dd7070Spatrick BinaryOperator *FlagAssignment = M.makeAssignment(
492e5dd7070Spatrick Deref, M.makeIntegralCast(M.makeIntegerLiteral(1, C.IntTy), DerefType),
493e5dd7070Spatrick DerefType);
494e5dd7070Spatrick
495e5dd7070Spatrick auto *Out =
496*12c85518Srobert IfStmt::Create(C, SourceLocation(), IfStatementKind::Ordinary,
497e5dd7070Spatrick /* Init=*/nullptr,
498e5dd7070Spatrick /* Var=*/nullptr,
499e5dd7070Spatrick /* Cond=*/FlagCheck,
500a9ac8606Spatrick /* LPL=*/SourceLocation(),
501a9ac8606Spatrick /* RPL=*/SourceLocation(),
502e5dd7070Spatrick /* Then=*/M.makeCompound({CallbackCall, FlagAssignment}));
503e5dd7070Spatrick
504e5dd7070Spatrick return Out;
505e5dd7070Spatrick }
506e5dd7070Spatrick
507e5dd7070Spatrick /// Create a fake body for dispatch_once.
create_dispatch_once(ASTContext & C,const FunctionDecl * D)508e5dd7070Spatrick static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
509e5dd7070Spatrick // Check if we have at least two parameters.
510e5dd7070Spatrick if (D->param_size() != 2)
511e5dd7070Spatrick return nullptr;
512e5dd7070Spatrick
513e5dd7070Spatrick // Check if the first parameter is a pointer to integer type.
514e5dd7070Spatrick const ParmVarDecl *Predicate = D->getParamDecl(0);
515e5dd7070Spatrick QualType PredicateQPtrTy = Predicate->getType();
516e5dd7070Spatrick const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();
517e5dd7070Spatrick if (!PredicatePtrTy)
518e5dd7070Spatrick return nullptr;
519e5dd7070Spatrick QualType PredicateTy = PredicatePtrTy->getPointeeType();
520e5dd7070Spatrick if (!PredicateTy->isIntegerType())
521e5dd7070Spatrick return nullptr;
522e5dd7070Spatrick
523e5dd7070Spatrick // Check if the second parameter is the proper block type.
524e5dd7070Spatrick const ParmVarDecl *Block = D->getParamDecl(1);
525e5dd7070Spatrick QualType Ty = Block->getType();
526e5dd7070Spatrick if (!isDispatchBlock(Ty))
527e5dd7070Spatrick return nullptr;
528e5dd7070Spatrick
529e5dd7070Spatrick // Everything checks out. Create a fakse body that checks the predicate,
530e5dd7070Spatrick // sets it, and calls the block. Basically, an AST dump of:
531e5dd7070Spatrick //
532e5dd7070Spatrick // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
533e5dd7070Spatrick // if (*predicate != ~0l) {
534e5dd7070Spatrick // *predicate = ~0l;
535e5dd7070Spatrick // block();
536e5dd7070Spatrick // }
537e5dd7070Spatrick // }
538e5dd7070Spatrick
539e5dd7070Spatrick ASTMaker M(C);
540e5dd7070Spatrick
541e5dd7070Spatrick // (1) Create the call.
542e5dd7070Spatrick CallExpr *CE = CallExpr::Create(
543e5dd7070Spatrick /*ASTContext=*/C,
544e5dd7070Spatrick /*StmtClass=*/M.makeLvalueToRvalue(/*Expr=*/Block),
545*12c85518Srobert /*Args=*/std::nullopt,
546e5dd7070Spatrick /*QualType=*/C.VoidTy,
547a9ac8606Spatrick /*ExprValueType=*/VK_PRValue,
548a9ac8606Spatrick /*SourceLocation=*/SourceLocation(), FPOptionsOverride());
549e5dd7070Spatrick
550e5dd7070Spatrick // (2) Create the assignment to the predicate.
551e5dd7070Spatrick Expr *DoneValue =
552ec727ea7Spatrick UnaryOperator::Create(C, M.makeIntegerLiteral(0, C.LongTy), UO_Not,
553a9ac8606Spatrick C.LongTy, VK_PRValue, OK_Ordinary, SourceLocation(),
554ec727ea7Spatrick /*CanOverflow*/ false, FPOptionsOverride());
555e5dd7070Spatrick
556e5dd7070Spatrick BinaryOperator *B =
557e5dd7070Spatrick M.makeAssignment(
558e5dd7070Spatrick M.makeDereference(
559e5dd7070Spatrick M.makeLvalueToRvalue(
560e5dd7070Spatrick M.makeDeclRefExpr(Predicate), PredicateQPtrTy),
561e5dd7070Spatrick PredicateTy),
562e5dd7070Spatrick M.makeIntegralCast(DoneValue, PredicateTy),
563e5dd7070Spatrick PredicateTy);
564e5dd7070Spatrick
565e5dd7070Spatrick // (3) Create the compound statement.
566e5dd7070Spatrick Stmt *Stmts[] = { B, CE };
567e5dd7070Spatrick CompoundStmt *CS = M.makeCompound(Stmts);
568e5dd7070Spatrick
569e5dd7070Spatrick // (4) Create the 'if' condition.
570e5dd7070Spatrick ImplicitCastExpr *LValToRval =
571e5dd7070Spatrick M.makeLvalueToRvalue(
572e5dd7070Spatrick M.makeDereference(
573e5dd7070Spatrick M.makeLvalueToRvalue(
574e5dd7070Spatrick M.makeDeclRefExpr(Predicate),
575e5dd7070Spatrick PredicateQPtrTy),
576e5dd7070Spatrick PredicateTy),
577e5dd7070Spatrick PredicateTy);
578e5dd7070Spatrick
579e5dd7070Spatrick Expr *GuardCondition = M.makeComparison(LValToRval, DoneValue, BO_NE);
580e5dd7070Spatrick // (5) Create the 'if' statement.
581*12c85518Srobert auto *If = IfStmt::Create(C, SourceLocation(), IfStatementKind::Ordinary,
582e5dd7070Spatrick /* Init=*/nullptr,
583e5dd7070Spatrick /* Var=*/nullptr,
584e5dd7070Spatrick /* Cond=*/GuardCondition,
585a9ac8606Spatrick /* LPL=*/SourceLocation(),
586a9ac8606Spatrick /* RPL=*/SourceLocation(),
587e5dd7070Spatrick /* Then=*/CS);
588e5dd7070Spatrick return If;
589e5dd7070Spatrick }
590e5dd7070Spatrick
591e5dd7070Spatrick /// Create a fake body for dispatch_sync.
create_dispatch_sync(ASTContext & C,const FunctionDecl * D)592e5dd7070Spatrick static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
593e5dd7070Spatrick // Check if we have at least two parameters.
594e5dd7070Spatrick if (D->param_size() != 2)
595e5dd7070Spatrick return nullptr;
596e5dd7070Spatrick
597e5dd7070Spatrick // Check if the second parameter is a block.
598e5dd7070Spatrick const ParmVarDecl *PV = D->getParamDecl(1);
599e5dd7070Spatrick QualType Ty = PV->getType();
600e5dd7070Spatrick if (!isDispatchBlock(Ty))
601e5dd7070Spatrick return nullptr;
602e5dd7070Spatrick
603e5dd7070Spatrick // Everything checks out. Create a fake body that just calls the block.
604e5dd7070Spatrick // This is basically just an AST dump of:
605e5dd7070Spatrick //
606e5dd7070Spatrick // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) {
607e5dd7070Spatrick // block();
608e5dd7070Spatrick // }
609e5dd7070Spatrick //
610e5dd7070Spatrick ASTMaker M(C);
611e5dd7070Spatrick DeclRefExpr *DR = M.makeDeclRefExpr(PV);
612e5dd7070Spatrick ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
613*12c85518Srobert CallExpr *CE = CallExpr::Create(C, ICE, std::nullopt, C.VoidTy, VK_PRValue,
614a9ac8606Spatrick SourceLocation(), FPOptionsOverride());
615e5dd7070Spatrick return CE;
616e5dd7070Spatrick }
617e5dd7070Spatrick
create_OSAtomicCompareAndSwap(ASTContext & C,const FunctionDecl * D)618e5dd7070Spatrick static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
619e5dd7070Spatrick {
620e5dd7070Spatrick // There are exactly 3 arguments.
621e5dd7070Spatrick if (D->param_size() != 3)
622e5dd7070Spatrick return nullptr;
623e5dd7070Spatrick
624e5dd7070Spatrick // Signature:
625e5dd7070Spatrick // _Bool OSAtomicCompareAndSwapPtr(void *__oldValue,
626e5dd7070Spatrick // void *__newValue,
627e5dd7070Spatrick // void * volatile *__theValue)
628e5dd7070Spatrick // Generate body:
629e5dd7070Spatrick // if (oldValue == *theValue) {
630e5dd7070Spatrick // *theValue = newValue;
631e5dd7070Spatrick // return YES;
632e5dd7070Spatrick // }
633e5dd7070Spatrick // else return NO;
634e5dd7070Spatrick
635e5dd7070Spatrick QualType ResultTy = D->getReturnType();
636e5dd7070Spatrick bool isBoolean = ResultTy->isBooleanType();
637e5dd7070Spatrick if (!isBoolean && !ResultTy->isIntegralType(C))
638e5dd7070Spatrick return nullptr;
639e5dd7070Spatrick
640e5dd7070Spatrick const ParmVarDecl *OldValue = D->getParamDecl(0);
641e5dd7070Spatrick QualType OldValueTy = OldValue->getType();
642e5dd7070Spatrick
643e5dd7070Spatrick const ParmVarDecl *NewValue = D->getParamDecl(1);
644e5dd7070Spatrick QualType NewValueTy = NewValue->getType();
645e5dd7070Spatrick
646e5dd7070Spatrick assert(OldValueTy == NewValueTy);
647e5dd7070Spatrick
648e5dd7070Spatrick const ParmVarDecl *TheValue = D->getParamDecl(2);
649e5dd7070Spatrick QualType TheValueTy = TheValue->getType();
650e5dd7070Spatrick const PointerType *PT = TheValueTy->getAs<PointerType>();
651e5dd7070Spatrick if (!PT)
652e5dd7070Spatrick return nullptr;
653e5dd7070Spatrick QualType PointeeTy = PT->getPointeeType();
654e5dd7070Spatrick
655e5dd7070Spatrick ASTMaker M(C);
656e5dd7070Spatrick // Construct the comparison.
657e5dd7070Spatrick Expr *Comparison =
658e5dd7070Spatrick M.makeComparison(
659e5dd7070Spatrick M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy),
660e5dd7070Spatrick M.makeLvalueToRvalue(
661e5dd7070Spatrick M.makeDereference(
662e5dd7070Spatrick M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
663e5dd7070Spatrick PointeeTy),
664e5dd7070Spatrick PointeeTy),
665e5dd7070Spatrick BO_EQ);
666e5dd7070Spatrick
667e5dd7070Spatrick // Construct the body of the IfStmt.
668e5dd7070Spatrick Stmt *Stmts[2];
669e5dd7070Spatrick Stmts[0] =
670e5dd7070Spatrick M.makeAssignment(
671e5dd7070Spatrick M.makeDereference(
672e5dd7070Spatrick M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
673e5dd7070Spatrick PointeeTy),
674e5dd7070Spatrick M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy),
675e5dd7070Spatrick NewValueTy);
676e5dd7070Spatrick
677e5dd7070Spatrick Expr *BoolVal = M.makeObjCBool(true);
678e5dd7070Spatrick Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
679e5dd7070Spatrick : M.makeIntegralCast(BoolVal, ResultTy);
680e5dd7070Spatrick Stmts[1] = M.makeReturn(RetVal);
681e5dd7070Spatrick CompoundStmt *Body = M.makeCompound(Stmts);
682e5dd7070Spatrick
683e5dd7070Spatrick // Construct the else clause.
684e5dd7070Spatrick BoolVal = M.makeObjCBool(false);
685e5dd7070Spatrick RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
686e5dd7070Spatrick : M.makeIntegralCast(BoolVal, ResultTy);
687e5dd7070Spatrick Stmt *Else = M.makeReturn(RetVal);
688e5dd7070Spatrick
689e5dd7070Spatrick /// Construct the If.
690a9ac8606Spatrick auto *If =
691*12c85518Srobert IfStmt::Create(C, SourceLocation(), IfStatementKind::Ordinary,
692e5dd7070Spatrick /* Init=*/nullptr,
693a9ac8606Spatrick /* Var=*/nullptr, Comparison,
694a9ac8606Spatrick /* LPL=*/SourceLocation(),
695a9ac8606Spatrick /* RPL=*/SourceLocation(), Body, SourceLocation(), Else);
696e5dd7070Spatrick
697e5dd7070Spatrick return If;
698e5dd7070Spatrick }
699e5dd7070Spatrick
getBody(const FunctionDecl * D)700e5dd7070Spatrick Stmt *BodyFarm::getBody(const FunctionDecl *D) {
701*12c85518Srobert std::optional<Stmt *> &Val = Bodies[D];
702*12c85518Srobert if (Val)
703*12c85518Srobert return *Val;
704e5dd7070Spatrick
705e5dd7070Spatrick Val = nullptr;
706e5dd7070Spatrick
707e5dd7070Spatrick if (D->getIdentifier() == nullptr)
708e5dd7070Spatrick return nullptr;
709e5dd7070Spatrick
710e5dd7070Spatrick StringRef Name = D->getName();
711e5dd7070Spatrick if (Name.empty())
712e5dd7070Spatrick return nullptr;
713e5dd7070Spatrick
714e5dd7070Spatrick FunctionFarmer FF;
715e5dd7070Spatrick
716*12c85518Srobert if (unsigned BuiltinID = D->getBuiltinID()) {
717*12c85518Srobert switch (BuiltinID) {
718*12c85518Srobert case Builtin::BIas_const:
719*12c85518Srobert case Builtin::BIforward:
720*12c85518Srobert case Builtin::BImove:
721*12c85518Srobert case Builtin::BImove_if_noexcept:
722*12c85518Srobert FF = create_std_move_forward;
723*12c85518Srobert break;
724*12c85518Srobert default:
725*12c85518Srobert FF = nullptr;
726*12c85518Srobert break;
727*12c85518Srobert }
728*12c85518Srobert } else if (Name.startswith("OSAtomicCompareAndSwap") ||
729e5dd7070Spatrick Name.startswith("objc_atomicCompareAndSwap")) {
730e5dd7070Spatrick FF = create_OSAtomicCompareAndSwap;
731e5dd7070Spatrick } else if (Name == "call_once" && D->getDeclContext()->isStdNamespace()) {
732e5dd7070Spatrick FF = create_call_once;
733e5dd7070Spatrick } else {
734e5dd7070Spatrick FF = llvm::StringSwitch<FunctionFarmer>(Name)
735e5dd7070Spatrick .Case("dispatch_sync", create_dispatch_sync)
736e5dd7070Spatrick .Case("dispatch_once", create_dispatch_once)
737e5dd7070Spatrick .Default(nullptr);
738e5dd7070Spatrick }
739e5dd7070Spatrick
740e5dd7070Spatrick if (FF) { Val = FF(C, D); }
741e5dd7070Spatrick else if (Injector) { Val = Injector->getBody(D); }
742*12c85518Srobert return *Val;
743e5dd7070Spatrick }
744e5dd7070Spatrick
findBackingIvar(const ObjCPropertyDecl * Prop)745e5dd7070Spatrick static const ObjCIvarDecl *findBackingIvar(const ObjCPropertyDecl *Prop) {
746e5dd7070Spatrick const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl();
747e5dd7070Spatrick
748e5dd7070Spatrick if (IVar)
749e5dd7070Spatrick return IVar;
750e5dd7070Spatrick
751e5dd7070Spatrick // When a readonly property is shadowed in a class extensions with a
752e5dd7070Spatrick // a readwrite property, the instance variable belongs to the shadowing
753e5dd7070Spatrick // property rather than the shadowed property. If there is no instance
754e5dd7070Spatrick // variable on a readonly property, check to see whether the property is
755e5dd7070Spatrick // shadowed and if so try to get the instance variable from shadowing
756e5dd7070Spatrick // property.
757e5dd7070Spatrick if (!Prop->isReadOnly())
758e5dd7070Spatrick return nullptr;
759e5dd7070Spatrick
760e5dd7070Spatrick auto *Container = cast<ObjCContainerDecl>(Prop->getDeclContext());
761e5dd7070Spatrick const ObjCInterfaceDecl *PrimaryInterface = nullptr;
762e5dd7070Spatrick if (auto *InterfaceDecl = dyn_cast<ObjCInterfaceDecl>(Container)) {
763e5dd7070Spatrick PrimaryInterface = InterfaceDecl;
764e5dd7070Spatrick } else if (auto *CategoryDecl = dyn_cast<ObjCCategoryDecl>(Container)) {
765e5dd7070Spatrick PrimaryInterface = CategoryDecl->getClassInterface();
766e5dd7070Spatrick } else if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container)) {
767e5dd7070Spatrick PrimaryInterface = ImplDecl->getClassInterface();
768e5dd7070Spatrick } else {
769e5dd7070Spatrick return nullptr;
770e5dd7070Spatrick }
771e5dd7070Spatrick
772e5dd7070Spatrick // FindPropertyVisibleInPrimaryClass() looks first in class extensions, so it
773e5dd7070Spatrick // is guaranteed to find the shadowing property, if it exists, rather than
774e5dd7070Spatrick // the shadowed property.
775e5dd7070Spatrick auto *ShadowingProp = PrimaryInterface->FindPropertyVisibleInPrimaryClass(
776e5dd7070Spatrick Prop->getIdentifier(), Prop->getQueryKind());
777e5dd7070Spatrick if (ShadowingProp && ShadowingProp != Prop) {
778e5dd7070Spatrick IVar = ShadowingProp->getPropertyIvarDecl();
779e5dd7070Spatrick }
780e5dd7070Spatrick
781e5dd7070Spatrick return IVar;
782e5dd7070Spatrick }
783e5dd7070Spatrick
createObjCPropertyGetter(ASTContext & Ctx,const ObjCMethodDecl * MD)784e5dd7070Spatrick static Stmt *createObjCPropertyGetter(ASTContext &Ctx,
785e5dd7070Spatrick const ObjCMethodDecl *MD) {
786e5dd7070Spatrick // First, find the backing ivar.
787e5dd7070Spatrick const ObjCIvarDecl *IVar = nullptr;
788a9ac8606Spatrick const ObjCPropertyDecl *Prop = nullptr;
789e5dd7070Spatrick
790e5dd7070Spatrick // Property accessor stubs sometimes do not correspond to any property decl
791e5dd7070Spatrick // in the current interface (but in a superclass). They still have a
792e5dd7070Spatrick // corresponding property impl decl in this case.
793e5dd7070Spatrick if (MD->isSynthesizedAccessorStub()) {
794e5dd7070Spatrick const ObjCInterfaceDecl *IntD = MD->getClassInterface();
795e5dd7070Spatrick const ObjCImplementationDecl *ImpD = IntD->getImplementation();
796e5dd7070Spatrick for (const auto *PI : ImpD->property_impls()) {
797a9ac8606Spatrick if (const ObjCPropertyDecl *Candidate = PI->getPropertyDecl()) {
798a9ac8606Spatrick if (Candidate->getGetterName() == MD->getSelector()) {
799a9ac8606Spatrick Prop = Candidate;
800a9ac8606Spatrick IVar = Prop->getPropertyIvarDecl();
801a9ac8606Spatrick }
802e5dd7070Spatrick }
803e5dd7070Spatrick }
804e5dd7070Spatrick }
805e5dd7070Spatrick
806e5dd7070Spatrick if (!IVar) {
807a9ac8606Spatrick Prop = MD->findPropertyDecl();
808e5dd7070Spatrick IVar = findBackingIvar(Prop);
809a9ac8606Spatrick }
810a9ac8606Spatrick
811a9ac8606Spatrick if (!IVar || !Prop)
812e5dd7070Spatrick return nullptr;
813e5dd7070Spatrick
814e5dd7070Spatrick // Ignore weak variables, which have special behavior.
815ec727ea7Spatrick if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak)
816e5dd7070Spatrick return nullptr;
817e5dd7070Spatrick
818e5dd7070Spatrick // Look to see if Sema has synthesized a body for us. This happens in
819e5dd7070Spatrick // Objective-C++ because the return value may be a C++ class type with a
820e5dd7070Spatrick // non-trivial copy constructor. We can only do this if we can find the
821e5dd7070Spatrick // @synthesize for this property, though (or if we know it's been auto-
822e5dd7070Spatrick // synthesized).
823e5dd7070Spatrick const ObjCImplementationDecl *ImplDecl =
824e5dd7070Spatrick IVar->getContainingInterface()->getImplementation();
825e5dd7070Spatrick if (ImplDecl) {
826e5dd7070Spatrick for (const auto *I : ImplDecl->property_impls()) {
827e5dd7070Spatrick if (I->getPropertyDecl() != Prop)
828e5dd7070Spatrick continue;
829e5dd7070Spatrick
830e5dd7070Spatrick if (I->getGetterCXXConstructor()) {
831e5dd7070Spatrick ASTMaker M(Ctx);
832e5dd7070Spatrick return M.makeReturn(I->getGetterCXXConstructor());
833e5dd7070Spatrick }
834e5dd7070Spatrick }
835e5dd7070Spatrick }
836e5dd7070Spatrick
837*12c85518Srobert // We expect that the property is the same type as the ivar, or a reference to
838*12c85518Srobert // it, and that it is either an object pointer or trivially copyable.
839e5dd7070Spatrick if (!Ctx.hasSameUnqualifiedType(IVar->getType(),
840e5dd7070Spatrick Prop->getType().getNonReferenceType()))
841e5dd7070Spatrick return nullptr;
842e5dd7070Spatrick if (!IVar->getType()->isObjCLifetimeType() &&
843e5dd7070Spatrick !IVar->getType().isTriviallyCopyableType(Ctx))
844e5dd7070Spatrick return nullptr;
845e5dd7070Spatrick
846e5dd7070Spatrick // Generate our body:
847e5dd7070Spatrick // return self->_ivar;
848e5dd7070Spatrick ASTMaker M(Ctx);
849e5dd7070Spatrick
850e5dd7070Spatrick const VarDecl *selfVar = MD->getSelfDecl();
851e5dd7070Spatrick if (!selfVar)
852e5dd7070Spatrick return nullptr;
853e5dd7070Spatrick
854a9ac8606Spatrick Expr *loadedIVar = M.makeObjCIvarRef(
855a9ac8606Spatrick M.makeLvalueToRvalue(M.makeDeclRefExpr(selfVar), selfVar->getType()),
856e5dd7070Spatrick IVar);
857e5dd7070Spatrick
858e5dd7070Spatrick if (!MD->getReturnType()->isReferenceType())
859e5dd7070Spatrick loadedIVar = M.makeLvalueToRvalue(loadedIVar, IVar->getType());
860e5dd7070Spatrick
861e5dd7070Spatrick return M.makeReturn(loadedIVar);
862e5dd7070Spatrick }
863e5dd7070Spatrick
getBody(const ObjCMethodDecl * D)864e5dd7070Spatrick Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
865e5dd7070Spatrick // We currently only know how to synthesize property accessors.
866e5dd7070Spatrick if (!D->isPropertyAccessor())
867e5dd7070Spatrick return nullptr;
868e5dd7070Spatrick
869e5dd7070Spatrick D = D->getCanonicalDecl();
870e5dd7070Spatrick
871e5dd7070Spatrick // We should not try to synthesize explicitly redefined accessors.
872e5dd7070Spatrick // We do not know for sure how they behave.
873e5dd7070Spatrick if (!D->isImplicit())
874e5dd7070Spatrick return nullptr;
875e5dd7070Spatrick
876*12c85518Srobert std::optional<Stmt *> &Val = Bodies[D];
877*12c85518Srobert if (Val)
878*12c85518Srobert return *Val;
879e5dd7070Spatrick Val = nullptr;
880e5dd7070Spatrick
881e5dd7070Spatrick // For now, we only synthesize getters.
882e5dd7070Spatrick // Synthesizing setters would cause false negatives in the
883e5dd7070Spatrick // RetainCountChecker because the method body would bind the parameter
884e5dd7070Spatrick // to an instance variable, causing it to escape. This would prevent
885e5dd7070Spatrick // warning in the following common scenario:
886e5dd7070Spatrick //
887e5dd7070Spatrick // id foo = [[NSObject alloc] init];
888e5dd7070Spatrick // self.foo = foo; // We should warn that foo leaks here.
889e5dd7070Spatrick //
890e5dd7070Spatrick if (D->param_size() != 0)
891e5dd7070Spatrick return nullptr;
892e5dd7070Spatrick
893e5dd7070Spatrick // If the property was defined in an extension, search the extensions for
894e5dd7070Spatrick // overrides.
895e5dd7070Spatrick const ObjCInterfaceDecl *OID = D->getClassInterface();
896e5dd7070Spatrick if (dyn_cast<ObjCInterfaceDecl>(D->getParent()) != OID)
897e5dd7070Spatrick for (auto *Ext : OID->known_extensions()) {
898e5dd7070Spatrick auto *OMD = Ext->getInstanceMethod(D->getSelector());
899e5dd7070Spatrick if (OMD && !OMD->isImplicit())
900e5dd7070Spatrick return nullptr;
901e5dd7070Spatrick }
902e5dd7070Spatrick
903e5dd7070Spatrick Val = createObjCPropertyGetter(C, D);
904e5dd7070Spatrick
905*12c85518Srobert return *Val;
906e5dd7070Spatrick }
907