xref: /openbsd-src/gnu/llvm/clang/lib/Analysis/BodyFarm.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
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