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, 119fe6060f1SDimitry Andric VK_PRValue, 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, 128fe6060f1SDimitry Andric C.getLogicalOperationType(), VK_PRValue, 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, 172fe6060f1SDimitry Andric /* ExprValueKind=*/VK_PRValue, 173e8d8bef9SDimitry 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); 179e8d8bef9SDimitry Andric return makeImplicitCast(Arg, Ty, CK_IntegralCast); 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) { 183e8d8bef9SDimitry 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 267fe6060f1SDimitry Andric return CallExpr::Create(C, SubExpr, CallArgs, C.VoidTy, VK_PRValue, 268e8d8bef9SDimitry 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, 294fe6060f1SDimitry Andric /*ExprValueType=*/VK_PRValue, 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, 454fe6060f1SDimitry Andric /* ExprValueKind=*/VK_PRValue, 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 = 464349cc55cSDimitry Andric IfStmt::Create(C, SourceLocation(), IfStatementKind::Ordinary, 4650b57cec5SDimitry Andric /* Init=*/nullptr, 4660b57cec5SDimitry Andric /* Var=*/nullptr, 4670b57cec5SDimitry Andric /* Cond=*/FlagCheck, 468e8d8bef9SDimitry Andric /* LPL=*/SourceLocation(), 469e8d8bef9SDimitry Andric /* RPL=*/SourceLocation(), 4700b57cec5SDimitry Andric /* Then=*/M.makeCompound({CallbackCall, FlagAssignment})); 4710b57cec5SDimitry Andric 4720b57cec5SDimitry Andric return Out; 4730b57cec5SDimitry Andric } 4740b57cec5SDimitry Andric 4750b57cec5SDimitry Andric /// Create a fake body for dispatch_once. 4760b57cec5SDimitry Andric static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { 4770b57cec5SDimitry Andric // Check if we have at least two parameters. 4780b57cec5SDimitry Andric if (D->param_size() != 2) 4790b57cec5SDimitry Andric return nullptr; 4800b57cec5SDimitry Andric 4810b57cec5SDimitry Andric // Check if the first parameter is a pointer to integer type. 4820b57cec5SDimitry Andric const ParmVarDecl *Predicate = D->getParamDecl(0); 4830b57cec5SDimitry Andric QualType PredicateQPtrTy = Predicate->getType(); 4840b57cec5SDimitry Andric const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>(); 4850b57cec5SDimitry Andric if (!PredicatePtrTy) 4860b57cec5SDimitry Andric return nullptr; 4870b57cec5SDimitry Andric QualType PredicateTy = PredicatePtrTy->getPointeeType(); 4880b57cec5SDimitry Andric if (!PredicateTy->isIntegerType()) 4890b57cec5SDimitry Andric return nullptr; 4900b57cec5SDimitry Andric 4910b57cec5SDimitry Andric // Check if the second parameter is the proper block type. 4920b57cec5SDimitry Andric const ParmVarDecl *Block = D->getParamDecl(1); 4930b57cec5SDimitry Andric QualType Ty = Block->getType(); 4940b57cec5SDimitry Andric if (!isDispatchBlock(Ty)) 4950b57cec5SDimitry Andric return nullptr; 4960b57cec5SDimitry Andric 4970b57cec5SDimitry Andric // Everything checks out. Create a fakse body that checks the predicate, 4980b57cec5SDimitry Andric // sets it, and calls the block. Basically, an AST dump of: 4990b57cec5SDimitry Andric // 5000b57cec5SDimitry Andric // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) { 5010b57cec5SDimitry Andric // if (*predicate != ~0l) { 5020b57cec5SDimitry Andric // *predicate = ~0l; 5030b57cec5SDimitry Andric // block(); 5040b57cec5SDimitry Andric // } 5050b57cec5SDimitry Andric // } 5060b57cec5SDimitry Andric 5070b57cec5SDimitry Andric ASTMaker M(C); 5080b57cec5SDimitry Andric 5090b57cec5SDimitry Andric // (1) Create the call. 5100b57cec5SDimitry Andric CallExpr *CE = CallExpr::Create( 5110b57cec5SDimitry Andric /*ASTContext=*/C, 5120b57cec5SDimitry Andric /*StmtClass=*/M.makeLvalueToRvalue(/*Expr=*/Block), 5130b57cec5SDimitry Andric /*Args=*/None, 5140b57cec5SDimitry Andric /*QualType=*/C.VoidTy, 515fe6060f1SDimitry Andric /*ExprValueType=*/VK_PRValue, 516e8d8bef9SDimitry Andric /*SourceLocation=*/SourceLocation(), FPOptionsOverride()); 5170b57cec5SDimitry Andric 5180b57cec5SDimitry Andric // (2) Create the assignment to the predicate. 5190b57cec5SDimitry Andric Expr *DoneValue = 5205ffd83dbSDimitry Andric UnaryOperator::Create(C, M.makeIntegerLiteral(0, C.LongTy), UO_Not, 521fe6060f1SDimitry Andric C.LongTy, VK_PRValue, OK_Ordinary, SourceLocation(), 5225ffd83dbSDimitry Andric /*CanOverflow*/ false, FPOptionsOverride()); 5230b57cec5SDimitry Andric 5240b57cec5SDimitry Andric BinaryOperator *B = 5250b57cec5SDimitry Andric M.makeAssignment( 5260b57cec5SDimitry Andric M.makeDereference( 5270b57cec5SDimitry Andric M.makeLvalueToRvalue( 5280b57cec5SDimitry Andric M.makeDeclRefExpr(Predicate), PredicateQPtrTy), 5290b57cec5SDimitry Andric PredicateTy), 5300b57cec5SDimitry Andric M.makeIntegralCast(DoneValue, PredicateTy), 5310b57cec5SDimitry Andric PredicateTy); 5320b57cec5SDimitry Andric 5330b57cec5SDimitry Andric // (3) Create the compound statement. 5340b57cec5SDimitry Andric Stmt *Stmts[] = { B, CE }; 5350b57cec5SDimitry Andric CompoundStmt *CS = M.makeCompound(Stmts); 5360b57cec5SDimitry Andric 5370b57cec5SDimitry Andric // (4) Create the 'if' condition. 5380b57cec5SDimitry Andric ImplicitCastExpr *LValToRval = 5390b57cec5SDimitry Andric M.makeLvalueToRvalue( 5400b57cec5SDimitry Andric M.makeDereference( 5410b57cec5SDimitry Andric M.makeLvalueToRvalue( 5420b57cec5SDimitry Andric M.makeDeclRefExpr(Predicate), 5430b57cec5SDimitry Andric PredicateQPtrTy), 5440b57cec5SDimitry Andric PredicateTy), 5450b57cec5SDimitry Andric PredicateTy); 5460b57cec5SDimitry Andric 5470b57cec5SDimitry Andric Expr *GuardCondition = M.makeComparison(LValToRval, DoneValue, BO_NE); 5480b57cec5SDimitry Andric // (5) Create the 'if' statement. 549349cc55cSDimitry Andric auto *If = IfStmt::Create(C, SourceLocation(), IfStatementKind::Ordinary, 5500b57cec5SDimitry Andric /* Init=*/nullptr, 5510b57cec5SDimitry Andric /* Var=*/nullptr, 5520b57cec5SDimitry Andric /* Cond=*/GuardCondition, 553e8d8bef9SDimitry Andric /* LPL=*/SourceLocation(), 554e8d8bef9SDimitry Andric /* RPL=*/SourceLocation(), 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); 581fe6060f1SDimitry Andric CallExpr *CE = CallExpr::Create(C, ICE, None, C.VoidTy, VK_PRValue, 582e8d8bef9SDimitry Andric SourceLocation(), FPOptionsOverride()); 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. 658e8d8bef9SDimitry Andric auto *If = 659349cc55cSDimitry Andric IfStmt::Create(C, SourceLocation(), IfStatementKind::Ordinary, 6600b57cec5SDimitry Andric /* Init=*/nullptr, 661e8d8bef9SDimitry Andric /* Var=*/nullptr, Comparison, 662e8d8bef9SDimitry Andric /* LPL=*/SourceLocation(), 663e8d8bef9SDimitry Andric /* RPL=*/SourceLocation(), Body, SourceLocation(), Else); 6640b57cec5SDimitry Andric 6650b57cec5SDimitry Andric return If; 6660b57cec5SDimitry Andric } 6670b57cec5SDimitry Andric 6680b57cec5SDimitry Andric Stmt *BodyFarm::getBody(const FunctionDecl *D) { 6690b57cec5SDimitry Andric Optional<Stmt *> &Val = Bodies[D]; 6700b57cec5SDimitry Andric if (Val.hasValue()) 6710b57cec5SDimitry Andric return Val.getValue(); 6720b57cec5SDimitry Andric 6730b57cec5SDimitry Andric Val = nullptr; 6740b57cec5SDimitry Andric 6750b57cec5SDimitry Andric if (D->getIdentifier() == nullptr) 6760b57cec5SDimitry Andric return nullptr; 6770b57cec5SDimitry Andric 6780b57cec5SDimitry Andric StringRef Name = D->getName(); 6790b57cec5SDimitry Andric if (Name.empty()) 6800b57cec5SDimitry Andric return nullptr; 6810b57cec5SDimitry Andric 6820b57cec5SDimitry Andric FunctionFarmer FF; 6830b57cec5SDimitry Andric 6840b57cec5SDimitry Andric if (Name.startswith("OSAtomicCompareAndSwap") || 6850b57cec5SDimitry Andric Name.startswith("objc_atomicCompareAndSwap")) { 6860b57cec5SDimitry Andric FF = create_OSAtomicCompareAndSwap; 6870b57cec5SDimitry Andric } else if (Name == "call_once" && D->getDeclContext()->isStdNamespace()) { 6880b57cec5SDimitry Andric FF = create_call_once; 6890b57cec5SDimitry Andric } else { 6900b57cec5SDimitry Andric FF = llvm::StringSwitch<FunctionFarmer>(Name) 6910b57cec5SDimitry Andric .Case("dispatch_sync", create_dispatch_sync) 6920b57cec5SDimitry Andric .Case("dispatch_once", create_dispatch_once) 6930b57cec5SDimitry Andric .Default(nullptr); 6940b57cec5SDimitry Andric } 6950b57cec5SDimitry Andric 6960b57cec5SDimitry Andric if (FF) { Val = FF(C, D); } 6970b57cec5SDimitry Andric else if (Injector) { Val = Injector->getBody(D); } 6980b57cec5SDimitry Andric return Val.getValue(); 6990b57cec5SDimitry Andric } 7000b57cec5SDimitry Andric 7010b57cec5SDimitry Andric static const ObjCIvarDecl *findBackingIvar(const ObjCPropertyDecl *Prop) { 7020b57cec5SDimitry Andric const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl(); 7030b57cec5SDimitry Andric 7040b57cec5SDimitry Andric if (IVar) 7050b57cec5SDimitry Andric return IVar; 7060b57cec5SDimitry Andric 7070b57cec5SDimitry Andric // When a readonly property is shadowed in a class extensions with a 7080b57cec5SDimitry Andric // a readwrite property, the instance variable belongs to the shadowing 7090b57cec5SDimitry Andric // property rather than the shadowed property. If there is no instance 7100b57cec5SDimitry Andric // variable on a readonly property, check to see whether the property is 7110b57cec5SDimitry Andric // shadowed and if so try to get the instance variable from shadowing 7120b57cec5SDimitry Andric // property. 7130b57cec5SDimitry Andric if (!Prop->isReadOnly()) 7140b57cec5SDimitry Andric return nullptr; 7150b57cec5SDimitry Andric 7160b57cec5SDimitry Andric auto *Container = cast<ObjCContainerDecl>(Prop->getDeclContext()); 7170b57cec5SDimitry Andric const ObjCInterfaceDecl *PrimaryInterface = nullptr; 7180b57cec5SDimitry Andric if (auto *InterfaceDecl = dyn_cast<ObjCInterfaceDecl>(Container)) { 7190b57cec5SDimitry Andric PrimaryInterface = InterfaceDecl; 7200b57cec5SDimitry Andric } else if (auto *CategoryDecl = dyn_cast<ObjCCategoryDecl>(Container)) { 7210b57cec5SDimitry Andric PrimaryInterface = CategoryDecl->getClassInterface(); 7220b57cec5SDimitry Andric } else if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container)) { 7230b57cec5SDimitry Andric PrimaryInterface = ImplDecl->getClassInterface(); 7240b57cec5SDimitry Andric } else { 7250b57cec5SDimitry Andric return nullptr; 7260b57cec5SDimitry Andric } 7270b57cec5SDimitry Andric 7280b57cec5SDimitry Andric // FindPropertyVisibleInPrimaryClass() looks first in class extensions, so it 7290b57cec5SDimitry Andric // is guaranteed to find the shadowing property, if it exists, rather than 7300b57cec5SDimitry Andric // the shadowed property. 7310b57cec5SDimitry Andric auto *ShadowingProp = PrimaryInterface->FindPropertyVisibleInPrimaryClass( 7320b57cec5SDimitry Andric Prop->getIdentifier(), Prop->getQueryKind()); 7330b57cec5SDimitry Andric if (ShadowingProp && ShadowingProp != Prop) { 7340b57cec5SDimitry Andric IVar = ShadowingProp->getPropertyIvarDecl(); 7350b57cec5SDimitry Andric } 7360b57cec5SDimitry Andric 7370b57cec5SDimitry Andric return IVar; 7380b57cec5SDimitry Andric } 7390b57cec5SDimitry Andric 7400b57cec5SDimitry Andric static Stmt *createObjCPropertyGetter(ASTContext &Ctx, 741480093f4SDimitry Andric const ObjCMethodDecl *MD) { 7420b57cec5SDimitry Andric // First, find the backing ivar. 743480093f4SDimitry Andric const ObjCIvarDecl *IVar = nullptr; 744fe6060f1SDimitry Andric const ObjCPropertyDecl *Prop = nullptr; 745480093f4SDimitry Andric 746480093f4SDimitry Andric // Property accessor stubs sometimes do not correspond to any property decl 747480093f4SDimitry Andric // in the current interface (but in a superclass). They still have a 748480093f4SDimitry Andric // corresponding property impl decl in this case. 749480093f4SDimitry Andric if (MD->isSynthesizedAccessorStub()) { 750480093f4SDimitry Andric const ObjCInterfaceDecl *IntD = MD->getClassInterface(); 751480093f4SDimitry Andric const ObjCImplementationDecl *ImpD = IntD->getImplementation(); 752480093f4SDimitry Andric for (const auto *PI : ImpD->property_impls()) { 753fe6060f1SDimitry Andric if (const ObjCPropertyDecl *Candidate = PI->getPropertyDecl()) { 754fe6060f1SDimitry Andric if (Candidate->getGetterName() == MD->getSelector()) { 755fe6060f1SDimitry Andric Prop = Candidate; 756fe6060f1SDimitry Andric IVar = Prop->getPropertyIvarDecl(); 757fe6060f1SDimitry Andric } 758480093f4SDimitry Andric } 759480093f4SDimitry Andric } 760480093f4SDimitry Andric } 761480093f4SDimitry Andric 762480093f4SDimitry Andric if (!IVar) { 763fe6060f1SDimitry Andric Prop = MD->findPropertyDecl(); 764480093f4SDimitry Andric IVar = findBackingIvar(Prop); 765fe6060f1SDimitry Andric } 766fe6060f1SDimitry Andric 767fe6060f1SDimitry Andric if (!IVar || !Prop) 7680b57cec5SDimitry Andric return nullptr; 7690b57cec5SDimitry Andric 7700b57cec5SDimitry Andric // Ignore weak variables, which have special behavior. 7715ffd83dbSDimitry Andric if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak) 7720b57cec5SDimitry Andric return nullptr; 7730b57cec5SDimitry Andric 7740b57cec5SDimitry Andric // Look to see if Sema has synthesized a body for us. This happens in 7750b57cec5SDimitry Andric // Objective-C++ because the return value may be a C++ class type with a 7760b57cec5SDimitry Andric // non-trivial copy constructor. We can only do this if we can find the 7770b57cec5SDimitry Andric // @synthesize for this property, though (or if we know it's been auto- 7780b57cec5SDimitry Andric // synthesized). 7790b57cec5SDimitry Andric const ObjCImplementationDecl *ImplDecl = 7800b57cec5SDimitry Andric IVar->getContainingInterface()->getImplementation(); 7810b57cec5SDimitry Andric if (ImplDecl) { 7820b57cec5SDimitry Andric for (const auto *I : ImplDecl->property_impls()) { 7830b57cec5SDimitry Andric if (I->getPropertyDecl() != Prop) 7840b57cec5SDimitry Andric continue; 7850b57cec5SDimitry Andric 7860b57cec5SDimitry Andric if (I->getGetterCXXConstructor()) { 7870b57cec5SDimitry Andric ASTMaker M(Ctx); 7880b57cec5SDimitry Andric return M.makeReturn(I->getGetterCXXConstructor()); 7890b57cec5SDimitry Andric } 7900b57cec5SDimitry Andric } 7910b57cec5SDimitry Andric } 7920b57cec5SDimitry Andric 7935e801ac6SDimitry Andric // We expect that the property is the same type as the ivar, or a reference to 7945e801ac6SDimitry Andric // it, and that it is either an object pointer or trivially copyable. 7950b57cec5SDimitry Andric if (!Ctx.hasSameUnqualifiedType(IVar->getType(), 7960b57cec5SDimitry Andric Prop->getType().getNonReferenceType())) 7970b57cec5SDimitry Andric return nullptr; 7980b57cec5SDimitry Andric if (!IVar->getType()->isObjCLifetimeType() && 7990b57cec5SDimitry Andric !IVar->getType().isTriviallyCopyableType(Ctx)) 8000b57cec5SDimitry Andric return nullptr; 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 810fe6060f1SDimitry Andric Expr *loadedIVar = M.makeObjCIvarRef( 811fe6060f1SDimitry Andric M.makeLvalueToRvalue(M.makeDeclRefExpr(selfVar), selfVar->getType()), 8120b57cec5SDimitry Andric IVar); 8130b57cec5SDimitry Andric 814480093f4SDimitry Andric if (!MD->getReturnType()->isReferenceType()) 8150b57cec5SDimitry Andric loadedIVar = M.makeLvalueToRvalue(loadedIVar, IVar->getType()); 8160b57cec5SDimitry Andric 8170b57cec5SDimitry Andric return M.makeReturn(loadedIVar); 8180b57cec5SDimitry Andric } 8190b57cec5SDimitry Andric 8200b57cec5SDimitry Andric Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) { 8210b57cec5SDimitry Andric // We currently only know how to synthesize property accessors. 8220b57cec5SDimitry Andric if (!D->isPropertyAccessor()) 8230b57cec5SDimitry Andric return nullptr; 8240b57cec5SDimitry Andric 8250b57cec5SDimitry Andric D = D->getCanonicalDecl(); 8260b57cec5SDimitry Andric 8270b57cec5SDimitry Andric // We should not try to synthesize explicitly redefined accessors. 8280b57cec5SDimitry Andric // We do not know for sure how they behave. 8290b57cec5SDimitry Andric if (!D->isImplicit()) 8300b57cec5SDimitry Andric return nullptr; 8310b57cec5SDimitry Andric 8320b57cec5SDimitry Andric Optional<Stmt *> &Val = Bodies[D]; 8330b57cec5SDimitry Andric if (Val.hasValue()) 8340b57cec5SDimitry Andric return Val.getValue(); 8350b57cec5SDimitry Andric Val = nullptr; 8360b57cec5SDimitry Andric 8370b57cec5SDimitry Andric // For now, we only synthesize getters. 8380b57cec5SDimitry Andric // Synthesizing setters would cause false negatives in the 8390b57cec5SDimitry Andric // RetainCountChecker because the method body would bind the parameter 8400b57cec5SDimitry Andric // to an instance variable, causing it to escape. This would prevent 8410b57cec5SDimitry Andric // warning in the following common scenario: 8420b57cec5SDimitry Andric // 8430b57cec5SDimitry Andric // id foo = [[NSObject alloc] init]; 8440b57cec5SDimitry Andric // self.foo = foo; // We should warn that foo leaks here. 8450b57cec5SDimitry Andric // 8460b57cec5SDimitry Andric if (D->param_size() != 0) 8470b57cec5SDimitry Andric return nullptr; 8480b57cec5SDimitry Andric 849480093f4SDimitry Andric // If the property was defined in an extension, search the extensions for 850480093f4SDimitry Andric // overrides. 851480093f4SDimitry Andric const ObjCInterfaceDecl *OID = D->getClassInterface(); 852480093f4SDimitry Andric if (dyn_cast<ObjCInterfaceDecl>(D->getParent()) != OID) 853480093f4SDimitry Andric for (auto *Ext : OID->known_extensions()) { 854480093f4SDimitry Andric auto *OMD = Ext->getInstanceMethod(D->getSelector()); 855480093f4SDimitry Andric if (OMD && !OMD->isImplicit()) 856480093f4SDimitry Andric return nullptr; 857480093f4SDimitry Andric } 858480093f4SDimitry Andric 859480093f4SDimitry Andric Val = createObjCPropertyGetter(C, D); 8600b57cec5SDimitry Andric 8610b57cec5SDimitry Andric return Val.getValue(); 8620b57cec5SDimitry Andric } 863