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