xref: /freebsd/contrib/llvm-project/clang/lib/Analysis/BodyFarm.cpp (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
10b57cec5SDimitry Andric //== BodyFarm.cpp  - Factory for conjuring up fake bodies ----------*- C++ -*-//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // BodyFarm is a factory for creating faux implementations for functions/methods
100b57cec5SDimitry Andric // for analysis purposes.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "clang/Analysis/BodyFarm.h"
150b57cec5SDimitry Andric #include "clang/AST/ASTContext.h"
160b57cec5SDimitry Andric #include "clang/AST/CXXInheritance.h"
170b57cec5SDimitry Andric #include "clang/AST/Decl.h"
180b57cec5SDimitry Andric #include "clang/AST/Expr.h"
190b57cec5SDimitry Andric #include "clang/AST/ExprCXX.h"
200b57cec5SDimitry Andric #include "clang/AST/ExprObjC.h"
210b57cec5SDimitry Andric #include "clang/AST/NestedNameSpecifier.h"
220b57cec5SDimitry Andric #include "clang/Analysis/CodeInjector.h"
230b57cec5SDimitry Andric #include "clang/Basic/OperatorKinds.h"
240b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
250b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric #define DEBUG_TYPE "body-farm"
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric using namespace clang;
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
320b57cec5SDimitry Andric // Helper creation functions for constructing faux ASTs.
330b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric static bool isDispatchBlock(QualType Ty) {
360b57cec5SDimitry Andric   // Is it a block pointer?
370b57cec5SDimitry Andric   const BlockPointerType *BPT = Ty->getAs<BlockPointerType>();
380b57cec5SDimitry Andric   if (!BPT)
390b57cec5SDimitry Andric     return false;
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric   // Check if the block pointer type takes no arguments and
420b57cec5SDimitry Andric   // returns void.
430b57cec5SDimitry Andric   const FunctionProtoType *FT =
440b57cec5SDimitry Andric   BPT->getPointeeType()->getAs<FunctionProtoType>();
450b57cec5SDimitry Andric   return FT && FT->getReturnType()->isVoidType() && FT->getNumParams() == 0;
460b57cec5SDimitry Andric }
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric namespace {
490b57cec5SDimitry Andric class ASTMaker {
500b57cec5SDimitry Andric public:
510b57cec5SDimitry Andric   ASTMaker(ASTContext &C) : C(C) {}
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric   /// Create a new BinaryOperator representing a simple assignment.
540b57cec5SDimitry Andric   BinaryOperator *makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty);
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric   /// Create a new BinaryOperator representing a comparison.
570b57cec5SDimitry Andric   BinaryOperator *makeComparison(const Expr *LHS, const Expr *RHS,
580b57cec5SDimitry Andric                                  BinaryOperator::Opcode Op);
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   /// Create a new compound stmt using the provided statements.
610b57cec5SDimitry Andric   CompoundStmt *makeCompound(ArrayRef<Stmt*>);
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric   /// Create a new DeclRefExpr for the referenced variable.
640b57cec5SDimitry Andric   DeclRefExpr *makeDeclRefExpr(const VarDecl *D,
650b57cec5SDimitry Andric                                bool RefersToEnclosingVariableOrCapture = false);
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   /// Create a new UnaryOperator representing a dereference.
680b57cec5SDimitry Andric   UnaryOperator *makeDereference(const Expr *Arg, QualType Ty);
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric   /// Create an implicit cast for an integer conversion.
710b57cec5SDimitry Andric   Expr *makeIntegralCast(const Expr *Arg, QualType Ty);
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   /// Create an implicit cast to a builtin boolean type.
740b57cec5SDimitry Andric   ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg);
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   /// Create an implicit cast for lvalue-to-rvaluate conversions.
770b57cec5SDimitry Andric   ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty);
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric   /// Make RValue out of variable declaration, creating a temporary
800b57cec5SDimitry Andric   /// DeclRefExpr in the process.
810b57cec5SDimitry Andric   ImplicitCastExpr *
820b57cec5SDimitry Andric   makeLvalueToRvalue(const VarDecl *Decl,
830b57cec5SDimitry Andric                      bool RefersToEnclosingVariableOrCapture = false);
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric   /// Create an implicit cast of the given type.
860b57cec5SDimitry Andric   ImplicitCastExpr *makeImplicitCast(const Expr *Arg, QualType Ty,
870b57cec5SDimitry Andric                                      CastKind CK = CK_LValueToRValue);
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   /// Create an Objective-C bool literal.
900b57cec5SDimitry Andric   ObjCBoolLiteralExpr *makeObjCBool(bool Val);
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   /// Create an Objective-C ivar reference.
930b57cec5SDimitry Andric   ObjCIvarRefExpr *makeObjCIvarRef(const Expr *Base, const ObjCIvarDecl *IVar);
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   /// Create a Return statement.
960b57cec5SDimitry Andric   ReturnStmt *makeReturn(const Expr *RetVal);
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   /// Create an integer literal expression of the given type.
990b57cec5SDimitry Andric   IntegerLiteral *makeIntegerLiteral(uint64_t Value, QualType Ty);
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   /// Create a member expression.
1020b57cec5SDimitry Andric   MemberExpr *makeMemberExpression(Expr *base, ValueDecl *MemberDecl,
1030b57cec5SDimitry Andric                                    bool IsArrow = false,
1040b57cec5SDimitry Andric                                    ExprValueKind ValueKind = VK_LValue);
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   /// Returns a *first* member field of a record declaration with a given name.
1070b57cec5SDimitry Andric   /// \return an nullptr if no member with such a name exists.
1080b57cec5SDimitry Andric   ValueDecl *findMemberField(const RecordDecl *RD, StringRef Name);
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric private:
1110b57cec5SDimitry Andric   ASTContext &C;
1120b57cec5SDimitry Andric };
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS,
1160b57cec5SDimitry Andric                                          QualType Ty) {
1175ffd83dbSDimitry Andric   return BinaryOperator::Create(
1185ffd83dbSDimitry Andric       C, const_cast<Expr *>(LHS), const_cast<Expr *>(RHS), BO_Assign, Ty,
1195ffd83dbSDimitry Andric       VK_RValue, OK_Ordinary, SourceLocation(), FPOptionsOverride());
1200b57cec5SDimitry Andric }
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,
1230b57cec5SDimitry Andric                                          BinaryOperator::Opcode Op) {
1240b57cec5SDimitry Andric   assert(BinaryOperator::isLogicalOp(Op) ||
1250b57cec5SDimitry Andric          BinaryOperator::isComparisonOp(Op));
1265ffd83dbSDimitry Andric   return BinaryOperator::Create(
1275ffd83dbSDimitry Andric       C, const_cast<Expr *>(LHS), const_cast<Expr *>(RHS), Op,
1285ffd83dbSDimitry Andric       C.getLogicalOperationType(), VK_RValue, OK_Ordinary, SourceLocation(),
1295ffd83dbSDimitry Andric       FPOptionsOverride());
1300b57cec5SDimitry Andric }
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {
1330b57cec5SDimitry Andric   return CompoundStmt::Create(C, Stmts, SourceLocation(), SourceLocation());
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric DeclRefExpr *ASTMaker::makeDeclRefExpr(
1370b57cec5SDimitry Andric     const VarDecl *D,
1380b57cec5SDimitry Andric     bool RefersToEnclosingVariableOrCapture) {
1390b57cec5SDimitry Andric   QualType Type = D->getType().getNonReferenceType();
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   DeclRefExpr *DR = DeclRefExpr::Create(
1420b57cec5SDimitry Andric       C, NestedNameSpecifierLoc(), SourceLocation(), const_cast<VarDecl *>(D),
1430b57cec5SDimitry Andric       RefersToEnclosingVariableOrCapture, SourceLocation(), Type, VK_LValue);
1440b57cec5SDimitry Andric   return DR;
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {
1485ffd83dbSDimitry Andric   return UnaryOperator::Create(C, const_cast<Expr *>(Arg), UO_Deref, Ty,
1490b57cec5SDimitry Andric                                VK_LValue, OK_Ordinary, SourceLocation(),
1505ffd83dbSDimitry Andric                                /*CanOverflow*/ false, FPOptionsOverride());
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
1540b57cec5SDimitry Andric   return makeImplicitCast(Arg, Ty, CK_LValueToRValue);
1550b57cec5SDimitry Andric }
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric ImplicitCastExpr *
1580b57cec5SDimitry Andric ASTMaker::makeLvalueToRvalue(const VarDecl *Arg,
1590b57cec5SDimitry Andric                              bool RefersToEnclosingVariableOrCapture) {
1600b57cec5SDimitry Andric   QualType Type = Arg->getType().getNonReferenceType();
1610b57cec5SDimitry Andric   return makeLvalueToRvalue(makeDeclRefExpr(Arg,
1620b57cec5SDimitry Andric                                             RefersToEnclosingVariableOrCapture),
1630b57cec5SDimitry Andric                             Type);
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric ImplicitCastExpr *ASTMaker::makeImplicitCast(const Expr *Arg, QualType Ty,
1670b57cec5SDimitry Andric                                              CastKind CK) {
1680b57cec5SDimitry Andric   return ImplicitCastExpr::Create(C, Ty,
1690b57cec5SDimitry Andric                                   /* CastKind=*/CK,
1700b57cec5SDimitry Andric                                   /* Expr=*/const_cast<Expr *>(Arg),
1710b57cec5SDimitry Andric                                   /* CXXCastPath=*/nullptr,
172*e8d8bef9SDimitry Andric                                   /* ExprValueKind=*/VK_RValue,
173*e8d8bef9SDimitry Andric                                   /* FPFeatures */ FPOptionsOverride());
1740b57cec5SDimitry Andric }
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
1770b57cec5SDimitry Andric   if (Arg->getType() == Ty)
1780b57cec5SDimitry Andric     return const_cast<Expr*>(Arg);
179*e8d8bef9SDimitry Andric   return makeImplicitCast(Arg, Ty, CK_IntegralCast);
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) {
183*e8d8bef9SDimitry Andric   return makeImplicitCast(Arg, C.BoolTy, CK_IntegralToBoolean);
1840b57cec5SDimitry Andric }
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) {
1870b57cec5SDimitry Andric   QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy;
1880b57cec5SDimitry Andric   return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation());
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric ObjCIvarRefExpr *ASTMaker::makeObjCIvarRef(const Expr *Base,
1920b57cec5SDimitry Andric                                            const ObjCIvarDecl *IVar) {
1930b57cec5SDimitry Andric   return new (C) ObjCIvarRefExpr(const_cast<ObjCIvarDecl*>(IVar),
1940b57cec5SDimitry Andric                                  IVar->getType(), SourceLocation(),
1950b57cec5SDimitry Andric                                  SourceLocation(), const_cast<Expr*>(Base),
1960b57cec5SDimitry Andric                                  /*arrow=*/true, /*free=*/false);
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) {
2000b57cec5SDimitry Andric   return ReturnStmt::Create(C, SourceLocation(), const_cast<Expr *>(RetVal),
2010b57cec5SDimitry Andric                             /* NRVOCandidate=*/nullptr);
2020b57cec5SDimitry Andric }
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric IntegerLiteral *ASTMaker::makeIntegerLiteral(uint64_t Value, QualType Ty) {
2050b57cec5SDimitry Andric   llvm::APInt APValue = llvm::APInt(C.getTypeSize(Ty), Value);
2060b57cec5SDimitry Andric   return IntegerLiteral::Create(C, APValue, Ty, SourceLocation());
2070b57cec5SDimitry Andric }
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric MemberExpr *ASTMaker::makeMemberExpression(Expr *base, ValueDecl *MemberDecl,
2100b57cec5SDimitry Andric                                            bool IsArrow,
2110b57cec5SDimitry Andric                                            ExprValueKind ValueKind) {
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric   DeclAccessPair FoundDecl = DeclAccessPair::make(MemberDecl, AS_public);
2140b57cec5SDimitry Andric   return MemberExpr::Create(
2150b57cec5SDimitry Andric       C, base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(),
2160b57cec5SDimitry Andric       SourceLocation(), MemberDecl, FoundDecl,
2170b57cec5SDimitry Andric       DeclarationNameInfo(MemberDecl->getDeclName(), SourceLocation()),
2180b57cec5SDimitry Andric       /* TemplateArgumentListInfo=*/ nullptr, MemberDecl->getType(), ValueKind,
2190b57cec5SDimitry Andric       OK_Ordinary, NOUR_None);
2200b57cec5SDimitry Andric }
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric ValueDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) {
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric   CXXBasePaths Paths(
2250b57cec5SDimitry Andric       /* FindAmbiguities=*/false,
2260b57cec5SDimitry Andric       /* RecordPaths=*/false,
2270b57cec5SDimitry Andric       /* DetectVirtual=*/ false);
2280b57cec5SDimitry Andric   const IdentifierInfo &II = C.Idents.get(Name);
2290b57cec5SDimitry Andric   DeclarationName DeclName = C.DeclarationNames.getIdentifier(&II);
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric   DeclContextLookupResult Decls = RD->lookup(DeclName);
2320b57cec5SDimitry Andric   for (NamedDecl *FoundDecl : Decls)
2330b57cec5SDimitry Andric     if (!FoundDecl->getDeclContext()->isFunctionOrMethod())
2340b57cec5SDimitry Andric       return cast<ValueDecl>(FoundDecl);
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric   return nullptr;
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2400b57cec5SDimitry Andric // Creation functions for faux ASTs.
2410b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2420b57cec5SDimitry Andric 
2430b57cec5SDimitry Andric typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric static CallExpr *create_call_once_funcptr_call(ASTContext &C, ASTMaker M,
2460b57cec5SDimitry Andric                                                const ParmVarDecl *Callback,
2470b57cec5SDimitry Andric                                                ArrayRef<Expr *> CallArgs) {
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric   QualType Ty = Callback->getType();
2500b57cec5SDimitry Andric   DeclRefExpr *Call = M.makeDeclRefExpr(Callback);
2510b57cec5SDimitry Andric   Expr *SubExpr;
2520b57cec5SDimitry Andric   if (Ty->isRValueReferenceType()) {
2530b57cec5SDimitry Andric     SubExpr = M.makeImplicitCast(
2540b57cec5SDimitry Andric         Call, Ty.getNonReferenceType(), CK_LValueToRValue);
2550b57cec5SDimitry Andric   } else if (Ty->isLValueReferenceType() &&
2560b57cec5SDimitry Andric              Call->getType()->isFunctionType()) {
2570b57cec5SDimitry Andric     Ty = C.getPointerType(Ty.getNonReferenceType());
2580b57cec5SDimitry Andric     SubExpr = M.makeImplicitCast(Call, Ty, CK_FunctionToPointerDecay);
2590b57cec5SDimitry Andric   } else if (Ty->isLValueReferenceType()
2600b57cec5SDimitry Andric              && Call->getType()->isPointerType()
2610b57cec5SDimitry Andric              && Call->getType()->getPointeeType()->isFunctionType()){
2620b57cec5SDimitry Andric     SubExpr = Call;
2630b57cec5SDimitry Andric   } else {
2640b57cec5SDimitry Andric     llvm_unreachable("Unexpected state");
2650b57cec5SDimitry Andric   }
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric   return CallExpr::Create(C, SubExpr, CallArgs, C.VoidTy, VK_RValue,
268*e8d8bef9SDimitry Andric                           SourceLocation(), FPOptionsOverride());
2690b57cec5SDimitry Andric }
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M,
2720b57cec5SDimitry Andric                                               const ParmVarDecl *Callback,
2730b57cec5SDimitry Andric                                               CXXRecordDecl *CallbackDecl,
2740b57cec5SDimitry Andric                                               ArrayRef<Expr *> CallArgs) {
2750b57cec5SDimitry Andric   assert(CallbackDecl != nullptr);
2760b57cec5SDimitry Andric   assert(CallbackDecl->isLambda());
2770b57cec5SDimitry Andric   FunctionDecl *callOperatorDecl = CallbackDecl->getLambdaCallOperator();
2780b57cec5SDimitry Andric   assert(callOperatorDecl != nullptr);
2790b57cec5SDimitry Andric 
2800b57cec5SDimitry Andric   DeclRefExpr *callOperatorDeclRef =
2810b57cec5SDimitry Andric       DeclRefExpr::Create(/* Ctx =*/ C,
2820b57cec5SDimitry Andric                           /* QualifierLoc =*/ NestedNameSpecifierLoc(),
2830b57cec5SDimitry Andric                           /* TemplateKWLoc =*/ SourceLocation(),
2840b57cec5SDimitry Andric                           const_cast<FunctionDecl *>(callOperatorDecl),
2850b57cec5SDimitry Andric                           /* RefersToEnclosingVariableOrCapture=*/ false,
2860b57cec5SDimitry Andric                           /* NameLoc =*/ SourceLocation(),
2870b57cec5SDimitry Andric                           /* T =*/ callOperatorDecl->getType(),
2880b57cec5SDimitry Andric                           /* VK =*/ VK_LValue);
2890b57cec5SDimitry Andric 
2900b57cec5SDimitry Andric   return CXXOperatorCallExpr::Create(
2910b57cec5SDimitry Andric       /*AstContext=*/C, OO_Call, callOperatorDeclRef,
2920b57cec5SDimitry Andric       /*Args=*/CallArgs,
2930b57cec5SDimitry Andric       /*QualType=*/C.VoidTy,
2940b57cec5SDimitry Andric       /*ExprValueType=*/VK_RValue,
2955ffd83dbSDimitry Andric       /*SourceLocation=*/SourceLocation(),
2965ffd83dbSDimitry Andric       /*FPFeatures=*/FPOptionsOverride());
2970b57cec5SDimitry Andric }
2980b57cec5SDimitry Andric 
2990b57cec5SDimitry Andric /// Create a fake body for std::call_once.
3000b57cec5SDimitry Andric /// Emulates the following function body:
3010b57cec5SDimitry Andric ///
3020b57cec5SDimitry Andric /// \code
3030b57cec5SDimitry Andric /// typedef struct once_flag_s {
3040b57cec5SDimitry Andric ///   unsigned long __state = 0;
3050b57cec5SDimitry Andric /// } once_flag;
3060b57cec5SDimitry Andric /// template<class Callable>
3070b57cec5SDimitry Andric /// void call_once(once_flag& o, Callable func) {
3080b57cec5SDimitry Andric ///   if (!o.__state) {
3090b57cec5SDimitry Andric ///     func();
3100b57cec5SDimitry Andric ///   }
3110b57cec5SDimitry Andric ///   o.__state = 1;
3120b57cec5SDimitry Andric /// }
3130b57cec5SDimitry Andric /// \endcode
3140b57cec5SDimitry Andric static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) {
3150b57cec5SDimitry Andric   LLVM_DEBUG(llvm::dbgs() << "Generating body for call_once\n");
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric   // We need at least two parameters.
3180b57cec5SDimitry Andric   if (D->param_size() < 2)
3190b57cec5SDimitry Andric     return nullptr;
3200b57cec5SDimitry Andric 
3210b57cec5SDimitry Andric   ASTMaker M(C);
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric   const ParmVarDecl *Flag = D->getParamDecl(0);
3240b57cec5SDimitry Andric   const ParmVarDecl *Callback = D->getParamDecl(1);
3250b57cec5SDimitry Andric 
3260b57cec5SDimitry Andric   if (!Callback->getType()->isReferenceType()) {
3270b57cec5SDimitry Andric     llvm::dbgs() << "libcxx03 std::call_once implementation, skipping.\n";
3280b57cec5SDimitry Andric     return nullptr;
3290b57cec5SDimitry Andric   }
3300b57cec5SDimitry Andric   if (!Flag->getType()->isReferenceType()) {
3310b57cec5SDimitry Andric     llvm::dbgs() << "unknown std::call_once implementation, skipping.\n";
3320b57cec5SDimitry Andric     return nullptr;
3330b57cec5SDimitry Andric   }
3340b57cec5SDimitry Andric 
3350b57cec5SDimitry Andric   QualType CallbackType = Callback->getType().getNonReferenceType();
3360b57cec5SDimitry Andric 
3370b57cec5SDimitry Andric   // Nullable pointer, non-null iff function is a CXXRecordDecl.
3380b57cec5SDimitry Andric   CXXRecordDecl *CallbackRecordDecl = CallbackType->getAsCXXRecordDecl();
3390b57cec5SDimitry Andric   QualType FlagType = Flag->getType().getNonReferenceType();
3400b57cec5SDimitry Andric   auto *FlagRecordDecl = FlagType->getAsRecordDecl();
3410b57cec5SDimitry Andric 
3420b57cec5SDimitry Andric   if (!FlagRecordDecl) {
3430b57cec5SDimitry Andric     LLVM_DEBUG(llvm::dbgs() << "Flag field is not a record: "
3440b57cec5SDimitry Andric                             << "unknown std::call_once implementation, "
3450b57cec5SDimitry Andric                             << "ignoring the call.\n");
3460b57cec5SDimitry Andric     return nullptr;
3470b57cec5SDimitry Andric   }
3480b57cec5SDimitry Andric 
3490b57cec5SDimitry Andric   // We initially assume libc++ implementation of call_once,
3500b57cec5SDimitry Andric   // where the once_flag struct has a field `__state_`.
3510b57cec5SDimitry Andric   ValueDecl *FlagFieldDecl = M.findMemberField(FlagRecordDecl, "__state_");
3520b57cec5SDimitry Andric 
3530b57cec5SDimitry Andric   // Otherwise, try libstdc++ implementation, with a field
3540b57cec5SDimitry Andric   // `_M_once`
3550b57cec5SDimitry Andric   if (!FlagFieldDecl) {
3560b57cec5SDimitry Andric     FlagFieldDecl = M.findMemberField(FlagRecordDecl, "_M_once");
3570b57cec5SDimitry Andric   }
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric   if (!FlagFieldDecl) {
3600b57cec5SDimitry Andric     LLVM_DEBUG(llvm::dbgs() << "No field _M_once or __state_ found on "
3610b57cec5SDimitry Andric                             << "std::once_flag struct: unknown std::call_once "
3620b57cec5SDimitry Andric                             << "implementation, ignoring the call.");
3630b57cec5SDimitry Andric     return nullptr;
3640b57cec5SDimitry Andric   }
3650b57cec5SDimitry Andric 
3660b57cec5SDimitry Andric   bool isLambdaCall = CallbackRecordDecl && CallbackRecordDecl->isLambda();
3670b57cec5SDimitry Andric   if (CallbackRecordDecl && !isLambdaCall) {
3680b57cec5SDimitry Andric     LLVM_DEBUG(llvm::dbgs()
3690b57cec5SDimitry Andric                << "Not supported: synthesizing body for functors when "
3700b57cec5SDimitry Andric                << "body farming std::call_once, ignoring the call.");
3710b57cec5SDimitry Andric     return nullptr;
3720b57cec5SDimitry Andric   }
3730b57cec5SDimitry Andric 
3740b57cec5SDimitry Andric   SmallVector<Expr *, 5> CallArgs;
3750b57cec5SDimitry Andric   const FunctionProtoType *CallbackFunctionType;
3760b57cec5SDimitry Andric   if (isLambdaCall) {
3770b57cec5SDimitry Andric 
3780b57cec5SDimitry Andric     // Lambda requires callback itself inserted as a first parameter.
3790b57cec5SDimitry Andric     CallArgs.push_back(
3800b57cec5SDimitry Andric         M.makeDeclRefExpr(Callback,
3810b57cec5SDimitry Andric                           /* RefersToEnclosingVariableOrCapture=*/ true));
3820b57cec5SDimitry Andric     CallbackFunctionType = CallbackRecordDecl->getLambdaCallOperator()
3830b57cec5SDimitry Andric                                ->getType()
3840b57cec5SDimitry Andric                                ->getAs<FunctionProtoType>();
3850b57cec5SDimitry Andric   } else if (!CallbackType->getPointeeType().isNull()) {
3860b57cec5SDimitry Andric     CallbackFunctionType =
3870b57cec5SDimitry Andric         CallbackType->getPointeeType()->getAs<FunctionProtoType>();
3880b57cec5SDimitry Andric   } else {
3890b57cec5SDimitry Andric     CallbackFunctionType = CallbackType->getAs<FunctionProtoType>();
3900b57cec5SDimitry Andric   }
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric   if (!CallbackFunctionType)
3930b57cec5SDimitry Andric     return nullptr;
3940b57cec5SDimitry Andric 
3950b57cec5SDimitry Andric   // First two arguments are used for the flag and for the callback.
3960b57cec5SDimitry Andric   if (D->getNumParams() != CallbackFunctionType->getNumParams() + 2) {
3970b57cec5SDimitry Andric     LLVM_DEBUG(llvm::dbgs() << "Types of params of the callback do not match "
3980b57cec5SDimitry Andric                             << "params passed to std::call_once, "
3990b57cec5SDimitry Andric                             << "ignoring the call\n");
4000b57cec5SDimitry Andric     return nullptr;
4010b57cec5SDimitry Andric   }
4020b57cec5SDimitry Andric 
4030b57cec5SDimitry Andric   // All arguments past first two ones are passed to the callback,
4040b57cec5SDimitry Andric   // and we turn lvalues into rvalues if the argument is not passed by
4050b57cec5SDimitry Andric   // reference.
4060b57cec5SDimitry Andric   for (unsigned int ParamIdx = 2; ParamIdx < D->getNumParams(); ParamIdx++) {
4070b57cec5SDimitry Andric     const ParmVarDecl *PDecl = D->getParamDecl(ParamIdx);
408a7dea167SDimitry Andric     assert(PDecl);
409a7dea167SDimitry Andric     if (CallbackFunctionType->getParamType(ParamIdx - 2)
4100b57cec5SDimitry Andric                 .getNonReferenceType()
4110b57cec5SDimitry Andric                 .getCanonicalType() !=
4120b57cec5SDimitry Andric             PDecl->getType().getNonReferenceType().getCanonicalType()) {
4130b57cec5SDimitry Andric       LLVM_DEBUG(llvm::dbgs() << "Types of params of the callback do not match "
4140b57cec5SDimitry Andric                               << "params passed to std::call_once, "
4150b57cec5SDimitry Andric                               << "ignoring the call\n");
4160b57cec5SDimitry Andric       return nullptr;
4170b57cec5SDimitry Andric     }
4180b57cec5SDimitry Andric     Expr *ParamExpr = M.makeDeclRefExpr(PDecl);
4190b57cec5SDimitry Andric     if (!CallbackFunctionType->getParamType(ParamIdx - 2)->isReferenceType()) {
4200b57cec5SDimitry Andric       QualType PTy = PDecl->getType().getNonReferenceType();
4210b57cec5SDimitry Andric       ParamExpr = M.makeLvalueToRvalue(ParamExpr, PTy);
4220b57cec5SDimitry Andric     }
4230b57cec5SDimitry Andric     CallArgs.push_back(ParamExpr);
4240b57cec5SDimitry Andric   }
4250b57cec5SDimitry Andric 
4260b57cec5SDimitry Andric   CallExpr *CallbackCall;
4270b57cec5SDimitry Andric   if (isLambdaCall) {
4280b57cec5SDimitry Andric 
4290b57cec5SDimitry Andric     CallbackCall = create_call_once_lambda_call(C, M, Callback,
4300b57cec5SDimitry Andric                                                 CallbackRecordDecl, CallArgs);
4310b57cec5SDimitry Andric   } else {
4320b57cec5SDimitry Andric 
4330b57cec5SDimitry Andric     // Function pointer case.
4340b57cec5SDimitry Andric     CallbackCall = create_call_once_funcptr_call(C, M, Callback, CallArgs);
4350b57cec5SDimitry Andric   }
4360b57cec5SDimitry Andric 
4370b57cec5SDimitry Andric   DeclRefExpr *FlagDecl =
4380b57cec5SDimitry Andric       M.makeDeclRefExpr(Flag,
4390b57cec5SDimitry Andric                         /* RefersToEnclosingVariableOrCapture=*/true);
4400b57cec5SDimitry Andric 
4410b57cec5SDimitry Andric 
4420b57cec5SDimitry Andric   MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FlagFieldDecl);
4430b57cec5SDimitry Andric   assert(Deref->isLValue());
4440b57cec5SDimitry Andric   QualType DerefType = Deref->getType();
4450b57cec5SDimitry Andric 
4460b57cec5SDimitry Andric   // Negation predicate.
4475ffd83dbSDimitry Andric   UnaryOperator *FlagCheck = UnaryOperator::Create(
4485ffd83dbSDimitry Andric       C,
4490b57cec5SDimitry Andric       /* input=*/
4500b57cec5SDimitry Andric       M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType,
4510b57cec5SDimitry Andric                          CK_IntegralToBoolean),
4520b57cec5SDimitry Andric       /* opc=*/UO_LNot,
4530b57cec5SDimitry Andric       /* QualType=*/C.IntTy,
4540b57cec5SDimitry Andric       /* ExprValueKind=*/VK_RValue,
4550b57cec5SDimitry Andric       /* ExprObjectKind=*/OK_Ordinary, SourceLocation(),
4565ffd83dbSDimitry Andric       /* CanOverflow*/ false, FPOptionsOverride());
4570b57cec5SDimitry Andric 
4580b57cec5SDimitry Andric   // Create assignment.
4590b57cec5SDimitry Andric   BinaryOperator *FlagAssignment = M.makeAssignment(
4600b57cec5SDimitry Andric       Deref, M.makeIntegralCast(M.makeIntegerLiteral(1, C.IntTy), DerefType),
4610b57cec5SDimitry Andric       DerefType);
4620b57cec5SDimitry Andric 
4630b57cec5SDimitry Andric   auto *Out =
4640b57cec5SDimitry Andric       IfStmt::Create(C, SourceLocation(),
4650b57cec5SDimitry Andric                      /* IsConstexpr=*/false,
4660b57cec5SDimitry Andric                      /* Init=*/nullptr,
4670b57cec5SDimitry Andric                      /* Var=*/nullptr,
4680b57cec5SDimitry Andric                      /* Cond=*/FlagCheck,
469*e8d8bef9SDimitry Andric                      /* LPL=*/SourceLocation(),
470*e8d8bef9SDimitry Andric                      /* RPL=*/SourceLocation(),
4710b57cec5SDimitry Andric                      /* Then=*/M.makeCompound({CallbackCall, FlagAssignment}));
4720b57cec5SDimitry Andric 
4730b57cec5SDimitry Andric   return Out;
4740b57cec5SDimitry Andric }
4750b57cec5SDimitry Andric 
4760b57cec5SDimitry Andric /// Create a fake body for dispatch_once.
4770b57cec5SDimitry Andric static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
4780b57cec5SDimitry Andric   // Check if we have at least two parameters.
4790b57cec5SDimitry Andric   if (D->param_size() != 2)
4800b57cec5SDimitry Andric     return nullptr;
4810b57cec5SDimitry Andric 
4820b57cec5SDimitry Andric   // Check if the first parameter is a pointer to integer type.
4830b57cec5SDimitry Andric   const ParmVarDecl *Predicate = D->getParamDecl(0);
4840b57cec5SDimitry Andric   QualType PredicateQPtrTy = Predicate->getType();
4850b57cec5SDimitry Andric   const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();
4860b57cec5SDimitry Andric   if (!PredicatePtrTy)
4870b57cec5SDimitry Andric     return nullptr;
4880b57cec5SDimitry Andric   QualType PredicateTy = PredicatePtrTy->getPointeeType();
4890b57cec5SDimitry Andric   if (!PredicateTy->isIntegerType())
4900b57cec5SDimitry Andric     return nullptr;
4910b57cec5SDimitry Andric 
4920b57cec5SDimitry Andric   // Check if the second parameter is the proper block type.
4930b57cec5SDimitry Andric   const ParmVarDecl *Block = D->getParamDecl(1);
4940b57cec5SDimitry Andric   QualType Ty = Block->getType();
4950b57cec5SDimitry Andric   if (!isDispatchBlock(Ty))
4960b57cec5SDimitry Andric     return nullptr;
4970b57cec5SDimitry Andric 
4980b57cec5SDimitry Andric   // Everything checks out.  Create a fakse body that checks the predicate,
4990b57cec5SDimitry Andric   // sets it, and calls the block.  Basically, an AST dump of:
5000b57cec5SDimitry Andric   //
5010b57cec5SDimitry Andric   // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
5020b57cec5SDimitry Andric   //  if (*predicate != ~0l) {
5030b57cec5SDimitry Andric   //    *predicate = ~0l;
5040b57cec5SDimitry Andric   //    block();
5050b57cec5SDimitry Andric   //  }
5060b57cec5SDimitry Andric   // }
5070b57cec5SDimitry Andric 
5080b57cec5SDimitry Andric   ASTMaker M(C);
5090b57cec5SDimitry Andric 
5100b57cec5SDimitry Andric   // (1) Create the call.
5110b57cec5SDimitry Andric   CallExpr *CE = CallExpr::Create(
5120b57cec5SDimitry Andric       /*ASTContext=*/C,
5130b57cec5SDimitry Andric       /*StmtClass=*/M.makeLvalueToRvalue(/*Expr=*/Block),
5140b57cec5SDimitry Andric       /*Args=*/None,
5150b57cec5SDimitry Andric       /*QualType=*/C.VoidTy,
5160b57cec5SDimitry Andric       /*ExprValueType=*/VK_RValue,
517*e8d8bef9SDimitry Andric       /*SourceLocation=*/SourceLocation(), FPOptionsOverride());
5180b57cec5SDimitry Andric 
5190b57cec5SDimitry Andric   // (2) Create the assignment to the predicate.
5200b57cec5SDimitry Andric   Expr *DoneValue =
5215ffd83dbSDimitry Andric       UnaryOperator::Create(C, M.makeIntegerLiteral(0, C.LongTy), UO_Not,
5225ffd83dbSDimitry Andric                             C.LongTy, VK_RValue, OK_Ordinary, SourceLocation(),
5235ffd83dbSDimitry Andric                             /*CanOverflow*/ false, FPOptionsOverride());
5240b57cec5SDimitry Andric 
5250b57cec5SDimitry Andric   BinaryOperator *B =
5260b57cec5SDimitry Andric     M.makeAssignment(
5270b57cec5SDimitry Andric        M.makeDereference(
5280b57cec5SDimitry Andric           M.makeLvalueToRvalue(
5290b57cec5SDimitry Andric             M.makeDeclRefExpr(Predicate), PredicateQPtrTy),
5300b57cec5SDimitry Andric             PredicateTy),
5310b57cec5SDimitry Andric        M.makeIntegralCast(DoneValue, PredicateTy),
5320b57cec5SDimitry Andric        PredicateTy);
5330b57cec5SDimitry Andric 
5340b57cec5SDimitry Andric   // (3) Create the compound statement.
5350b57cec5SDimitry Andric   Stmt *Stmts[] = { B, CE };
5360b57cec5SDimitry Andric   CompoundStmt *CS = M.makeCompound(Stmts);
5370b57cec5SDimitry Andric 
5380b57cec5SDimitry Andric   // (4) Create the 'if' condition.
5390b57cec5SDimitry Andric   ImplicitCastExpr *LValToRval =
5400b57cec5SDimitry Andric     M.makeLvalueToRvalue(
5410b57cec5SDimitry Andric       M.makeDereference(
5420b57cec5SDimitry Andric         M.makeLvalueToRvalue(
5430b57cec5SDimitry Andric           M.makeDeclRefExpr(Predicate),
5440b57cec5SDimitry Andric           PredicateQPtrTy),
5450b57cec5SDimitry Andric         PredicateTy),
5460b57cec5SDimitry Andric     PredicateTy);
5470b57cec5SDimitry Andric 
5480b57cec5SDimitry Andric   Expr *GuardCondition = M.makeComparison(LValToRval, DoneValue, BO_NE);
5490b57cec5SDimitry Andric   // (5) Create the 'if' statement.
5500b57cec5SDimitry Andric   auto *If = IfStmt::Create(C, SourceLocation(),
5510b57cec5SDimitry Andric                             /* IsConstexpr=*/false,
5520b57cec5SDimitry Andric                             /* Init=*/nullptr,
5530b57cec5SDimitry Andric                             /* Var=*/nullptr,
5540b57cec5SDimitry Andric                             /* Cond=*/GuardCondition,
555*e8d8bef9SDimitry Andric                             /* LPL=*/SourceLocation(),
556*e8d8bef9SDimitry Andric                             /* RPL=*/SourceLocation(),
5570b57cec5SDimitry Andric                             /* Then=*/CS);
5580b57cec5SDimitry Andric   return If;
5590b57cec5SDimitry Andric }
5600b57cec5SDimitry Andric 
5610b57cec5SDimitry Andric /// Create a fake body for dispatch_sync.
5620b57cec5SDimitry Andric static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
5630b57cec5SDimitry Andric   // Check if we have at least two parameters.
5640b57cec5SDimitry Andric   if (D->param_size() != 2)
5650b57cec5SDimitry Andric     return nullptr;
5660b57cec5SDimitry Andric 
5670b57cec5SDimitry Andric   // Check if the second parameter is a block.
5680b57cec5SDimitry Andric   const ParmVarDecl *PV = D->getParamDecl(1);
5690b57cec5SDimitry Andric   QualType Ty = PV->getType();
5700b57cec5SDimitry Andric   if (!isDispatchBlock(Ty))
5710b57cec5SDimitry Andric     return nullptr;
5720b57cec5SDimitry Andric 
5730b57cec5SDimitry Andric   // Everything checks out.  Create a fake body that just calls the block.
5740b57cec5SDimitry Andric   // This is basically just an AST dump of:
5750b57cec5SDimitry Andric   //
5760b57cec5SDimitry Andric   // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) {
5770b57cec5SDimitry Andric   //   block();
5780b57cec5SDimitry Andric   // }
5790b57cec5SDimitry Andric   //
5800b57cec5SDimitry Andric   ASTMaker M(C);
5810b57cec5SDimitry Andric   DeclRefExpr *DR = M.makeDeclRefExpr(PV);
5820b57cec5SDimitry Andric   ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
583*e8d8bef9SDimitry Andric   CallExpr *CE = CallExpr::Create(C, ICE, None, C.VoidTy, VK_RValue,
584*e8d8bef9SDimitry Andric                                   SourceLocation(), FPOptionsOverride());
5850b57cec5SDimitry Andric   return CE;
5860b57cec5SDimitry Andric }
5870b57cec5SDimitry Andric 
5880b57cec5SDimitry Andric static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
5890b57cec5SDimitry Andric {
5900b57cec5SDimitry Andric   // There are exactly 3 arguments.
5910b57cec5SDimitry Andric   if (D->param_size() != 3)
5920b57cec5SDimitry Andric     return nullptr;
5930b57cec5SDimitry Andric 
5940b57cec5SDimitry Andric   // Signature:
5950b57cec5SDimitry Andric   // _Bool OSAtomicCompareAndSwapPtr(void *__oldValue,
5960b57cec5SDimitry Andric   //                                 void *__newValue,
5970b57cec5SDimitry Andric   //                                 void * volatile *__theValue)
5980b57cec5SDimitry Andric   // Generate body:
5990b57cec5SDimitry Andric   //   if (oldValue == *theValue) {
6000b57cec5SDimitry Andric   //    *theValue = newValue;
6010b57cec5SDimitry Andric   //    return YES;
6020b57cec5SDimitry Andric   //   }
6030b57cec5SDimitry Andric   //   else return NO;
6040b57cec5SDimitry Andric 
6050b57cec5SDimitry Andric   QualType ResultTy = D->getReturnType();
6060b57cec5SDimitry Andric   bool isBoolean = ResultTy->isBooleanType();
6070b57cec5SDimitry Andric   if (!isBoolean && !ResultTy->isIntegralType(C))
6080b57cec5SDimitry Andric     return nullptr;
6090b57cec5SDimitry Andric 
6100b57cec5SDimitry Andric   const ParmVarDecl *OldValue = D->getParamDecl(0);
6110b57cec5SDimitry Andric   QualType OldValueTy = OldValue->getType();
6120b57cec5SDimitry Andric 
6130b57cec5SDimitry Andric   const ParmVarDecl *NewValue = D->getParamDecl(1);
6140b57cec5SDimitry Andric   QualType NewValueTy = NewValue->getType();
6150b57cec5SDimitry Andric 
6160b57cec5SDimitry Andric   assert(OldValueTy == NewValueTy);
6170b57cec5SDimitry Andric 
6180b57cec5SDimitry Andric   const ParmVarDecl *TheValue = D->getParamDecl(2);
6190b57cec5SDimitry Andric   QualType TheValueTy = TheValue->getType();
6200b57cec5SDimitry Andric   const PointerType *PT = TheValueTy->getAs<PointerType>();
6210b57cec5SDimitry Andric   if (!PT)
6220b57cec5SDimitry Andric     return nullptr;
6230b57cec5SDimitry Andric   QualType PointeeTy = PT->getPointeeType();
6240b57cec5SDimitry Andric 
6250b57cec5SDimitry Andric   ASTMaker M(C);
6260b57cec5SDimitry Andric   // Construct the comparison.
6270b57cec5SDimitry Andric   Expr *Comparison =
6280b57cec5SDimitry Andric     M.makeComparison(
6290b57cec5SDimitry Andric       M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy),
6300b57cec5SDimitry Andric       M.makeLvalueToRvalue(
6310b57cec5SDimitry Andric         M.makeDereference(
6320b57cec5SDimitry Andric           M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
6330b57cec5SDimitry Andric           PointeeTy),
6340b57cec5SDimitry Andric         PointeeTy),
6350b57cec5SDimitry Andric       BO_EQ);
6360b57cec5SDimitry Andric 
6370b57cec5SDimitry Andric   // Construct the body of the IfStmt.
6380b57cec5SDimitry Andric   Stmt *Stmts[2];
6390b57cec5SDimitry Andric   Stmts[0] =
6400b57cec5SDimitry Andric     M.makeAssignment(
6410b57cec5SDimitry Andric       M.makeDereference(
6420b57cec5SDimitry Andric         M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
6430b57cec5SDimitry Andric         PointeeTy),
6440b57cec5SDimitry Andric       M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy),
6450b57cec5SDimitry Andric       NewValueTy);
6460b57cec5SDimitry Andric 
6470b57cec5SDimitry Andric   Expr *BoolVal = M.makeObjCBool(true);
6480b57cec5SDimitry Andric   Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
6490b57cec5SDimitry Andric                            : M.makeIntegralCast(BoolVal, ResultTy);
6500b57cec5SDimitry Andric   Stmts[1] = M.makeReturn(RetVal);
6510b57cec5SDimitry Andric   CompoundStmt *Body = M.makeCompound(Stmts);
6520b57cec5SDimitry Andric 
6530b57cec5SDimitry Andric   // Construct the else clause.
6540b57cec5SDimitry Andric   BoolVal = M.makeObjCBool(false);
6550b57cec5SDimitry Andric   RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
6560b57cec5SDimitry Andric                      : M.makeIntegralCast(BoolVal, ResultTy);
6570b57cec5SDimitry Andric   Stmt *Else = M.makeReturn(RetVal);
6580b57cec5SDimitry Andric 
6590b57cec5SDimitry Andric   /// Construct the If.
660*e8d8bef9SDimitry Andric   auto *If =
661*e8d8bef9SDimitry Andric       IfStmt::Create(C, SourceLocation(),
6620b57cec5SDimitry Andric                      /* IsConstexpr=*/false,
6630b57cec5SDimitry Andric                      /* Init=*/nullptr,
664*e8d8bef9SDimitry Andric                      /* Var=*/nullptr, Comparison,
665*e8d8bef9SDimitry Andric                      /* LPL=*/SourceLocation(),
666*e8d8bef9SDimitry Andric                      /* RPL=*/SourceLocation(), Body, SourceLocation(), Else);
6670b57cec5SDimitry Andric 
6680b57cec5SDimitry Andric   return If;
6690b57cec5SDimitry Andric }
6700b57cec5SDimitry Andric 
6710b57cec5SDimitry Andric Stmt *BodyFarm::getBody(const FunctionDecl *D) {
6720b57cec5SDimitry Andric   Optional<Stmt *> &Val = Bodies[D];
6730b57cec5SDimitry Andric   if (Val.hasValue())
6740b57cec5SDimitry Andric     return Val.getValue();
6750b57cec5SDimitry Andric 
6760b57cec5SDimitry Andric   Val = nullptr;
6770b57cec5SDimitry Andric 
6780b57cec5SDimitry Andric   if (D->getIdentifier() == nullptr)
6790b57cec5SDimitry Andric     return nullptr;
6800b57cec5SDimitry Andric 
6810b57cec5SDimitry Andric   StringRef Name = D->getName();
6820b57cec5SDimitry Andric   if (Name.empty())
6830b57cec5SDimitry Andric     return nullptr;
6840b57cec5SDimitry Andric 
6850b57cec5SDimitry Andric   FunctionFarmer FF;
6860b57cec5SDimitry Andric 
6870b57cec5SDimitry Andric   if (Name.startswith("OSAtomicCompareAndSwap") ||
6880b57cec5SDimitry Andric       Name.startswith("objc_atomicCompareAndSwap")) {
6890b57cec5SDimitry Andric     FF = create_OSAtomicCompareAndSwap;
6900b57cec5SDimitry Andric   } else if (Name == "call_once" && D->getDeclContext()->isStdNamespace()) {
6910b57cec5SDimitry Andric     FF = create_call_once;
6920b57cec5SDimitry Andric   } else {
6930b57cec5SDimitry Andric     FF = llvm::StringSwitch<FunctionFarmer>(Name)
6940b57cec5SDimitry Andric           .Case("dispatch_sync", create_dispatch_sync)
6950b57cec5SDimitry Andric           .Case("dispatch_once", create_dispatch_once)
6960b57cec5SDimitry Andric           .Default(nullptr);
6970b57cec5SDimitry Andric   }
6980b57cec5SDimitry Andric 
6990b57cec5SDimitry Andric   if (FF) { Val = FF(C, D); }
7000b57cec5SDimitry Andric   else if (Injector) { Val = Injector->getBody(D); }
7010b57cec5SDimitry Andric   return Val.getValue();
7020b57cec5SDimitry Andric }
7030b57cec5SDimitry Andric 
7040b57cec5SDimitry Andric static const ObjCIvarDecl *findBackingIvar(const ObjCPropertyDecl *Prop) {
7050b57cec5SDimitry Andric   const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl();
7060b57cec5SDimitry Andric 
7070b57cec5SDimitry Andric   if (IVar)
7080b57cec5SDimitry Andric     return IVar;
7090b57cec5SDimitry Andric 
7100b57cec5SDimitry Andric   // When a readonly property is shadowed in a class extensions with a
7110b57cec5SDimitry Andric   // a readwrite property, the instance variable belongs to the shadowing
7120b57cec5SDimitry Andric   // property rather than the shadowed property. If there is no instance
7130b57cec5SDimitry Andric   // variable on a readonly property, check to see whether the property is
7140b57cec5SDimitry Andric   // shadowed and if so try to get the instance variable from shadowing
7150b57cec5SDimitry Andric   // property.
7160b57cec5SDimitry Andric   if (!Prop->isReadOnly())
7170b57cec5SDimitry Andric     return nullptr;
7180b57cec5SDimitry Andric 
7190b57cec5SDimitry Andric   auto *Container = cast<ObjCContainerDecl>(Prop->getDeclContext());
7200b57cec5SDimitry Andric   const ObjCInterfaceDecl *PrimaryInterface = nullptr;
7210b57cec5SDimitry Andric   if (auto *InterfaceDecl = dyn_cast<ObjCInterfaceDecl>(Container)) {
7220b57cec5SDimitry Andric     PrimaryInterface = InterfaceDecl;
7230b57cec5SDimitry Andric   } else if (auto *CategoryDecl = dyn_cast<ObjCCategoryDecl>(Container)) {
7240b57cec5SDimitry Andric     PrimaryInterface = CategoryDecl->getClassInterface();
7250b57cec5SDimitry Andric   } else if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container)) {
7260b57cec5SDimitry Andric     PrimaryInterface = ImplDecl->getClassInterface();
7270b57cec5SDimitry Andric   } else {
7280b57cec5SDimitry Andric     return nullptr;
7290b57cec5SDimitry Andric   }
7300b57cec5SDimitry Andric 
7310b57cec5SDimitry Andric   // FindPropertyVisibleInPrimaryClass() looks first in class extensions, so it
7320b57cec5SDimitry Andric   // is guaranteed to find the shadowing property, if it exists, rather than
7330b57cec5SDimitry Andric   // the shadowed property.
7340b57cec5SDimitry Andric   auto *ShadowingProp = PrimaryInterface->FindPropertyVisibleInPrimaryClass(
7350b57cec5SDimitry Andric       Prop->getIdentifier(), Prop->getQueryKind());
7360b57cec5SDimitry Andric   if (ShadowingProp && ShadowingProp != Prop) {
7370b57cec5SDimitry Andric     IVar = ShadowingProp->getPropertyIvarDecl();
7380b57cec5SDimitry Andric   }
7390b57cec5SDimitry Andric 
7400b57cec5SDimitry Andric   return IVar;
7410b57cec5SDimitry Andric }
7420b57cec5SDimitry Andric 
7430b57cec5SDimitry Andric static Stmt *createObjCPropertyGetter(ASTContext &Ctx,
744480093f4SDimitry Andric                                       const ObjCMethodDecl *MD) {
7450b57cec5SDimitry Andric     // First, find the backing ivar.
746480093f4SDimitry Andric   const ObjCIvarDecl *IVar = nullptr;
747480093f4SDimitry Andric 
748480093f4SDimitry Andric   // Property accessor stubs sometimes do not correspond to any property decl
749480093f4SDimitry Andric   // in the current interface (but in a superclass). They still have a
750480093f4SDimitry Andric   // corresponding property impl decl in this case.
751480093f4SDimitry Andric   if (MD->isSynthesizedAccessorStub()) {
752480093f4SDimitry Andric     const ObjCInterfaceDecl *IntD = MD->getClassInterface();
753480093f4SDimitry Andric     const ObjCImplementationDecl *ImpD = IntD->getImplementation();
754480093f4SDimitry Andric     for (const auto *PI: ImpD->property_impls()) {
755480093f4SDimitry Andric       if (const ObjCPropertyDecl *P = PI->getPropertyDecl()) {
756480093f4SDimitry Andric         if (P->getGetterName() == MD->getSelector())
757480093f4SDimitry Andric           IVar = P->getPropertyIvarDecl();
758480093f4SDimitry Andric       }
759480093f4SDimitry Andric     }
760480093f4SDimitry Andric   }
761480093f4SDimitry Andric 
762480093f4SDimitry Andric   if (!IVar) {
763480093f4SDimitry Andric     const ObjCPropertyDecl *Prop = MD->findPropertyDecl();
764480093f4SDimitry Andric     IVar = findBackingIvar(Prop);
7650b57cec5SDimitry Andric     if (!IVar)
7660b57cec5SDimitry Andric       return nullptr;
7670b57cec5SDimitry Andric 
7680b57cec5SDimitry Andric     // Ignore weak variables, which have special behavior.
7695ffd83dbSDimitry Andric     if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak)
7700b57cec5SDimitry Andric       return nullptr;
7710b57cec5SDimitry Andric 
7720b57cec5SDimitry Andric     // Look to see if Sema has synthesized a body for us. This happens in
7730b57cec5SDimitry Andric     // Objective-C++ because the return value may be a C++ class type with a
7740b57cec5SDimitry Andric     // non-trivial copy constructor. We can only do this if we can find the
7750b57cec5SDimitry Andric     // @synthesize for this property, though (or if we know it's been auto-
7760b57cec5SDimitry Andric     // synthesized).
7770b57cec5SDimitry Andric     const ObjCImplementationDecl *ImplDecl =
7780b57cec5SDimitry Andric       IVar->getContainingInterface()->getImplementation();
7790b57cec5SDimitry Andric     if (ImplDecl) {
7800b57cec5SDimitry Andric       for (const auto *I : ImplDecl->property_impls()) {
7810b57cec5SDimitry Andric         if (I->getPropertyDecl() != Prop)
7820b57cec5SDimitry Andric           continue;
7830b57cec5SDimitry Andric 
7840b57cec5SDimitry Andric         if (I->getGetterCXXConstructor()) {
7850b57cec5SDimitry Andric           ASTMaker M(Ctx);
7860b57cec5SDimitry Andric           return M.makeReturn(I->getGetterCXXConstructor());
7870b57cec5SDimitry Andric         }
7880b57cec5SDimitry Andric       }
7890b57cec5SDimitry Andric     }
7900b57cec5SDimitry Andric 
7910b57cec5SDimitry Andric     // Sanity check that the property is the same type as the ivar, or a
7920b57cec5SDimitry Andric     // reference to it, and that it is either an object pointer or trivially
7930b57cec5SDimitry Andric     // copyable.
7940b57cec5SDimitry Andric     if (!Ctx.hasSameUnqualifiedType(IVar->getType(),
7950b57cec5SDimitry Andric                                     Prop->getType().getNonReferenceType()))
7960b57cec5SDimitry Andric       return nullptr;
7970b57cec5SDimitry Andric     if (!IVar->getType()->isObjCLifetimeType() &&
7980b57cec5SDimitry Andric         !IVar->getType().isTriviallyCopyableType(Ctx))
7990b57cec5SDimitry Andric       return nullptr;
800480093f4SDimitry Andric   }
8010b57cec5SDimitry Andric 
8020b57cec5SDimitry Andric   // Generate our body:
8030b57cec5SDimitry Andric   //   return self->_ivar;
8040b57cec5SDimitry Andric   ASTMaker M(Ctx);
8050b57cec5SDimitry Andric 
806480093f4SDimitry Andric   const VarDecl *selfVar = MD->getSelfDecl();
8070b57cec5SDimitry Andric   if (!selfVar)
8080b57cec5SDimitry Andric     return nullptr;
8090b57cec5SDimitry Andric 
8100b57cec5SDimitry Andric   Expr *loadedIVar =
8110b57cec5SDimitry Andric     M.makeObjCIvarRef(
8120b57cec5SDimitry Andric       M.makeLvalueToRvalue(
8130b57cec5SDimitry Andric         M.makeDeclRefExpr(selfVar),
8140b57cec5SDimitry Andric         selfVar->getType()),
8150b57cec5SDimitry Andric       IVar);
8160b57cec5SDimitry Andric 
817480093f4SDimitry Andric   if (!MD->getReturnType()->isReferenceType())
8180b57cec5SDimitry Andric     loadedIVar = M.makeLvalueToRvalue(loadedIVar, IVar->getType());
8190b57cec5SDimitry Andric 
8200b57cec5SDimitry Andric   return M.makeReturn(loadedIVar);
8210b57cec5SDimitry Andric }
8220b57cec5SDimitry Andric 
8230b57cec5SDimitry Andric Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
8240b57cec5SDimitry Andric   // We currently only know how to synthesize property accessors.
8250b57cec5SDimitry Andric   if (!D->isPropertyAccessor())
8260b57cec5SDimitry Andric     return nullptr;
8270b57cec5SDimitry Andric 
8280b57cec5SDimitry Andric   D = D->getCanonicalDecl();
8290b57cec5SDimitry Andric 
8300b57cec5SDimitry Andric   // We should not try to synthesize explicitly redefined accessors.
8310b57cec5SDimitry Andric   // We do not know for sure how they behave.
8320b57cec5SDimitry Andric   if (!D->isImplicit())
8330b57cec5SDimitry Andric     return nullptr;
8340b57cec5SDimitry Andric 
8350b57cec5SDimitry Andric   Optional<Stmt *> &Val = Bodies[D];
8360b57cec5SDimitry Andric   if (Val.hasValue())
8370b57cec5SDimitry Andric     return Val.getValue();
8380b57cec5SDimitry Andric   Val = nullptr;
8390b57cec5SDimitry Andric 
8400b57cec5SDimitry Andric   // For now, we only synthesize getters.
8410b57cec5SDimitry Andric   // Synthesizing setters would cause false negatives in the
8420b57cec5SDimitry Andric   // RetainCountChecker because the method body would bind the parameter
8430b57cec5SDimitry Andric   // to an instance variable, causing it to escape. This would prevent
8440b57cec5SDimitry Andric   // warning in the following common scenario:
8450b57cec5SDimitry Andric   //
8460b57cec5SDimitry Andric   //  id foo = [[NSObject alloc] init];
8470b57cec5SDimitry Andric   //  self.foo = foo; // We should warn that foo leaks here.
8480b57cec5SDimitry Andric   //
8490b57cec5SDimitry Andric   if (D->param_size() != 0)
8500b57cec5SDimitry Andric     return nullptr;
8510b57cec5SDimitry Andric 
852480093f4SDimitry Andric   // If the property was defined in an extension, search the extensions for
853480093f4SDimitry Andric   // overrides.
854480093f4SDimitry Andric   const ObjCInterfaceDecl *OID = D->getClassInterface();
855480093f4SDimitry Andric   if (dyn_cast<ObjCInterfaceDecl>(D->getParent()) != OID)
856480093f4SDimitry Andric     for (auto *Ext : OID->known_extensions()) {
857480093f4SDimitry Andric       auto *OMD = Ext->getInstanceMethod(D->getSelector());
858480093f4SDimitry Andric       if (OMD && !OMD->isImplicit())
859480093f4SDimitry Andric         return nullptr;
860480093f4SDimitry Andric     }
861480093f4SDimitry Andric 
862480093f4SDimitry Andric   Val = createObjCPropertyGetter(C, D);
8630b57cec5SDimitry Andric 
8640b57cec5SDimitry Andric   return Val.getValue();
8650b57cec5SDimitry Andric }
866