xref: /freebsd/contrib/llvm-project/clang/lib/Analysis/BodyFarm.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
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) {
117*5ffd83dbSDimitry Andric   return BinaryOperator::Create(
118*5ffd83dbSDimitry Andric       C, const_cast<Expr *>(LHS), const_cast<Expr *>(RHS), BO_Assign, Ty,
119*5ffd83dbSDimitry 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));
126*5ffd83dbSDimitry Andric   return BinaryOperator::Create(
127*5ffd83dbSDimitry Andric       C, const_cast<Expr *>(LHS), const_cast<Expr *>(RHS), Op,
128*5ffd83dbSDimitry Andric       C.getLogicalOperationType(), VK_RValue, OK_Ordinary, SourceLocation(),
129*5ffd83dbSDimitry 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) {
148*5ffd83dbSDimitry Andric   return UnaryOperator::Create(C, const_cast<Expr *>(Arg), UO_Deref, Ty,
1490b57cec5SDimitry Andric                                VK_LValue, OK_Ordinary, SourceLocation(),
150*5ffd83dbSDimitry 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,
1720b57cec5SDimitry Andric                                   /* ExprValueKind=*/ VK_RValue);
1730b57cec5SDimitry Andric }
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
1760b57cec5SDimitry Andric   if (Arg->getType() == Ty)
1770b57cec5SDimitry Andric     return const_cast<Expr*>(Arg);
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric   return ImplicitCastExpr::Create(C, Ty, CK_IntegralCast,
1800b57cec5SDimitry Andric                                   const_cast<Expr*>(Arg), nullptr, VK_RValue);
1810b57cec5SDimitry Andric }
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) {
1840b57cec5SDimitry Andric   return ImplicitCastExpr::Create(C, C.BoolTy, CK_IntegralToBoolean,
1850b57cec5SDimitry Andric                                   const_cast<Expr*>(Arg), nullptr, VK_RValue);
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) {
1890b57cec5SDimitry Andric   QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy;
1900b57cec5SDimitry Andric   return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation());
1910b57cec5SDimitry Andric }
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric ObjCIvarRefExpr *ASTMaker::makeObjCIvarRef(const Expr *Base,
1940b57cec5SDimitry Andric                                            const ObjCIvarDecl *IVar) {
1950b57cec5SDimitry Andric   return new (C) ObjCIvarRefExpr(const_cast<ObjCIvarDecl*>(IVar),
1960b57cec5SDimitry Andric                                  IVar->getType(), SourceLocation(),
1970b57cec5SDimitry Andric                                  SourceLocation(), const_cast<Expr*>(Base),
1980b57cec5SDimitry Andric                                  /*arrow=*/true, /*free=*/false);
1990b57cec5SDimitry Andric }
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) {
2020b57cec5SDimitry Andric   return ReturnStmt::Create(C, SourceLocation(), const_cast<Expr *>(RetVal),
2030b57cec5SDimitry Andric                             /* NRVOCandidate=*/nullptr);
2040b57cec5SDimitry Andric }
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric IntegerLiteral *ASTMaker::makeIntegerLiteral(uint64_t Value, QualType Ty) {
2070b57cec5SDimitry Andric   llvm::APInt APValue = llvm::APInt(C.getTypeSize(Ty), Value);
2080b57cec5SDimitry Andric   return IntegerLiteral::Create(C, APValue, Ty, SourceLocation());
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric MemberExpr *ASTMaker::makeMemberExpression(Expr *base, ValueDecl *MemberDecl,
2120b57cec5SDimitry Andric                                            bool IsArrow,
2130b57cec5SDimitry Andric                                            ExprValueKind ValueKind) {
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric   DeclAccessPair FoundDecl = DeclAccessPair::make(MemberDecl, AS_public);
2160b57cec5SDimitry Andric   return MemberExpr::Create(
2170b57cec5SDimitry Andric       C, base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(),
2180b57cec5SDimitry Andric       SourceLocation(), MemberDecl, FoundDecl,
2190b57cec5SDimitry Andric       DeclarationNameInfo(MemberDecl->getDeclName(), SourceLocation()),
2200b57cec5SDimitry Andric       /* TemplateArgumentListInfo=*/ nullptr, MemberDecl->getType(), ValueKind,
2210b57cec5SDimitry Andric       OK_Ordinary, NOUR_None);
2220b57cec5SDimitry Andric }
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric ValueDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) {
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric   CXXBasePaths Paths(
2270b57cec5SDimitry Andric       /* FindAmbiguities=*/false,
2280b57cec5SDimitry Andric       /* RecordPaths=*/false,
2290b57cec5SDimitry Andric       /* DetectVirtual=*/ false);
2300b57cec5SDimitry Andric   const IdentifierInfo &II = C.Idents.get(Name);
2310b57cec5SDimitry Andric   DeclarationName DeclName = C.DeclarationNames.getIdentifier(&II);
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric   DeclContextLookupResult Decls = RD->lookup(DeclName);
2340b57cec5SDimitry Andric   for (NamedDecl *FoundDecl : Decls)
2350b57cec5SDimitry Andric     if (!FoundDecl->getDeclContext()->isFunctionOrMethod())
2360b57cec5SDimitry Andric       return cast<ValueDecl>(FoundDecl);
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   return nullptr;
2390b57cec5SDimitry Andric }
2400b57cec5SDimitry Andric 
2410b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2420b57cec5SDimitry Andric // Creation functions for faux ASTs.
2430b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric static CallExpr *create_call_once_funcptr_call(ASTContext &C, ASTMaker M,
2480b57cec5SDimitry Andric                                                const ParmVarDecl *Callback,
2490b57cec5SDimitry Andric                                                ArrayRef<Expr *> CallArgs) {
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric   QualType Ty = Callback->getType();
2520b57cec5SDimitry Andric   DeclRefExpr *Call = M.makeDeclRefExpr(Callback);
2530b57cec5SDimitry Andric   Expr *SubExpr;
2540b57cec5SDimitry Andric   if (Ty->isRValueReferenceType()) {
2550b57cec5SDimitry Andric     SubExpr = M.makeImplicitCast(
2560b57cec5SDimitry Andric         Call, Ty.getNonReferenceType(), CK_LValueToRValue);
2570b57cec5SDimitry Andric   } else if (Ty->isLValueReferenceType() &&
2580b57cec5SDimitry Andric              Call->getType()->isFunctionType()) {
2590b57cec5SDimitry Andric     Ty = C.getPointerType(Ty.getNonReferenceType());
2600b57cec5SDimitry Andric     SubExpr = M.makeImplicitCast(Call, Ty, CK_FunctionToPointerDecay);
2610b57cec5SDimitry Andric   } else if (Ty->isLValueReferenceType()
2620b57cec5SDimitry Andric              && Call->getType()->isPointerType()
2630b57cec5SDimitry Andric              && Call->getType()->getPointeeType()->isFunctionType()){
2640b57cec5SDimitry Andric     SubExpr = Call;
2650b57cec5SDimitry Andric   } else {
2660b57cec5SDimitry Andric     llvm_unreachable("Unexpected state");
2670b57cec5SDimitry Andric   }
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric   return CallExpr::Create(C, SubExpr, CallArgs, C.VoidTy, VK_RValue,
2700b57cec5SDimitry Andric                           SourceLocation());
2710b57cec5SDimitry Andric }
2720b57cec5SDimitry Andric 
2730b57cec5SDimitry Andric static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M,
2740b57cec5SDimitry Andric                                               const ParmVarDecl *Callback,
2750b57cec5SDimitry Andric                                               CXXRecordDecl *CallbackDecl,
2760b57cec5SDimitry Andric                                               ArrayRef<Expr *> CallArgs) {
2770b57cec5SDimitry Andric   assert(CallbackDecl != nullptr);
2780b57cec5SDimitry Andric   assert(CallbackDecl->isLambda());
2790b57cec5SDimitry Andric   FunctionDecl *callOperatorDecl = CallbackDecl->getLambdaCallOperator();
2800b57cec5SDimitry Andric   assert(callOperatorDecl != nullptr);
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric   DeclRefExpr *callOperatorDeclRef =
2830b57cec5SDimitry Andric       DeclRefExpr::Create(/* Ctx =*/ C,
2840b57cec5SDimitry Andric                           /* QualifierLoc =*/ NestedNameSpecifierLoc(),
2850b57cec5SDimitry Andric                           /* TemplateKWLoc =*/ SourceLocation(),
2860b57cec5SDimitry Andric                           const_cast<FunctionDecl *>(callOperatorDecl),
2870b57cec5SDimitry Andric                           /* RefersToEnclosingVariableOrCapture=*/ false,
2880b57cec5SDimitry Andric                           /* NameLoc =*/ SourceLocation(),
2890b57cec5SDimitry Andric                           /* T =*/ callOperatorDecl->getType(),
2900b57cec5SDimitry Andric                           /* VK =*/ VK_LValue);
2910b57cec5SDimitry Andric 
2920b57cec5SDimitry Andric   return CXXOperatorCallExpr::Create(
2930b57cec5SDimitry Andric       /*AstContext=*/C, OO_Call, callOperatorDeclRef,
2940b57cec5SDimitry Andric       /*Args=*/CallArgs,
2950b57cec5SDimitry Andric       /*QualType=*/C.VoidTy,
2960b57cec5SDimitry Andric       /*ExprValueType=*/VK_RValue,
297*5ffd83dbSDimitry Andric       /*SourceLocation=*/SourceLocation(),
298*5ffd83dbSDimitry Andric       /*FPFeatures=*/FPOptionsOverride());
2990b57cec5SDimitry Andric }
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric /// Create a fake body for std::call_once.
3020b57cec5SDimitry Andric /// Emulates the following function body:
3030b57cec5SDimitry Andric ///
3040b57cec5SDimitry Andric /// \code
3050b57cec5SDimitry Andric /// typedef struct once_flag_s {
3060b57cec5SDimitry Andric ///   unsigned long __state = 0;
3070b57cec5SDimitry Andric /// } once_flag;
3080b57cec5SDimitry Andric /// template<class Callable>
3090b57cec5SDimitry Andric /// void call_once(once_flag& o, Callable func) {
3100b57cec5SDimitry Andric ///   if (!o.__state) {
3110b57cec5SDimitry Andric ///     func();
3120b57cec5SDimitry Andric ///   }
3130b57cec5SDimitry Andric ///   o.__state = 1;
3140b57cec5SDimitry Andric /// }
3150b57cec5SDimitry Andric /// \endcode
3160b57cec5SDimitry Andric static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) {
3170b57cec5SDimitry Andric   LLVM_DEBUG(llvm::dbgs() << "Generating body for call_once\n");
3180b57cec5SDimitry Andric 
3190b57cec5SDimitry Andric   // We need at least two parameters.
3200b57cec5SDimitry Andric   if (D->param_size() < 2)
3210b57cec5SDimitry Andric     return nullptr;
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric   ASTMaker M(C);
3240b57cec5SDimitry Andric 
3250b57cec5SDimitry Andric   const ParmVarDecl *Flag = D->getParamDecl(0);
3260b57cec5SDimitry Andric   const ParmVarDecl *Callback = D->getParamDecl(1);
3270b57cec5SDimitry Andric 
3280b57cec5SDimitry Andric   if (!Callback->getType()->isReferenceType()) {
3290b57cec5SDimitry Andric     llvm::dbgs() << "libcxx03 std::call_once implementation, skipping.\n";
3300b57cec5SDimitry Andric     return nullptr;
3310b57cec5SDimitry Andric   }
3320b57cec5SDimitry Andric   if (!Flag->getType()->isReferenceType()) {
3330b57cec5SDimitry Andric     llvm::dbgs() << "unknown std::call_once implementation, skipping.\n";
3340b57cec5SDimitry Andric     return nullptr;
3350b57cec5SDimitry Andric   }
3360b57cec5SDimitry Andric 
3370b57cec5SDimitry Andric   QualType CallbackType = Callback->getType().getNonReferenceType();
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric   // Nullable pointer, non-null iff function is a CXXRecordDecl.
3400b57cec5SDimitry Andric   CXXRecordDecl *CallbackRecordDecl = CallbackType->getAsCXXRecordDecl();
3410b57cec5SDimitry Andric   QualType FlagType = Flag->getType().getNonReferenceType();
3420b57cec5SDimitry Andric   auto *FlagRecordDecl = FlagType->getAsRecordDecl();
3430b57cec5SDimitry Andric 
3440b57cec5SDimitry Andric   if (!FlagRecordDecl) {
3450b57cec5SDimitry Andric     LLVM_DEBUG(llvm::dbgs() << "Flag field is not a record: "
3460b57cec5SDimitry Andric                             << "unknown std::call_once implementation, "
3470b57cec5SDimitry Andric                             << "ignoring the call.\n");
3480b57cec5SDimitry Andric     return nullptr;
3490b57cec5SDimitry Andric   }
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric   // We initially assume libc++ implementation of call_once,
3520b57cec5SDimitry Andric   // where the once_flag struct has a field `__state_`.
3530b57cec5SDimitry Andric   ValueDecl *FlagFieldDecl = M.findMemberField(FlagRecordDecl, "__state_");
3540b57cec5SDimitry Andric 
3550b57cec5SDimitry Andric   // Otherwise, try libstdc++ implementation, with a field
3560b57cec5SDimitry Andric   // `_M_once`
3570b57cec5SDimitry Andric   if (!FlagFieldDecl) {
3580b57cec5SDimitry Andric     FlagFieldDecl = M.findMemberField(FlagRecordDecl, "_M_once");
3590b57cec5SDimitry Andric   }
3600b57cec5SDimitry Andric 
3610b57cec5SDimitry Andric   if (!FlagFieldDecl) {
3620b57cec5SDimitry Andric     LLVM_DEBUG(llvm::dbgs() << "No field _M_once or __state_ found on "
3630b57cec5SDimitry Andric                             << "std::once_flag struct: unknown std::call_once "
3640b57cec5SDimitry Andric                             << "implementation, ignoring the call.");
3650b57cec5SDimitry Andric     return nullptr;
3660b57cec5SDimitry Andric   }
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric   bool isLambdaCall = CallbackRecordDecl && CallbackRecordDecl->isLambda();
3690b57cec5SDimitry Andric   if (CallbackRecordDecl && !isLambdaCall) {
3700b57cec5SDimitry Andric     LLVM_DEBUG(llvm::dbgs()
3710b57cec5SDimitry Andric                << "Not supported: synthesizing body for functors when "
3720b57cec5SDimitry Andric                << "body farming std::call_once, ignoring the call.");
3730b57cec5SDimitry Andric     return nullptr;
3740b57cec5SDimitry Andric   }
3750b57cec5SDimitry Andric 
3760b57cec5SDimitry Andric   SmallVector<Expr *, 5> CallArgs;
3770b57cec5SDimitry Andric   const FunctionProtoType *CallbackFunctionType;
3780b57cec5SDimitry Andric   if (isLambdaCall) {
3790b57cec5SDimitry Andric 
3800b57cec5SDimitry Andric     // Lambda requires callback itself inserted as a first parameter.
3810b57cec5SDimitry Andric     CallArgs.push_back(
3820b57cec5SDimitry Andric         M.makeDeclRefExpr(Callback,
3830b57cec5SDimitry Andric                           /* RefersToEnclosingVariableOrCapture=*/ true));
3840b57cec5SDimitry Andric     CallbackFunctionType = CallbackRecordDecl->getLambdaCallOperator()
3850b57cec5SDimitry Andric                                ->getType()
3860b57cec5SDimitry Andric                                ->getAs<FunctionProtoType>();
3870b57cec5SDimitry Andric   } else if (!CallbackType->getPointeeType().isNull()) {
3880b57cec5SDimitry Andric     CallbackFunctionType =
3890b57cec5SDimitry Andric         CallbackType->getPointeeType()->getAs<FunctionProtoType>();
3900b57cec5SDimitry Andric   } else {
3910b57cec5SDimitry Andric     CallbackFunctionType = CallbackType->getAs<FunctionProtoType>();
3920b57cec5SDimitry Andric   }
3930b57cec5SDimitry Andric 
3940b57cec5SDimitry Andric   if (!CallbackFunctionType)
3950b57cec5SDimitry Andric     return nullptr;
3960b57cec5SDimitry Andric 
3970b57cec5SDimitry Andric   // First two arguments are used for the flag and for the callback.
3980b57cec5SDimitry Andric   if (D->getNumParams() != CallbackFunctionType->getNumParams() + 2) {
3990b57cec5SDimitry Andric     LLVM_DEBUG(llvm::dbgs() << "Types of params of the callback do not match "
4000b57cec5SDimitry Andric                             << "params passed to std::call_once, "
4010b57cec5SDimitry Andric                             << "ignoring the call\n");
4020b57cec5SDimitry Andric     return nullptr;
4030b57cec5SDimitry Andric   }
4040b57cec5SDimitry Andric 
4050b57cec5SDimitry Andric   // All arguments past first two ones are passed to the callback,
4060b57cec5SDimitry Andric   // and we turn lvalues into rvalues if the argument is not passed by
4070b57cec5SDimitry Andric   // reference.
4080b57cec5SDimitry Andric   for (unsigned int ParamIdx = 2; ParamIdx < D->getNumParams(); ParamIdx++) {
4090b57cec5SDimitry Andric     const ParmVarDecl *PDecl = D->getParamDecl(ParamIdx);
410a7dea167SDimitry Andric     assert(PDecl);
411a7dea167SDimitry Andric     if (CallbackFunctionType->getParamType(ParamIdx - 2)
4120b57cec5SDimitry Andric                 .getNonReferenceType()
4130b57cec5SDimitry Andric                 .getCanonicalType() !=
4140b57cec5SDimitry Andric             PDecl->getType().getNonReferenceType().getCanonicalType()) {
4150b57cec5SDimitry Andric       LLVM_DEBUG(llvm::dbgs() << "Types of params of the callback do not match "
4160b57cec5SDimitry Andric                               << "params passed to std::call_once, "
4170b57cec5SDimitry Andric                               << "ignoring the call\n");
4180b57cec5SDimitry Andric       return nullptr;
4190b57cec5SDimitry Andric     }
4200b57cec5SDimitry Andric     Expr *ParamExpr = M.makeDeclRefExpr(PDecl);
4210b57cec5SDimitry Andric     if (!CallbackFunctionType->getParamType(ParamIdx - 2)->isReferenceType()) {
4220b57cec5SDimitry Andric       QualType PTy = PDecl->getType().getNonReferenceType();
4230b57cec5SDimitry Andric       ParamExpr = M.makeLvalueToRvalue(ParamExpr, PTy);
4240b57cec5SDimitry Andric     }
4250b57cec5SDimitry Andric     CallArgs.push_back(ParamExpr);
4260b57cec5SDimitry Andric   }
4270b57cec5SDimitry Andric 
4280b57cec5SDimitry Andric   CallExpr *CallbackCall;
4290b57cec5SDimitry Andric   if (isLambdaCall) {
4300b57cec5SDimitry Andric 
4310b57cec5SDimitry Andric     CallbackCall = create_call_once_lambda_call(C, M, Callback,
4320b57cec5SDimitry Andric                                                 CallbackRecordDecl, CallArgs);
4330b57cec5SDimitry Andric   } else {
4340b57cec5SDimitry Andric 
4350b57cec5SDimitry Andric     // Function pointer case.
4360b57cec5SDimitry Andric     CallbackCall = create_call_once_funcptr_call(C, M, Callback, CallArgs);
4370b57cec5SDimitry Andric   }
4380b57cec5SDimitry Andric 
4390b57cec5SDimitry Andric   DeclRefExpr *FlagDecl =
4400b57cec5SDimitry Andric       M.makeDeclRefExpr(Flag,
4410b57cec5SDimitry Andric                         /* RefersToEnclosingVariableOrCapture=*/true);
4420b57cec5SDimitry Andric 
4430b57cec5SDimitry Andric 
4440b57cec5SDimitry Andric   MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FlagFieldDecl);
4450b57cec5SDimitry Andric   assert(Deref->isLValue());
4460b57cec5SDimitry Andric   QualType DerefType = Deref->getType();
4470b57cec5SDimitry Andric 
4480b57cec5SDimitry Andric   // Negation predicate.
449*5ffd83dbSDimitry Andric   UnaryOperator *FlagCheck = UnaryOperator::Create(
450*5ffd83dbSDimitry Andric       C,
4510b57cec5SDimitry Andric       /* input=*/
4520b57cec5SDimitry Andric       M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType,
4530b57cec5SDimitry Andric                          CK_IntegralToBoolean),
4540b57cec5SDimitry Andric       /* opc=*/UO_LNot,
4550b57cec5SDimitry Andric       /* QualType=*/C.IntTy,
4560b57cec5SDimitry Andric       /* ExprValueKind=*/VK_RValue,
4570b57cec5SDimitry Andric       /* ExprObjectKind=*/OK_Ordinary, SourceLocation(),
458*5ffd83dbSDimitry Andric       /* CanOverflow*/ false, FPOptionsOverride());
4590b57cec5SDimitry Andric 
4600b57cec5SDimitry Andric   // Create assignment.
4610b57cec5SDimitry Andric   BinaryOperator *FlagAssignment = M.makeAssignment(
4620b57cec5SDimitry Andric       Deref, M.makeIntegralCast(M.makeIntegerLiteral(1, C.IntTy), DerefType),
4630b57cec5SDimitry Andric       DerefType);
4640b57cec5SDimitry Andric 
4650b57cec5SDimitry Andric   auto *Out =
4660b57cec5SDimitry Andric       IfStmt::Create(C, SourceLocation(),
4670b57cec5SDimitry Andric                      /* IsConstexpr=*/false,
4680b57cec5SDimitry Andric                      /* Init=*/nullptr,
4690b57cec5SDimitry Andric                      /* Var=*/nullptr,
4700b57cec5SDimitry Andric                      /* Cond=*/FlagCheck,
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,
5170b57cec5SDimitry Andric       /*SourceLocation=*/SourceLocation());
5180b57cec5SDimitry Andric 
5190b57cec5SDimitry Andric   // (2) Create the assignment to the predicate.
5200b57cec5SDimitry Andric   Expr *DoneValue =
521*5ffd83dbSDimitry Andric       UnaryOperator::Create(C, M.makeIntegerLiteral(0, C.LongTy), UO_Not,
522*5ffd83dbSDimitry Andric                             C.LongTy, VK_RValue, OK_Ordinary, SourceLocation(),
523*5ffd83dbSDimitry 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,
5550b57cec5SDimitry Andric                             /* Then=*/CS);
5560b57cec5SDimitry Andric   return If;
5570b57cec5SDimitry Andric }
5580b57cec5SDimitry Andric 
5590b57cec5SDimitry Andric /// Create a fake body for dispatch_sync.
5600b57cec5SDimitry Andric static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
5610b57cec5SDimitry Andric   // Check if we have at least two parameters.
5620b57cec5SDimitry Andric   if (D->param_size() != 2)
5630b57cec5SDimitry Andric     return nullptr;
5640b57cec5SDimitry Andric 
5650b57cec5SDimitry Andric   // Check if the second parameter is a block.
5660b57cec5SDimitry Andric   const ParmVarDecl *PV = D->getParamDecl(1);
5670b57cec5SDimitry Andric   QualType Ty = PV->getType();
5680b57cec5SDimitry Andric   if (!isDispatchBlock(Ty))
5690b57cec5SDimitry Andric     return nullptr;
5700b57cec5SDimitry Andric 
5710b57cec5SDimitry Andric   // Everything checks out.  Create a fake body that just calls the block.
5720b57cec5SDimitry Andric   // This is basically just an AST dump of:
5730b57cec5SDimitry Andric   //
5740b57cec5SDimitry Andric   // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) {
5750b57cec5SDimitry Andric   //   block();
5760b57cec5SDimitry Andric   // }
5770b57cec5SDimitry Andric   //
5780b57cec5SDimitry Andric   ASTMaker M(C);
5790b57cec5SDimitry Andric   DeclRefExpr *DR = M.makeDeclRefExpr(PV);
5800b57cec5SDimitry Andric   ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
5810b57cec5SDimitry Andric   CallExpr *CE =
5820b57cec5SDimitry Andric       CallExpr::Create(C, ICE, None, C.VoidTy, VK_RValue, SourceLocation());
5830b57cec5SDimitry Andric   return CE;
5840b57cec5SDimitry Andric }
5850b57cec5SDimitry Andric 
5860b57cec5SDimitry Andric static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
5870b57cec5SDimitry Andric {
5880b57cec5SDimitry Andric   // There are exactly 3 arguments.
5890b57cec5SDimitry Andric   if (D->param_size() != 3)
5900b57cec5SDimitry Andric     return nullptr;
5910b57cec5SDimitry Andric 
5920b57cec5SDimitry Andric   // Signature:
5930b57cec5SDimitry Andric   // _Bool OSAtomicCompareAndSwapPtr(void *__oldValue,
5940b57cec5SDimitry Andric   //                                 void *__newValue,
5950b57cec5SDimitry Andric   //                                 void * volatile *__theValue)
5960b57cec5SDimitry Andric   // Generate body:
5970b57cec5SDimitry Andric   //   if (oldValue == *theValue) {
5980b57cec5SDimitry Andric   //    *theValue = newValue;
5990b57cec5SDimitry Andric   //    return YES;
6000b57cec5SDimitry Andric   //   }
6010b57cec5SDimitry Andric   //   else return NO;
6020b57cec5SDimitry Andric 
6030b57cec5SDimitry Andric   QualType ResultTy = D->getReturnType();
6040b57cec5SDimitry Andric   bool isBoolean = ResultTy->isBooleanType();
6050b57cec5SDimitry Andric   if (!isBoolean && !ResultTy->isIntegralType(C))
6060b57cec5SDimitry Andric     return nullptr;
6070b57cec5SDimitry Andric 
6080b57cec5SDimitry Andric   const ParmVarDecl *OldValue = D->getParamDecl(0);
6090b57cec5SDimitry Andric   QualType OldValueTy = OldValue->getType();
6100b57cec5SDimitry Andric 
6110b57cec5SDimitry Andric   const ParmVarDecl *NewValue = D->getParamDecl(1);
6120b57cec5SDimitry Andric   QualType NewValueTy = NewValue->getType();
6130b57cec5SDimitry Andric 
6140b57cec5SDimitry Andric   assert(OldValueTy == NewValueTy);
6150b57cec5SDimitry Andric 
6160b57cec5SDimitry Andric   const ParmVarDecl *TheValue = D->getParamDecl(2);
6170b57cec5SDimitry Andric   QualType TheValueTy = TheValue->getType();
6180b57cec5SDimitry Andric   const PointerType *PT = TheValueTy->getAs<PointerType>();
6190b57cec5SDimitry Andric   if (!PT)
6200b57cec5SDimitry Andric     return nullptr;
6210b57cec5SDimitry Andric   QualType PointeeTy = PT->getPointeeType();
6220b57cec5SDimitry Andric 
6230b57cec5SDimitry Andric   ASTMaker M(C);
6240b57cec5SDimitry Andric   // Construct the comparison.
6250b57cec5SDimitry Andric   Expr *Comparison =
6260b57cec5SDimitry Andric     M.makeComparison(
6270b57cec5SDimitry Andric       M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy),
6280b57cec5SDimitry Andric       M.makeLvalueToRvalue(
6290b57cec5SDimitry Andric         M.makeDereference(
6300b57cec5SDimitry Andric           M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
6310b57cec5SDimitry Andric           PointeeTy),
6320b57cec5SDimitry Andric         PointeeTy),
6330b57cec5SDimitry Andric       BO_EQ);
6340b57cec5SDimitry Andric 
6350b57cec5SDimitry Andric   // Construct the body of the IfStmt.
6360b57cec5SDimitry Andric   Stmt *Stmts[2];
6370b57cec5SDimitry Andric   Stmts[0] =
6380b57cec5SDimitry Andric     M.makeAssignment(
6390b57cec5SDimitry Andric       M.makeDereference(
6400b57cec5SDimitry Andric         M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
6410b57cec5SDimitry Andric         PointeeTy),
6420b57cec5SDimitry Andric       M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy),
6430b57cec5SDimitry Andric       NewValueTy);
6440b57cec5SDimitry Andric 
6450b57cec5SDimitry Andric   Expr *BoolVal = M.makeObjCBool(true);
6460b57cec5SDimitry Andric   Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
6470b57cec5SDimitry Andric                            : M.makeIntegralCast(BoolVal, ResultTy);
6480b57cec5SDimitry Andric   Stmts[1] = M.makeReturn(RetVal);
6490b57cec5SDimitry Andric   CompoundStmt *Body = M.makeCompound(Stmts);
6500b57cec5SDimitry Andric 
6510b57cec5SDimitry Andric   // Construct the else clause.
6520b57cec5SDimitry Andric   BoolVal = M.makeObjCBool(false);
6530b57cec5SDimitry Andric   RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
6540b57cec5SDimitry Andric                      : M.makeIntegralCast(BoolVal, ResultTy);
6550b57cec5SDimitry Andric   Stmt *Else = M.makeReturn(RetVal);
6560b57cec5SDimitry Andric 
6570b57cec5SDimitry Andric   /// Construct the If.
6580b57cec5SDimitry Andric   auto *If = IfStmt::Create(C, SourceLocation(),
6590b57cec5SDimitry Andric                             /* IsConstexpr=*/false,
6600b57cec5SDimitry Andric                             /* Init=*/nullptr,
6610b57cec5SDimitry Andric                             /* Var=*/nullptr, Comparison, Body,
6620b57cec5SDimitry Andric                             SourceLocation(), Else);
6630b57cec5SDimitry Andric 
6640b57cec5SDimitry Andric   return If;
6650b57cec5SDimitry Andric }
6660b57cec5SDimitry Andric 
6670b57cec5SDimitry Andric Stmt *BodyFarm::getBody(const FunctionDecl *D) {
6680b57cec5SDimitry Andric   Optional<Stmt *> &Val = Bodies[D];
6690b57cec5SDimitry Andric   if (Val.hasValue())
6700b57cec5SDimitry Andric     return Val.getValue();
6710b57cec5SDimitry Andric 
6720b57cec5SDimitry Andric   Val = nullptr;
6730b57cec5SDimitry Andric 
6740b57cec5SDimitry Andric   if (D->getIdentifier() == nullptr)
6750b57cec5SDimitry Andric     return nullptr;
6760b57cec5SDimitry Andric 
6770b57cec5SDimitry Andric   StringRef Name = D->getName();
6780b57cec5SDimitry Andric   if (Name.empty())
6790b57cec5SDimitry Andric     return nullptr;
6800b57cec5SDimitry Andric 
6810b57cec5SDimitry Andric   FunctionFarmer FF;
6820b57cec5SDimitry Andric 
6830b57cec5SDimitry Andric   if (Name.startswith("OSAtomicCompareAndSwap") ||
6840b57cec5SDimitry Andric       Name.startswith("objc_atomicCompareAndSwap")) {
6850b57cec5SDimitry Andric     FF = create_OSAtomicCompareAndSwap;
6860b57cec5SDimitry Andric   } else if (Name == "call_once" && D->getDeclContext()->isStdNamespace()) {
6870b57cec5SDimitry Andric     FF = create_call_once;
6880b57cec5SDimitry Andric   } else {
6890b57cec5SDimitry Andric     FF = llvm::StringSwitch<FunctionFarmer>(Name)
6900b57cec5SDimitry Andric           .Case("dispatch_sync", create_dispatch_sync)
6910b57cec5SDimitry Andric           .Case("dispatch_once", create_dispatch_once)
6920b57cec5SDimitry Andric           .Default(nullptr);
6930b57cec5SDimitry Andric   }
6940b57cec5SDimitry Andric 
6950b57cec5SDimitry Andric   if (FF) { Val = FF(C, D); }
6960b57cec5SDimitry Andric   else if (Injector) { Val = Injector->getBody(D); }
6970b57cec5SDimitry Andric   return Val.getValue();
6980b57cec5SDimitry Andric }
6990b57cec5SDimitry Andric 
7000b57cec5SDimitry Andric static const ObjCIvarDecl *findBackingIvar(const ObjCPropertyDecl *Prop) {
7010b57cec5SDimitry Andric   const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl();
7020b57cec5SDimitry Andric 
7030b57cec5SDimitry Andric   if (IVar)
7040b57cec5SDimitry Andric     return IVar;
7050b57cec5SDimitry Andric 
7060b57cec5SDimitry Andric   // When a readonly property is shadowed in a class extensions with a
7070b57cec5SDimitry Andric   // a readwrite property, the instance variable belongs to the shadowing
7080b57cec5SDimitry Andric   // property rather than the shadowed property. If there is no instance
7090b57cec5SDimitry Andric   // variable on a readonly property, check to see whether the property is
7100b57cec5SDimitry Andric   // shadowed and if so try to get the instance variable from shadowing
7110b57cec5SDimitry Andric   // property.
7120b57cec5SDimitry Andric   if (!Prop->isReadOnly())
7130b57cec5SDimitry Andric     return nullptr;
7140b57cec5SDimitry Andric 
7150b57cec5SDimitry Andric   auto *Container = cast<ObjCContainerDecl>(Prop->getDeclContext());
7160b57cec5SDimitry Andric   const ObjCInterfaceDecl *PrimaryInterface = nullptr;
7170b57cec5SDimitry Andric   if (auto *InterfaceDecl = dyn_cast<ObjCInterfaceDecl>(Container)) {
7180b57cec5SDimitry Andric     PrimaryInterface = InterfaceDecl;
7190b57cec5SDimitry Andric   } else if (auto *CategoryDecl = dyn_cast<ObjCCategoryDecl>(Container)) {
7200b57cec5SDimitry Andric     PrimaryInterface = CategoryDecl->getClassInterface();
7210b57cec5SDimitry Andric   } else if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container)) {
7220b57cec5SDimitry Andric     PrimaryInterface = ImplDecl->getClassInterface();
7230b57cec5SDimitry Andric   } else {
7240b57cec5SDimitry Andric     return nullptr;
7250b57cec5SDimitry Andric   }
7260b57cec5SDimitry Andric 
7270b57cec5SDimitry Andric   // FindPropertyVisibleInPrimaryClass() looks first in class extensions, so it
7280b57cec5SDimitry Andric   // is guaranteed to find the shadowing property, if it exists, rather than
7290b57cec5SDimitry Andric   // the shadowed property.
7300b57cec5SDimitry Andric   auto *ShadowingProp = PrimaryInterface->FindPropertyVisibleInPrimaryClass(
7310b57cec5SDimitry Andric       Prop->getIdentifier(), Prop->getQueryKind());
7320b57cec5SDimitry Andric   if (ShadowingProp && ShadowingProp != Prop) {
7330b57cec5SDimitry Andric     IVar = ShadowingProp->getPropertyIvarDecl();
7340b57cec5SDimitry Andric   }
7350b57cec5SDimitry Andric 
7360b57cec5SDimitry Andric   return IVar;
7370b57cec5SDimitry Andric }
7380b57cec5SDimitry Andric 
7390b57cec5SDimitry Andric static Stmt *createObjCPropertyGetter(ASTContext &Ctx,
740480093f4SDimitry Andric                                       const ObjCMethodDecl *MD) {
7410b57cec5SDimitry Andric     // First, find the backing ivar.
742480093f4SDimitry Andric   const ObjCIvarDecl *IVar = nullptr;
743480093f4SDimitry Andric 
744480093f4SDimitry Andric   // Property accessor stubs sometimes do not correspond to any property decl
745480093f4SDimitry Andric   // in the current interface (but in a superclass). They still have a
746480093f4SDimitry Andric   // corresponding property impl decl in this case.
747480093f4SDimitry Andric   if (MD->isSynthesizedAccessorStub()) {
748480093f4SDimitry Andric     const ObjCInterfaceDecl *IntD = MD->getClassInterface();
749480093f4SDimitry Andric     const ObjCImplementationDecl *ImpD = IntD->getImplementation();
750480093f4SDimitry Andric     for (const auto *PI: ImpD->property_impls()) {
751480093f4SDimitry Andric       if (const ObjCPropertyDecl *P = PI->getPropertyDecl()) {
752480093f4SDimitry Andric         if (P->getGetterName() == MD->getSelector())
753480093f4SDimitry Andric           IVar = P->getPropertyIvarDecl();
754480093f4SDimitry Andric       }
755480093f4SDimitry Andric     }
756480093f4SDimitry Andric   }
757480093f4SDimitry Andric 
758480093f4SDimitry Andric   if (!IVar) {
759480093f4SDimitry Andric     const ObjCPropertyDecl *Prop = MD->findPropertyDecl();
760480093f4SDimitry Andric     IVar = findBackingIvar(Prop);
7610b57cec5SDimitry Andric     if (!IVar)
7620b57cec5SDimitry Andric       return nullptr;
7630b57cec5SDimitry Andric 
7640b57cec5SDimitry Andric     // Ignore weak variables, which have special behavior.
765*5ffd83dbSDimitry Andric     if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak)
7660b57cec5SDimitry Andric       return nullptr;
7670b57cec5SDimitry Andric 
7680b57cec5SDimitry Andric     // Look to see if Sema has synthesized a body for us. This happens in
7690b57cec5SDimitry Andric     // Objective-C++ because the return value may be a C++ class type with a
7700b57cec5SDimitry Andric     // non-trivial copy constructor. We can only do this if we can find the
7710b57cec5SDimitry Andric     // @synthesize for this property, though (or if we know it's been auto-
7720b57cec5SDimitry Andric     // synthesized).
7730b57cec5SDimitry Andric     const ObjCImplementationDecl *ImplDecl =
7740b57cec5SDimitry Andric       IVar->getContainingInterface()->getImplementation();
7750b57cec5SDimitry Andric     if (ImplDecl) {
7760b57cec5SDimitry Andric       for (const auto *I : ImplDecl->property_impls()) {
7770b57cec5SDimitry Andric         if (I->getPropertyDecl() != Prop)
7780b57cec5SDimitry Andric           continue;
7790b57cec5SDimitry Andric 
7800b57cec5SDimitry Andric         if (I->getGetterCXXConstructor()) {
7810b57cec5SDimitry Andric           ASTMaker M(Ctx);
7820b57cec5SDimitry Andric           return M.makeReturn(I->getGetterCXXConstructor());
7830b57cec5SDimitry Andric         }
7840b57cec5SDimitry Andric       }
7850b57cec5SDimitry Andric     }
7860b57cec5SDimitry Andric 
7870b57cec5SDimitry Andric     // Sanity check that the property is the same type as the ivar, or a
7880b57cec5SDimitry Andric     // reference to it, and that it is either an object pointer or trivially
7890b57cec5SDimitry Andric     // copyable.
7900b57cec5SDimitry Andric     if (!Ctx.hasSameUnqualifiedType(IVar->getType(),
7910b57cec5SDimitry Andric                                     Prop->getType().getNonReferenceType()))
7920b57cec5SDimitry Andric       return nullptr;
7930b57cec5SDimitry Andric     if (!IVar->getType()->isObjCLifetimeType() &&
7940b57cec5SDimitry Andric         !IVar->getType().isTriviallyCopyableType(Ctx))
7950b57cec5SDimitry Andric       return nullptr;
796480093f4SDimitry Andric   }
7970b57cec5SDimitry Andric 
7980b57cec5SDimitry Andric   // Generate our body:
7990b57cec5SDimitry Andric   //   return self->_ivar;
8000b57cec5SDimitry Andric   ASTMaker M(Ctx);
8010b57cec5SDimitry Andric 
802480093f4SDimitry Andric   const VarDecl *selfVar = MD->getSelfDecl();
8030b57cec5SDimitry Andric   if (!selfVar)
8040b57cec5SDimitry Andric     return nullptr;
8050b57cec5SDimitry Andric 
8060b57cec5SDimitry Andric   Expr *loadedIVar =
8070b57cec5SDimitry Andric     M.makeObjCIvarRef(
8080b57cec5SDimitry Andric       M.makeLvalueToRvalue(
8090b57cec5SDimitry Andric         M.makeDeclRefExpr(selfVar),
8100b57cec5SDimitry Andric         selfVar->getType()),
8110b57cec5SDimitry Andric       IVar);
8120b57cec5SDimitry Andric 
813480093f4SDimitry Andric   if (!MD->getReturnType()->isReferenceType())
8140b57cec5SDimitry Andric     loadedIVar = M.makeLvalueToRvalue(loadedIVar, IVar->getType());
8150b57cec5SDimitry Andric 
8160b57cec5SDimitry Andric   return M.makeReturn(loadedIVar);
8170b57cec5SDimitry Andric }
8180b57cec5SDimitry Andric 
8190b57cec5SDimitry Andric Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
8200b57cec5SDimitry Andric   // We currently only know how to synthesize property accessors.
8210b57cec5SDimitry Andric   if (!D->isPropertyAccessor())
8220b57cec5SDimitry Andric     return nullptr;
8230b57cec5SDimitry Andric 
8240b57cec5SDimitry Andric   D = D->getCanonicalDecl();
8250b57cec5SDimitry Andric 
8260b57cec5SDimitry Andric   // We should not try to synthesize explicitly redefined accessors.
8270b57cec5SDimitry Andric   // We do not know for sure how they behave.
8280b57cec5SDimitry Andric   if (!D->isImplicit())
8290b57cec5SDimitry Andric     return nullptr;
8300b57cec5SDimitry Andric 
8310b57cec5SDimitry Andric   Optional<Stmt *> &Val = Bodies[D];
8320b57cec5SDimitry Andric   if (Val.hasValue())
8330b57cec5SDimitry Andric     return Val.getValue();
8340b57cec5SDimitry Andric   Val = nullptr;
8350b57cec5SDimitry Andric 
8360b57cec5SDimitry Andric   // For now, we only synthesize getters.
8370b57cec5SDimitry Andric   // Synthesizing setters would cause false negatives in the
8380b57cec5SDimitry Andric   // RetainCountChecker because the method body would bind the parameter
8390b57cec5SDimitry Andric   // to an instance variable, causing it to escape. This would prevent
8400b57cec5SDimitry Andric   // warning in the following common scenario:
8410b57cec5SDimitry Andric   //
8420b57cec5SDimitry Andric   //  id foo = [[NSObject alloc] init];
8430b57cec5SDimitry Andric   //  self.foo = foo; // We should warn that foo leaks here.
8440b57cec5SDimitry Andric   //
8450b57cec5SDimitry Andric   if (D->param_size() != 0)
8460b57cec5SDimitry Andric     return nullptr;
8470b57cec5SDimitry Andric 
848480093f4SDimitry Andric   // If the property was defined in an extension, search the extensions for
849480093f4SDimitry Andric   // overrides.
850480093f4SDimitry Andric   const ObjCInterfaceDecl *OID = D->getClassInterface();
851480093f4SDimitry Andric   if (dyn_cast<ObjCInterfaceDecl>(D->getParent()) != OID)
852480093f4SDimitry Andric     for (auto *Ext : OID->known_extensions()) {
853480093f4SDimitry Andric       auto *OMD = Ext->getInstanceMethod(D->getSelector());
854480093f4SDimitry Andric       if (OMD && !OMD->isImplicit())
855480093f4SDimitry Andric         return nullptr;
856480093f4SDimitry Andric     }
857480093f4SDimitry Andric 
858480093f4SDimitry Andric   Val = createObjCPropertyGetter(C, D);
8590b57cec5SDimitry Andric 
8600b57cec5SDimitry Andric   return Val.getValue();
8610b57cec5SDimitry Andric }
862