1243791Sdim//== BodyFarm.cpp - Factory for conjuring up fake bodies ----------*- C++ -*-// 2243791Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6243791Sdim// 7243791Sdim//===----------------------------------------------------------------------===// 8243791Sdim// 9243791Sdim// BodyFarm is a factory for creating faux implementations for functions/methods 10243791Sdim// for analysis purposes. 11243791Sdim// 12243791Sdim//===----------------------------------------------------------------------===// 13243791Sdim 14327952Sdim#include "clang/Analysis/BodyFarm.h" 15243791Sdim#include "clang/AST/ASTContext.h" 16327952Sdim#include "clang/AST/CXXInheritance.h" 17249423Sdim#include "clang/AST/Decl.h" 18243791Sdim#include "clang/AST/Expr.h" 19327952Sdim#include "clang/AST/ExprCXX.h" 20243791Sdim#include "clang/AST/ExprObjC.h" 21327952Sdim#include "clang/AST/NestedNameSpecifier.h" 22280031Sdim#include "clang/Analysis/CodeInjector.h" 23327952Sdim#include "clang/Basic/OperatorKinds.h" 24249423Sdim#include "llvm/ADT/StringSwitch.h" 25327952Sdim#include "llvm/Support/Debug.h" 26243791Sdim 27327952Sdim#define DEBUG_TYPE "body-farm" 28327952Sdim 29243791Sdimusing namespace clang; 30243791Sdim 31243791Sdim//===----------------------------------------------------------------------===// 32243791Sdim// Helper creation functions for constructing faux ASTs. 33243791Sdim//===----------------------------------------------------------------------===// 34243791Sdim 35243791Sdimstatic bool isDispatchBlock(QualType Ty) { 36243791Sdim // Is it a block pointer? 37243791Sdim const BlockPointerType *BPT = Ty->getAs<BlockPointerType>(); 38243791Sdim if (!BPT) 39243791Sdim return false; 40243791Sdim 41243791Sdim // Check if the block pointer type takes no arguments and 42243791Sdim // returns void. 43243791Sdim const FunctionProtoType *FT = 44243791Sdim BPT->getPointeeType()->getAs<FunctionProtoType>(); 45296417Sdim return FT && FT->getReturnType()->isVoidType() && FT->getNumParams() == 0; 46243791Sdim} 47243791Sdim 48243791Sdimnamespace { 49243791Sdimclass ASTMaker { 50243791Sdimpublic: 51243791Sdim ASTMaker(ASTContext &C) : C(C) {} 52341825Sdim 53243791Sdim /// Create a new BinaryOperator representing a simple assignment. 54243791Sdim BinaryOperator *makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty); 55341825Sdim 56243791Sdim /// Create a new BinaryOperator representing a comparison. 57243791Sdim BinaryOperator *makeComparison(const Expr *LHS, const Expr *RHS, 58243791Sdim BinaryOperator::Opcode Op); 59341825Sdim 60243791Sdim /// Create a new compound stmt using the provided statements. 61243791Sdim CompoundStmt *makeCompound(ArrayRef<Stmt*>); 62341825Sdim 63243791Sdim /// Create a new DeclRefExpr for the referenced variable. 64327952Sdim DeclRefExpr *makeDeclRefExpr(const VarDecl *D, 65327952Sdim bool RefersToEnclosingVariableOrCapture = false); 66341825Sdim 67243791Sdim /// Create a new UnaryOperator representing a dereference. 68243791Sdim UnaryOperator *makeDereference(const Expr *Arg, QualType Ty); 69341825Sdim 70243791Sdim /// Create an implicit cast for an integer conversion. 71243791Sdim Expr *makeIntegralCast(const Expr *Arg, QualType Ty); 72341825Sdim 73243791Sdim /// Create an implicit cast to a builtin boolean type. 74243791Sdim ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg); 75341825Sdim 76327952Sdim /// Create an implicit cast for lvalue-to-rvaluate conversions. 77243791Sdim ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty); 78341825Sdim 79327952Sdim /// Make RValue out of variable declaration, creating a temporary 80327952Sdim /// DeclRefExpr in the process. 81327952Sdim ImplicitCastExpr * 82327952Sdim makeLvalueToRvalue(const VarDecl *Decl, 83327952Sdim bool RefersToEnclosingVariableOrCapture = false); 84327952Sdim 85327952Sdim /// Create an implicit cast of the given type. 86327952Sdim ImplicitCastExpr *makeImplicitCast(const Expr *Arg, QualType Ty, 87327952Sdim CastKind CK = CK_LValueToRValue); 88327952Sdim 89243791Sdim /// Create an Objective-C bool literal. 90243791Sdim ObjCBoolLiteralExpr *makeObjCBool(bool Val); 91276479Sdim 92276479Sdim /// Create an Objective-C ivar reference. 93276479Sdim ObjCIvarRefExpr *makeObjCIvarRef(const Expr *Base, const ObjCIvarDecl *IVar); 94341825Sdim 95243791Sdim /// Create a Return statement. 96243791Sdim ReturnStmt *makeReturn(const Expr *RetVal); 97341825Sdim 98327952Sdim /// Create an integer literal expression of the given type. 99327952Sdim IntegerLiteral *makeIntegerLiteral(uint64_t Value, QualType Ty); 100327952Sdim 101327952Sdim /// Create a member expression. 102327952Sdim MemberExpr *makeMemberExpression(Expr *base, ValueDecl *MemberDecl, 103327952Sdim bool IsArrow = false, 104327952Sdim ExprValueKind ValueKind = VK_LValue); 105327952Sdim 106327952Sdim /// Returns a *first* member field of a record declaration with a given name. 107327952Sdim /// \return an nullptr if no member with such a name exists. 108327952Sdim ValueDecl *findMemberField(const RecordDecl *RD, StringRef Name); 109327952Sdim 110243791Sdimprivate: 111243791Sdim ASTContext &C; 112243791Sdim}; 113243791Sdim} 114243791Sdim 115243791SdimBinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS, 116243791Sdim QualType Ty) { 117243791Sdim return new (C) BinaryOperator(const_cast<Expr*>(LHS), const_cast<Expr*>(RHS), 118243791Sdim BO_Assign, Ty, VK_RValue, 119321369Sdim OK_Ordinary, SourceLocation(), FPOptions()); 120243791Sdim} 121243791Sdim 122243791SdimBinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS, 123243791Sdim BinaryOperator::Opcode Op) { 124243791Sdim assert(BinaryOperator::isLogicalOp(Op) || 125243791Sdim BinaryOperator::isComparisonOp(Op)); 126243791Sdim return new (C) BinaryOperator(const_cast<Expr*>(LHS), 127243791Sdim const_cast<Expr*>(RHS), 128243791Sdim Op, 129243791Sdim C.getLogicalOperationType(), 130243791Sdim VK_RValue, 131321369Sdim OK_Ordinary, SourceLocation(), FPOptions()); 132243791Sdim} 133243791Sdim 134243791SdimCompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) { 135327952Sdim return CompoundStmt::Create(C, Stmts, SourceLocation(), SourceLocation()); 136243791Sdim} 137243791Sdim 138327952SdimDeclRefExpr *ASTMaker::makeDeclRefExpr( 139327952Sdim const VarDecl *D, 140327952Sdim bool RefersToEnclosingVariableOrCapture) { 141327952Sdim QualType Type = D->getType().getNonReferenceType(); 142327952Sdim 143327952Sdim DeclRefExpr *DR = DeclRefExpr::Create( 144327952Sdim C, NestedNameSpecifierLoc(), SourceLocation(), const_cast<VarDecl *>(D), 145327952Sdim RefersToEnclosingVariableOrCapture, SourceLocation(), Type, VK_LValue); 146243791Sdim return DR; 147243791Sdim} 148243791Sdim 149243791SdimUnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) { 150243791Sdim return new (C) UnaryOperator(const_cast<Expr*>(Arg), UO_Deref, Ty, 151341825Sdim VK_LValue, OK_Ordinary, SourceLocation(), 152341825Sdim /*CanOverflow*/ false); 153243791Sdim} 154243791Sdim 155243791SdimImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) { 156327952Sdim return makeImplicitCast(Arg, Ty, CK_LValueToRValue); 157243791Sdim} 158243791Sdim 159327952SdimImplicitCastExpr * 160327952SdimASTMaker::makeLvalueToRvalue(const VarDecl *Arg, 161327952Sdim bool RefersToEnclosingVariableOrCapture) { 162327952Sdim QualType Type = Arg->getType().getNonReferenceType(); 163327952Sdim return makeLvalueToRvalue(makeDeclRefExpr(Arg, 164327952Sdim RefersToEnclosingVariableOrCapture), 165327952Sdim Type); 166327952Sdim} 167327952Sdim 168327952SdimImplicitCastExpr *ASTMaker::makeImplicitCast(const Expr *Arg, QualType Ty, 169327952Sdim CastKind CK) { 170327952Sdim return ImplicitCastExpr::Create(C, Ty, 171327952Sdim /* CastKind=*/ CK, 172327952Sdim /* Expr=*/ const_cast<Expr *>(Arg), 173327952Sdim /* CXXCastPath=*/ nullptr, 174327952Sdim /* ExprValueKind=*/ VK_RValue); 175327952Sdim} 176327952Sdim 177243791SdimExpr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) { 178243791Sdim if (Arg->getType() == Ty) 179243791Sdim return const_cast<Expr*>(Arg); 180276479Sdim 181243791Sdim return ImplicitCastExpr::Create(C, Ty, CK_IntegralCast, 182276479Sdim const_cast<Expr*>(Arg), nullptr, VK_RValue); 183243791Sdim} 184243791Sdim 185243791SdimImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) { 186243791Sdim return ImplicitCastExpr::Create(C, C.BoolTy, CK_IntegralToBoolean, 187276479Sdim const_cast<Expr*>(Arg), nullptr, VK_RValue); 188243791Sdim} 189243791Sdim 190243791SdimObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) { 191243791Sdim QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy; 192243791Sdim return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation()); 193243791Sdim} 194243791Sdim 195276479SdimObjCIvarRefExpr *ASTMaker::makeObjCIvarRef(const Expr *Base, 196276479Sdim const ObjCIvarDecl *IVar) { 197276479Sdim return new (C) ObjCIvarRefExpr(const_cast<ObjCIvarDecl*>(IVar), 198276479Sdim IVar->getType(), SourceLocation(), 199276479Sdim SourceLocation(), const_cast<Expr*>(Base), 200276479Sdim /*arrow=*/true, /*free=*/false); 201276479Sdim} 202276479Sdim 203243791SdimReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) { 204344779Sdim return ReturnStmt::Create(C, SourceLocation(), const_cast<Expr *>(RetVal), 205344779Sdim /* NRVOCandidate=*/nullptr); 206243791Sdim} 207243791Sdim 208327952SdimIntegerLiteral *ASTMaker::makeIntegerLiteral(uint64_t Value, QualType Ty) { 209327952Sdim llvm::APInt APValue = llvm::APInt(C.getTypeSize(Ty), Value); 210327952Sdim return IntegerLiteral::Create(C, APValue, Ty, SourceLocation()); 211327952Sdim} 212327952Sdim 213327952SdimMemberExpr *ASTMaker::makeMemberExpression(Expr *base, ValueDecl *MemberDecl, 214327952Sdim bool IsArrow, 215327952Sdim ExprValueKind ValueKind) { 216327952Sdim 217327952Sdim DeclAccessPair FoundDecl = DeclAccessPair::make(MemberDecl, AS_public); 218327952Sdim return MemberExpr::Create( 219327952Sdim C, base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(), 220327952Sdim SourceLocation(), MemberDecl, FoundDecl, 221327952Sdim DeclarationNameInfo(MemberDecl->getDeclName(), SourceLocation()), 222327952Sdim /* TemplateArgumentListInfo=*/ nullptr, MemberDecl->getType(), ValueKind, 223353358Sdim OK_Ordinary, NOUR_None); 224327952Sdim} 225327952Sdim 226327952SdimValueDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) { 227327952Sdim 228327952Sdim CXXBasePaths Paths( 229327952Sdim /* FindAmbiguities=*/false, 230327952Sdim /* RecordPaths=*/false, 231327952Sdim /* DetectVirtual=*/ false); 232327952Sdim const IdentifierInfo &II = C.Idents.get(Name); 233327952Sdim DeclarationName DeclName = C.DeclarationNames.getIdentifier(&II); 234327952Sdim 235327952Sdim DeclContextLookupResult Decls = RD->lookup(DeclName); 236327952Sdim for (NamedDecl *FoundDecl : Decls) 237327952Sdim if (!FoundDecl->getDeclContext()->isFunctionOrMethod()) 238327952Sdim return cast<ValueDecl>(FoundDecl); 239327952Sdim 240327952Sdim return nullptr; 241327952Sdim} 242327952Sdim 243243791Sdim//===----------------------------------------------------------------------===// 244243791Sdim// Creation functions for faux ASTs. 245243791Sdim//===----------------------------------------------------------------------===// 246243791Sdim 247243791Sdimtypedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D); 248243791Sdim 249327952Sdimstatic CallExpr *create_call_once_funcptr_call(ASTContext &C, ASTMaker M, 250327952Sdim const ParmVarDecl *Callback, 251327952Sdim ArrayRef<Expr *> CallArgs) { 252327952Sdim 253327952Sdim QualType Ty = Callback->getType(); 254327952Sdim DeclRefExpr *Call = M.makeDeclRefExpr(Callback); 255341825Sdim Expr *SubExpr; 256327952Sdim if (Ty->isRValueReferenceType()) { 257341825Sdim SubExpr = M.makeImplicitCast( 258341825Sdim Call, Ty.getNonReferenceType(), CK_LValueToRValue); 259341825Sdim } else if (Ty->isLValueReferenceType() && 260341825Sdim Call->getType()->isFunctionType()) { 261341825Sdim Ty = C.getPointerType(Ty.getNonReferenceType()); 262341825Sdim SubExpr = M.makeImplicitCast(Call, Ty, CK_FunctionToPointerDecay); 263341825Sdim } else if (Ty->isLValueReferenceType() 264341825Sdim && Call->getType()->isPointerType() 265341825Sdim && Call->getType()->getPointeeType()->isFunctionType()){ 266341825Sdim SubExpr = Call; 267327952Sdim } else { 268341825Sdim llvm_unreachable("Unexpected state"); 269327952Sdim } 270327952Sdim 271344779Sdim return CallExpr::Create(C, SubExpr, CallArgs, C.VoidTy, VK_RValue, 272344779Sdim SourceLocation()); 273327952Sdim} 274327952Sdim 275327952Sdimstatic CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M, 276327952Sdim const ParmVarDecl *Callback, 277327952Sdim CXXRecordDecl *CallbackDecl, 278327952Sdim ArrayRef<Expr *> CallArgs) { 279327952Sdim assert(CallbackDecl != nullptr); 280327952Sdim assert(CallbackDecl->isLambda()); 281327952Sdim FunctionDecl *callOperatorDecl = CallbackDecl->getLambdaCallOperator(); 282327952Sdim assert(callOperatorDecl != nullptr); 283327952Sdim 284327952Sdim DeclRefExpr *callOperatorDeclRef = 285327952Sdim DeclRefExpr::Create(/* Ctx =*/ C, 286327952Sdim /* QualifierLoc =*/ NestedNameSpecifierLoc(), 287327952Sdim /* TemplateKWLoc =*/ SourceLocation(), 288327952Sdim const_cast<FunctionDecl *>(callOperatorDecl), 289327952Sdim /* RefersToEnclosingVariableOrCapture=*/ false, 290327952Sdim /* NameLoc =*/ SourceLocation(), 291327952Sdim /* T =*/ callOperatorDecl->getType(), 292327952Sdim /* VK =*/ VK_LValue); 293327952Sdim 294344779Sdim return CXXOperatorCallExpr::Create( 295344779Sdim /*AstContext=*/C, OO_Call, callOperatorDeclRef, 296353358Sdim /*Args=*/CallArgs, 297344779Sdim /*QualType=*/C.VoidTy, 298344779Sdim /*ExprValueType=*/VK_RValue, 299344779Sdim /*SourceLocation=*/SourceLocation(), FPOptions()); 300327952Sdim} 301327952Sdim 302327952Sdim/// Create a fake body for std::call_once. 303327952Sdim/// Emulates the following function body: 304327952Sdim/// 305327952Sdim/// \code 306327952Sdim/// typedef struct once_flag_s { 307327952Sdim/// unsigned long __state = 0; 308327952Sdim/// } once_flag; 309327952Sdim/// template<class Callable> 310327952Sdim/// void call_once(once_flag& o, Callable func) { 311327952Sdim/// if (!o.__state) { 312327952Sdim/// func(); 313327952Sdim/// } 314327952Sdim/// o.__state = 1; 315327952Sdim/// } 316327952Sdim/// \endcode 317327952Sdimstatic Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) { 318341825Sdim LLVM_DEBUG(llvm::dbgs() << "Generating body for call_once\n"); 319327952Sdim 320327952Sdim // We need at least two parameters. 321327952Sdim if (D->param_size() < 2) 322327952Sdim return nullptr; 323327952Sdim 324327952Sdim ASTMaker M(C); 325327952Sdim 326327952Sdim const ParmVarDecl *Flag = D->getParamDecl(0); 327327952Sdim const ParmVarDecl *Callback = D->getParamDecl(1); 328327952Sdim 329327952Sdim if (!Callback->getType()->isReferenceType()) { 330327952Sdim llvm::dbgs() << "libcxx03 std::call_once implementation, skipping.\n"; 331327952Sdim return nullptr; 332327952Sdim } 333327952Sdim if (!Flag->getType()->isReferenceType()) { 334327952Sdim llvm::dbgs() << "unknown std::call_once implementation, skipping.\n"; 335327952Sdim return nullptr; 336327952Sdim } 337327952Sdim 338327952Sdim QualType CallbackType = Callback->getType().getNonReferenceType(); 339327952Sdim 340327952Sdim // Nullable pointer, non-null iff function is a CXXRecordDecl. 341327952Sdim CXXRecordDecl *CallbackRecordDecl = CallbackType->getAsCXXRecordDecl(); 342327952Sdim QualType FlagType = Flag->getType().getNonReferenceType(); 343341825Sdim auto *FlagRecordDecl = FlagType->getAsRecordDecl(); 344327952Sdim 345327952Sdim if (!FlagRecordDecl) { 346341825Sdim LLVM_DEBUG(llvm::dbgs() << "Flag field is not a record: " 347341825Sdim << "unknown std::call_once implementation, " 348341825Sdim << "ignoring the call.\n"); 349327952Sdim return nullptr; 350327952Sdim } 351327952Sdim 352327952Sdim // We initially assume libc++ implementation of call_once, 353327952Sdim // where the once_flag struct has a field `__state_`. 354327952Sdim ValueDecl *FlagFieldDecl = M.findMemberField(FlagRecordDecl, "__state_"); 355327952Sdim 356327952Sdim // Otherwise, try libstdc++ implementation, with a field 357327952Sdim // `_M_once` 358327952Sdim if (!FlagFieldDecl) { 359327952Sdim FlagFieldDecl = M.findMemberField(FlagRecordDecl, "_M_once"); 360327952Sdim } 361327952Sdim 362327952Sdim if (!FlagFieldDecl) { 363341825Sdim LLVM_DEBUG(llvm::dbgs() << "No field _M_once or __state_ found on " 364341825Sdim << "std::once_flag struct: unknown std::call_once " 365341825Sdim << "implementation, ignoring the call."); 366327952Sdim return nullptr; 367327952Sdim } 368327952Sdim 369327952Sdim bool isLambdaCall = CallbackRecordDecl && CallbackRecordDecl->isLambda(); 370327952Sdim if (CallbackRecordDecl && !isLambdaCall) { 371341825Sdim LLVM_DEBUG(llvm::dbgs() 372341825Sdim << "Not supported: synthesizing body for functors when " 373341825Sdim << "body farming std::call_once, ignoring the call."); 374327952Sdim return nullptr; 375327952Sdim } 376327952Sdim 377327952Sdim SmallVector<Expr *, 5> CallArgs; 378327952Sdim const FunctionProtoType *CallbackFunctionType; 379327952Sdim if (isLambdaCall) { 380327952Sdim 381327952Sdim // Lambda requires callback itself inserted as a first parameter. 382327952Sdim CallArgs.push_back( 383327952Sdim M.makeDeclRefExpr(Callback, 384327952Sdim /* RefersToEnclosingVariableOrCapture=*/ true)); 385327952Sdim CallbackFunctionType = CallbackRecordDecl->getLambdaCallOperator() 386327952Sdim ->getType() 387327952Sdim ->getAs<FunctionProtoType>(); 388327952Sdim } else if (!CallbackType->getPointeeType().isNull()) { 389327952Sdim CallbackFunctionType = 390327952Sdim CallbackType->getPointeeType()->getAs<FunctionProtoType>(); 391327952Sdim } else { 392327952Sdim CallbackFunctionType = CallbackType->getAs<FunctionProtoType>(); 393327952Sdim } 394327952Sdim 395327952Sdim if (!CallbackFunctionType) 396327952Sdim return nullptr; 397327952Sdim 398327952Sdim // First two arguments are used for the flag and for the callback. 399327952Sdim if (D->getNumParams() != CallbackFunctionType->getNumParams() + 2) { 400341825Sdim LLVM_DEBUG(llvm::dbgs() << "Types of params of the callback do not match " 401341825Sdim << "params passed to std::call_once, " 402341825Sdim << "ignoring the call\n"); 403327952Sdim return nullptr; 404327952Sdim } 405327952Sdim 406327952Sdim // All arguments past first two ones are passed to the callback, 407327952Sdim // and we turn lvalues into rvalues if the argument is not passed by 408327952Sdim // reference. 409327952Sdim for (unsigned int ParamIdx = 2; ParamIdx < D->getNumParams(); ParamIdx++) { 410327952Sdim const ParmVarDecl *PDecl = D->getParamDecl(ParamIdx); 411360784Sdim assert(PDecl); 412360784Sdim if (CallbackFunctionType->getParamType(ParamIdx - 2) 413341825Sdim .getNonReferenceType() 414341825Sdim .getCanonicalType() != 415341825Sdim PDecl->getType().getNonReferenceType().getCanonicalType()) { 416341825Sdim LLVM_DEBUG(llvm::dbgs() << "Types of params of the callback do not match " 417341825Sdim << "params passed to std::call_once, " 418341825Sdim << "ignoring the call\n"); 419341825Sdim return nullptr; 420341825Sdim } 421327952Sdim Expr *ParamExpr = M.makeDeclRefExpr(PDecl); 422327952Sdim if (!CallbackFunctionType->getParamType(ParamIdx - 2)->isReferenceType()) { 423327952Sdim QualType PTy = PDecl->getType().getNonReferenceType(); 424327952Sdim ParamExpr = M.makeLvalueToRvalue(ParamExpr, PTy); 425327952Sdim } 426327952Sdim CallArgs.push_back(ParamExpr); 427327952Sdim } 428327952Sdim 429327952Sdim CallExpr *CallbackCall; 430327952Sdim if (isLambdaCall) { 431327952Sdim 432327952Sdim CallbackCall = create_call_once_lambda_call(C, M, Callback, 433327952Sdim CallbackRecordDecl, CallArgs); 434327952Sdim } else { 435327952Sdim 436327952Sdim // Function pointer case. 437327952Sdim CallbackCall = create_call_once_funcptr_call(C, M, Callback, CallArgs); 438327952Sdim } 439327952Sdim 440327952Sdim DeclRefExpr *FlagDecl = 441327952Sdim M.makeDeclRefExpr(Flag, 442327952Sdim /* RefersToEnclosingVariableOrCapture=*/true); 443327952Sdim 444327952Sdim 445327952Sdim MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FlagFieldDecl); 446327952Sdim assert(Deref->isLValue()); 447327952Sdim QualType DerefType = Deref->getType(); 448327952Sdim 449327952Sdim // Negation predicate. 450327952Sdim UnaryOperator *FlagCheck = new (C) UnaryOperator( 451327952Sdim /* input=*/ 452327952Sdim M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType, 453327952Sdim CK_IntegralToBoolean), 454327952Sdim /* opc=*/ UO_LNot, 455327952Sdim /* QualType=*/ C.IntTy, 456327952Sdim /* ExprValueKind=*/ VK_RValue, 457341825Sdim /* ExprObjectKind=*/ OK_Ordinary, SourceLocation(), 458341825Sdim /* CanOverflow*/ false); 459327952Sdim 460327952Sdim // Create assignment. 461327952Sdim BinaryOperator *FlagAssignment = M.makeAssignment( 462327952Sdim Deref, M.makeIntegralCast(M.makeIntegerLiteral(1, C.IntTy), DerefType), 463327952Sdim DerefType); 464327952Sdim 465344779Sdim auto *Out = 466344779Sdim IfStmt::Create(C, SourceLocation(), 467344779Sdim /* IsConstexpr=*/false, 468353358Sdim /* Init=*/nullptr, 469353358Sdim /* Var=*/nullptr, 470353358Sdim /* Cond=*/FlagCheck, 471353358Sdim /* Then=*/M.makeCompound({CallbackCall, FlagAssignment})); 472327952Sdim 473327952Sdim return Out; 474327952Sdim} 475327952Sdim 476243791Sdim/// Create a fake body for dispatch_once. 477243791Sdimstatic Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { 478243791Sdim // Check if we have at least two parameters. 479243791Sdim if (D->param_size() != 2) 480276479Sdim return nullptr; 481243791Sdim 482243791Sdim // Check if the first parameter is a pointer to integer type. 483243791Sdim const ParmVarDecl *Predicate = D->getParamDecl(0); 484243791Sdim QualType PredicateQPtrTy = Predicate->getType(); 485243791Sdim const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>(); 486243791Sdim if (!PredicatePtrTy) 487276479Sdim return nullptr; 488243791Sdim QualType PredicateTy = PredicatePtrTy->getPointeeType(); 489243791Sdim if (!PredicateTy->isIntegerType()) 490276479Sdim return nullptr; 491276479Sdim 492243791Sdim // Check if the second parameter is the proper block type. 493243791Sdim const ParmVarDecl *Block = D->getParamDecl(1); 494243791Sdim QualType Ty = Block->getType(); 495243791Sdim if (!isDispatchBlock(Ty)) 496276479Sdim return nullptr; 497276479Sdim 498243791Sdim // Everything checks out. Create a fakse body that checks the predicate, 499243791Sdim // sets it, and calls the block. Basically, an AST dump of: 500243791Sdim // 501243791Sdim // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) { 502327952Sdim // if (*predicate != ~0l) { 503327952Sdim // *predicate = ~0l; 504243791Sdim // block(); 505243791Sdim // } 506243791Sdim // } 507341825Sdim 508243791Sdim ASTMaker M(C); 509341825Sdim 510243791Sdim // (1) Create the call. 511344779Sdim CallExpr *CE = CallExpr::Create( 512327952Sdim /*ASTContext=*/C, 513327952Sdim /*StmtClass=*/M.makeLvalueToRvalue(/*Expr=*/Block), 514353358Sdim /*Args=*/None, 515327952Sdim /*QualType=*/C.VoidTy, 516327952Sdim /*ExprValueType=*/VK_RValue, 517327952Sdim /*SourceLocation=*/SourceLocation()); 518243791Sdim 519243791Sdim // (2) Create the assignment to the predicate. 520327952Sdim Expr *DoneValue = 521327952Sdim new (C) UnaryOperator(M.makeIntegerLiteral(0, C.LongTy), UO_Not, C.LongTy, 522341825Sdim VK_RValue, OK_Ordinary, SourceLocation(), 523341825Sdim /*CanOverflow*/false); 524327952Sdim 525243791Sdim BinaryOperator *B = 526243791Sdim M.makeAssignment( 527243791Sdim M.makeDereference( 528243791Sdim M.makeLvalueToRvalue( 529243791Sdim M.makeDeclRefExpr(Predicate), PredicateQPtrTy), 530243791Sdim PredicateTy), 531327952Sdim M.makeIntegralCast(DoneValue, PredicateTy), 532243791Sdim PredicateTy); 533341825Sdim 534243791Sdim // (3) Create the compound statement. 535280031Sdim Stmt *Stmts[] = { B, CE }; 536280031Sdim CompoundStmt *CS = M.makeCompound(Stmts); 537341825Sdim 538243791Sdim // (4) Create the 'if' condition. 539243791Sdim ImplicitCastExpr *LValToRval = 540243791Sdim M.makeLvalueToRvalue( 541243791Sdim M.makeDereference( 542243791Sdim M.makeLvalueToRvalue( 543243791Sdim M.makeDeclRefExpr(Predicate), 544243791Sdim PredicateQPtrTy), 545243791Sdim PredicateTy), 546243791Sdim PredicateTy); 547327952Sdim 548327952Sdim Expr *GuardCondition = M.makeComparison(LValToRval, DoneValue, BO_NE); 549243791Sdim // (5) Create the 'if' statement. 550344779Sdim auto *If = IfStmt::Create(C, SourceLocation(), 551344779Sdim /* IsConstexpr=*/false, 552353358Sdim /* Init=*/nullptr, 553353358Sdim /* Var=*/nullptr, 554353358Sdim /* Cond=*/GuardCondition, 555353358Sdim /* Then=*/CS); 556243791Sdim return If; 557243791Sdim} 558243791Sdim 559243791Sdim/// Create a fake body for dispatch_sync. 560243791Sdimstatic Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) { 561243791Sdim // Check if we have at least two parameters. 562243791Sdim if (D->param_size() != 2) 563276479Sdim return nullptr; 564276479Sdim 565243791Sdim // Check if the second parameter is a block. 566243791Sdim const ParmVarDecl *PV = D->getParamDecl(1); 567243791Sdim QualType Ty = PV->getType(); 568243791Sdim if (!isDispatchBlock(Ty)) 569276479Sdim return nullptr; 570276479Sdim 571243791Sdim // Everything checks out. Create a fake body that just calls the block. 572243791Sdim // This is basically just an AST dump of: 573243791Sdim // 574243791Sdim // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) { 575243791Sdim // block(); 576243791Sdim // } 577341825Sdim // 578243791Sdim ASTMaker M(C); 579243791Sdim DeclRefExpr *DR = M.makeDeclRefExpr(PV); 580243791Sdim ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty); 581344779Sdim CallExpr *CE = 582344779Sdim CallExpr::Create(C, ICE, None, C.VoidTy, VK_RValue, SourceLocation()); 583243791Sdim return CE; 584243791Sdim} 585243791Sdim 586243791Sdimstatic Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D) 587243791Sdim{ 588243791Sdim // There are exactly 3 arguments. 589243791Sdim if (D->param_size() != 3) 590276479Sdim return nullptr; 591276479Sdim 592249423Sdim // Signature: 593249423Sdim // _Bool OSAtomicCompareAndSwapPtr(void *__oldValue, 594249423Sdim // void *__newValue, 595249423Sdim // void * volatile *__theValue) 596249423Sdim // Generate body: 597243791Sdim // if (oldValue == *theValue) { 598243791Sdim // *theValue = newValue; 599243791Sdim // return YES; 600243791Sdim // } 601243791Sdim // else return NO; 602276479Sdim 603276479Sdim QualType ResultTy = D->getReturnType(); 604243791Sdim bool isBoolean = ResultTy->isBooleanType(); 605243791Sdim if (!isBoolean && !ResultTy->isIntegralType(C)) 606276479Sdim return nullptr; 607276479Sdim 608243791Sdim const ParmVarDecl *OldValue = D->getParamDecl(0); 609243791Sdim QualType OldValueTy = OldValue->getType(); 610243791Sdim 611243791Sdim const ParmVarDecl *NewValue = D->getParamDecl(1); 612243791Sdim QualType NewValueTy = NewValue->getType(); 613341825Sdim 614243791Sdim assert(OldValueTy == NewValueTy); 615341825Sdim 616243791Sdim const ParmVarDecl *TheValue = D->getParamDecl(2); 617243791Sdim QualType TheValueTy = TheValue->getType(); 618243791Sdim const PointerType *PT = TheValueTy->getAs<PointerType>(); 619243791Sdim if (!PT) 620276479Sdim return nullptr; 621243791Sdim QualType PointeeTy = PT->getPointeeType(); 622341825Sdim 623243791Sdim ASTMaker M(C); 624243791Sdim // Construct the comparison. 625243791Sdim Expr *Comparison = 626243791Sdim M.makeComparison( 627243791Sdim M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy), 628243791Sdim M.makeLvalueToRvalue( 629243791Sdim M.makeDereference( 630243791Sdim M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy), 631243791Sdim PointeeTy), 632243791Sdim PointeeTy), 633243791Sdim BO_EQ); 634243791Sdim 635243791Sdim // Construct the body of the IfStmt. 636243791Sdim Stmt *Stmts[2]; 637243791Sdim Stmts[0] = 638243791Sdim M.makeAssignment( 639243791Sdim M.makeDereference( 640243791Sdim M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy), 641243791Sdim PointeeTy), 642243791Sdim M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy), 643243791Sdim NewValueTy); 644341825Sdim 645243791Sdim Expr *BoolVal = M.makeObjCBool(true); 646243791Sdim Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal) 647243791Sdim : M.makeIntegralCast(BoolVal, ResultTy); 648243791Sdim Stmts[1] = M.makeReturn(RetVal); 649280031Sdim CompoundStmt *Body = M.makeCompound(Stmts); 650341825Sdim 651243791Sdim // Construct the else clause. 652243791Sdim BoolVal = M.makeObjCBool(false); 653243791Sdim RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal) 654243791Sdim : M.makeIntegralCast(BoolVal, ResultTy); 655243791Sdim Stmt *Else = M.makeReturn(RetVal); 656341825Sdim 657243791Sdim /// Construct the If. 658344779Sdim auto *If = IfStmt::Create(C, SourceLocation(), 659344779Sdim /* IsConstexpr=*/false, 660353358Sdim /* Init=*/nullptr, 661353358Sdim /* Var=*/nullptr, Comparison, Body, 662344779Sdim SourceLocation(), Else); 663276479Sdim 664341825Sdim return If; 665243791Sdim} 666243791Sdim 667243791SdimStmt *BodyFarm::getBody(const FunctionDecl *D) { 668249423Sdim Optional<Stmt *> &Val = Bodies[D]; 669243791Sdim if (Val.hasValue()) 670243791Sdim return Val.getValue(); 671243791Sdim 672276479Sdim Val = nullptr; 673276479Sdim 674276479Sdim if (D->getIdentifier() == nullptr) 675276479Sdim return nullptr; 676276479Sdim 677243791Sdim StringRef Name = D->getName(); 678243791Sdim if (Name.empty()) 679276479Sdim return nullptr; 680243791Sdim 681243791Sdim FunctionFarmer FF; 682243791Sdim 683243791Sdim if (Name.startswith("OSAtomicCompareAndSwap") || 684243791Sdim Name.startswith("objc_atomicCompareAndSwap")) { 685243791Sdim FF = create_OSAtomicCompareAndSwap; 686327952Sdim } else if (Name == "call_once" && D->getDeclContext()->isStdNamespace()) { 687327952Sdim FF = create_call_once; 688327952Sdim } else { 689243791Sdim FF = llvm::StringSwitch<FunctionFarmer>(Name) 690243791Sdim .Case("dispatch_sync", create_dispatch_sync) 691243791Sdim .Case("dispatch_once", create_dispatch_once) 692276479Sdim .Default(nullptr); 693243791Sdim } 694341825Sdim 695243791Sdim if (FF) { Val = FF(C, D); } 696280031Sdim else if (Injector) { Val = Injector->getBody(D); } 697243791Sdim return Val.getValue(); 698243791Sdim} 699243791Sdim 700309124Sdimstatic const ObjCIvarDecl *findBackingIvar(const ObjCPropertyDecl *Prop) { 701309124Sdim const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl(); 702309124Sdim 703309124Sdim if (IVar) 704309124Sdim return IVar; 705309124Sdim 706309124Sdim // When a readonly property is shadowed in a class extensions with a 707309124Sdim // a readwrite property, the instance variable belongs to the shadowing 708309124Sdim // property rather than the shadowed property. If there is no instance 709309124Sdim // variable on a readonly property, check to see whether the property is 710309124Sdim // shadowed and if so try to get the instance variable from shadowing 711309124Sdim // property. 712309124Sdim if (!Prop->isReadOnly()) 713309124Sdim return nullptr; 714309124Sdim 715309124Sdim auto *Container = cast<ObjCContainerDecl>(Prop->getDeclContext()); 716309124Sdim const ObjCInterfaceDecl *PrimaryInterface = nullptr; 717309124Sdim if (auto *InterfaceDecl = dyn_cast<ObjCInterfaceDecl>(Container)) { 718309124Sdim PrimaryInterface = InterfaceDecl; 719309124Sdim } else if (auto *CategoryDecl = dyn_cast<ObjCCategoryDecl>(Container)) { 720309124Sdim PrimaryInterface = CategoryDecl->getClassInterface(); 721309124Sdim } else if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container)) { 722309124Sdim PrimaryInterface = ImplDecl->getClassInterface(); 723309124Sdim } else { 724309124Sdim return nullptr; 725309124Sdim } 726309124Sdim 727309124Sdim // FindPropertyVisibleInPrimaryClass() looks first in class extensions, so it 728309124Sdim // is guaranteed to find the shadowing property, if it exists, rather than 729309124Sdim // the shadowed property. 730309124Sdim auto *ShadowingProp = PrimaryInterface->FindPropertyVisibleInPrimaryClass( 731309124Sdim Prop->getIdentifier(), Prop->getQueryKind()); 732309124Sdim if (ShadowingProp && ShadowingProp != Prop) { 733309124Sdim IVar = ShadowingProp->getPropertyIvarDecl(); 734309124Sdim } 735309124Sdim 736309124Sdim return IVar; 737309124Sdim} 738309124Sdim 739276479Sdimstatic Stmt *createObjCPropertyGetter(ASTContext &Ctx, 740360784Sdim const ObjCMethodDecl *MD) { 741360784Sdim // First, find the backing ivar. 742360784Sdim const ObjCIvarDecl *IVar = nullptr; 743276479Sdim 744360784Sdim // Property accessor stubs sometimes do not correspond to any property decl 745360784Sdim // in the current interface (but in a superclass). They still have a 746360784Sdim // corresponding property impl decl in this case. 747360784Sdim if (MD->isSynthesizedAccessorStub()) { 748360784Sdim const ObjCInterfaceDecl *IntD = MD->getClassInterface(); 749360784Sdim const ObjCImplementationDecl *ImpD = IntD->getImplementation(); 750360784Sdim for (const auto *PI: ImpD->property_impls()) { 751360784Sdim if (const ObjCPropertyDecl *P = PI->getPropertyDecl()) { 752360784Sdim if (P->getGetterName() == MD->getSelector()) 753360784Sdim IVar = P->getPropertyIvarDecl(); 754360784Sdim } 755360784Sdim } 756360784Sdim } 757276479Sdim 758360784Sdim if (!IVar) { 759360784Sdim const ObjCPropertyDecl *Prop = MD->findPropertyDecl(); 760360784Sdim IVar = findBackingIvar(Prop); 761360784Sdim if (!IVar) 762360784Sdim return nullptr; 763276479Sdim 764360784Sdim // Ignore weak variables, which have special behavior. 765360784Sdim if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak) 766360784Sdim return nullptr; 767360784Sdim 768360784Sdim // Look to see if Sema has synthesized a body for us. This happens in 769360784Sdim // Objective-C++ because the return value may be a C++ class type with a 770360784Sdim // non-trivial copy constructor. We can only do this if we can find the 771360784Sdim // @synthesize for this property, though (or if we know it's been auto- 772360784Sdim // synthesized). 773360784Sdim const ObjCImplementationDecl *ImplDecl = 774360784Sdim IVar->getContainingInterface()->getImplementation(); 775360784Sdim if (ImplDecl) { 776360784Sdim for (const auto *I : ImplDecl->property_impls()) { 777360784Sdim if (I->getPropertyDecl() != Prop) 778360784Sdim continue; 779360784Sdim 780360784Sdim if (I->getGetterCXXConstructor()) { 781360784Sdim ASTMaker M(Ctx); 782360784Sdim return M.makeReturn(I->getGetterCXXConstructor()); 783360784Sdim } 784276479Sdim } 785276479Sdim } 786360784Sdim 787360784Sdim // Sanity check that the property is the same type as the ivar, or a 788360784Sdim // reference to it, and that it is either an object pointer or trivially 789360784Sdim // copyable. 790360784Sdim if (!Ctx.hasSameUnqualifiedType(IVar->getType(), 791360784Sdim Prop->getType().getNonReferenceType())) 792360784Sdim return nullptr; 793360784Sdim if (!IVar->getType()->isObjCLifetimeType() && 794360784Sdim !IVar->getType().isTriviallyCopyableType(Ctx)) 795360784Sdim return nullptr; 796276479Sdim } 797276479Sdim 798276479Sdim // Generate our body: 799276479Sdim // return self->_ivar; 800276479Sdim ASTMaker M(Ctx); 801276479Sdim 802360784Sdim const VarDecl *selfVar = MD->getSelfDecl(); 803314564Sdim if (!selfVar) 804314564Sdim return nullptr; 805276479Sdim 806276479Sdim Expr *loadedIVar = 807276479Sdim M.makeObjCIvarRef( 808276479Sdim M.makeLvalueToRvalue( 809276479Sdim M.makeDeclRefExpr(selfVar), 810276479Sdim selfVar->getType()), 811276479Sdim IVar); 812276479Sdim 813360784Sdim if (!MD->getReturnType()->isReferenceType()) 814276479Sdim loadedIVar = M.makeLvalueToRvalue(loadedIVar, IVar->getType()); 815276479Sdim 816276479Sdim return M.makeReturn(loadedIVar); 817276479Sdim} 818276479Sdim 819276479SdimStmt *BodyFarm::getBody(const ObjCMethodDecl *D) { 820276479Sdim // We currently only know how to synthesize property accessors. 821276479Sdim if (!D->isPropertyAccessor()) 822276479Sdim return nullptr; 823276479Sdim 824276479Sdim D = D->getCanonicalDecl(); 825276479Sdim 826353358Sdim // We should not try to synthesize explicitly redefined accessors. 827353358Sdim // We do not know for sure how they behave. 828353358Sdim if (!D->isImplicit()) 829353358Sdim return nullptr; 830353358Sdim 831276479Sdim Optional<Stmt *> &Val = Bodies[D]; 832276479Sdim if (Val.hasValue()) 833276479Sdim return Val.getValue(); 834276479Sdim Val = nullptr; 835276479Sdim 836276479Sdim // For now, we only synthesize getters. 837309124Sdim // Synthesizing setters would cause false negatives in the 838309124Sdim // RetainCountChecker because the method body would bind the parameter 839309124Sdim // to an instance variable, causing it to escape. This would prevent 840309124Sdim // warning in the following common scenario: 841309124Sdim // 842309124Sdim // id foo = [[NSObject alloc] init]; 843309124Sdim // self.foo = foo; // We should warn that foo leaks here. 844309124Sdim // 845276479Sdim if (D->param_size() != 0) 846276479Sdim return nullptr; 847276479Sdim 848360784Sdim // If the property was defined in an extension, search the extensions for 849360784Sdim // overrides. 850360784Sdim const ObjCInterfaceDecl *OID = D->getClassInterface(); 851360784Sdim if (dyn_cast<ObjCInterfaceDecl>(D->getParent()) != OID) 852360784Sdim for (auto *Ext : OID->known_extensions()) { 853360784Sdim auto *OMD = Ext->getInstanceMethod(D->getSelector()); 854360784Sdim if (OMD && !OMD->isImplicit()) 855360784Sdim return nullptr; 856360784Sdim } 857276479Sdim 858360784Sdim Val = createObjCPropertyGetter(C, D); 859360784Sdim 860276479Sdim return Val.getValue(); 861276479Sdim} 862