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" 2381ad6265SDimitry Andric #include "clang/Basic/Builtins.h" 240b57cec5SDimitry Andric #include "clang/Basic/OperatorKinds.h" 250b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h" 260b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 27bdd1243dSDimitry Andric #include <optional> 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric #define DEBUG_TYPE "body-farm" 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric using namespace clang; 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 340b57cec5SDimitry Andric // Helper creation functions for constructing faux ASTs. 350b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric static bool isDispatchBlock(QualType Ty) { 380b57cec5SDimitry Andric // Is it a block pointer? 390b57cec5SDimitry Andric const BlockPointerType *BPT = Ty->getAs<BlockPointerType>(); 400b57cec5SDimitry Andric if (!BPT) 410b57cec5SDimitry Andric return false; 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric // Check if the block pointer type takes no arguments and 440b57cec5SDimitry Andric // returns void. 450b57cec5SDimitry Andric const FunctionProtoType *FT = 460b57cec5SDimitry Andric BPT->getPointeeType()->getAs<FunctionProtoType>(); 470b57cec5SDimitry Andric return FT && FT->getReturnType()->isVoidType() && FT->getNumParams() == 0; 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric namespace { 510b57cec5SDimitry Andric class ASTMaker { 520b57cec5SDimitry Andric public: 530b57cec5SDimitry Andric ASTMaker(ASTContext &C) : C(C) {} 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric /// Create a new BinaryOperator representing a simple assignment. 560b57cec5SDimitry Andric BinaryOperator *makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty); 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric /// Create a new BinaryOperator representing a comparison. 590b57cec5SDimitry Andric BinaryOperator *makeComparison(const Expr *LHS, const Expr *RHS, 600b57cec5SDimitry Andric BinaryOperator::Opcode Op); 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric /// Create a new compound stmt using the provided statements. 630b57cec5SDimitry Andric CompoundStmt *makeCompound(ArrayRef<Stmt*>); 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric /// Create a new DeclRefExpr for the referenced variable. 660b57cec5SDimitry Andric DeclRefExpr *makeDeclRefExpr(const VarDecl *D, 670b57cec5SDimitry Andric bool RefersToEnclosingVariableOrCapture = false); 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric /// Create a new UnaryOperator representing a dereference. 700b57cec5SDimitry Andric UnaryOperator *makeDereference(const Expr *Arg, QualType Ty); 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric /// Create an implicit cast for an integer conversion. 730b57cec5SDimitry Andric Expr *makeIntegralCast(const Expr *Arg, QualType Ty); 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric /// Create an implicit cast to a builtin boolean type. 760b57cec5SDimitry Andric ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg); 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric /// Create an implicit cast for lvalue-to-rvaluate conversions. 790b57cec5SDimitry Andric ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty); 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric /// Make RValue out of variable declaration, creating a temporary 820b57cec5SDimitry Andric /// DeclRefExpr in the process. 830b57cec5SDimitry Andric ImplicitCastExpr * 840b57cec5SDimitry Andric makeLvalueToRvalue(const VarDecl *Decl, 850b57cec5SDimitry Andric bool RefersToEnclosingVariableOrCapture = false); 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric /// Create an implicit cast of the given type. 880b57cec5SDimitry Andric ImplicitCastExpr *makeImplicitCast(const Expr *Arg, QualType Ty, 890b57cec5SDimitry Andric CastKind CK = CK_LValueToRValue); 900b57cec5SDimitry Andric 9181ad6265SDimitry Andric /// Create a cast to reference type. 9281ad6265SDimitry Andric CastExpr *makeReferenceCast(const Expr *Arg, QualType Ty); 9381ad6265SDimitry Andric 940b57cec5SDimitry Andric /// Create an Objective-C bool literal. 950b57cec5SDimitry Andric ObjCBoolLiteralExpr *makeObjCBool(bool Val); 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric /// Create an Objective-C ivar reference. 980b57cec5SDimitry Andric ObjCIvarRefExpr *makeObjCIvarRef(const Expr *Base, const ObjCIvarDecl *IVar); 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric /// Create a Return statement. 1010b57cec5SDimitry Andric ReturnStmt *makeReturn(const Expr *RetVal); 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric /// Create an integer literal expression of the given type. 1040b57cec5SDimitry Andric IntegerLiteral *makeIntegerLiteral(uint64_t Value, QualType Ty); 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric /// Create a member expression. 1070b57cec5SDimitry Andric MemberExpr *makeMemberExpression(Expr *base, ValueDecl *MemberDecl, 1080b57cec5SDimitry Andric bool IsArrow = false, 1090b57cec5SDimitry Andric ExprValueKind ValueKind = VK_LValue); 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric /// Returns a *first* member field of a record declaration with a given name. 1120b57cec5SDimitry Andric /// \return an nullptr if no member with such a name exists. 1130b57cec5SDimitry Andric ValueDecl *findMemberField(const RecordDecl *RD, StringRef Name); 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric private: 1160b57cec5SDimitry Andric ASTContext &C; 1170b57cec5SDimitry Andric }; 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS, 1210b57cec5SDimitry Andric QualType Ty) { 1225ffd83dbSDimitry Andric return BinaryOperator::Create( 1235ffd83dbSDimitry Andric C, const_cast<Expr *>(LHS), const_cast<Expr *>(RHS), BO_Assign, Ty, 124fe6060f1SDimitry Andric VK_PRValue, OK_Ordinary, SourceLocation(), FPOptionsOverride()); 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS, 1280b57cec5SDimitry Andric BinaryOperator::Opcode Op) { 1290b57cec5SDimitry Andric assert(BinaryOperator::isLogicalOp(Op) || 1300b57cec5SDimitry Andric BinaryOperator::isComparisonOp(Op)); 1315ffd83dbSDimitry Andric return BinaryOperator::Create( 1325ffd83dbSDimitry Andric C, const_cast<Expr *>(LHS), const_cast<Expr *>(RHS), Op, 133fe6060f1SDimitry Andric C.getLogicalOperationType(), VK_PRValue, OK_Ordinary, SourceLocation(), 1345ffd83dbSDimitry Andric FPOptionsOverride()); 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) { 13881ad6265SDimitry Andric return CompoundStmt::Create(C, Stmts, FPOptionsOverride(), SourceLocation(), 13981ad6265SDimitry Andric SourceLocation()); 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric DeclRefExpr *ASTMaker::makeDeclRefExpr( 1430b57cec5SDimitry Andric const VarDecl *D, 1440b57cec5SDimitry Andric bool RefersToEnclosingVariableOrCapture) { 1450b57cec5SDimitry Andric QualType Type = D->getType().getNonReferenceType(); 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric DeclRefExpr *DR = DeclRefExpr::Create( 1480b57cec5SDimitry Andric C, NestedNameSpecifierLoc(), SourceLocation(), const_cast<VarDecl *>(D), 1490b57cec5SDimitry Andric RefersToEnclosingVariableOrCapture, SourceLocation(), Type, VK_LValue); 1500b57cec5SDimitry Andric return DR; 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) { 1545ffd83dbSDimitry Andric return UnaryOperator::Create(C, const_cast<Expr *>(Arg), UO_Deref, Ty, 1550b57cec5SDimitry Andric VK_LValue, OK_Ordinary, SourceLocation(), 1565ffd83dbSDimitry Andric /*CanOverflow*/ false, FPOptionsOverride()); 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) { 1600b57cec5SDimitry Andric return makeImplicitCast(Arg, Ty, CK_LValueToRValue); 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric ImplicitCastExpr * 1640b57cec5SDimitry Andric ASTMaker::makeLvalueToRvalue(const VarDecl *Arg, 1650b57cec5SDimitry Andric bool RefersToEnclosingVariableOrCapture) { 1660b57cec5SDimitry Andric QualType Type = Arg->getType().getNonReferenceType(); 1670b57cec5SDimitry Andric return makeLvalueToRvalue(makeDeclRefExpr(Arg, 1680b57cec5SDimitry Andric RefersToEnclosingVariableOrCapture), 1690b57cec5SDimitry Andric Type); 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric ImplicitCastExpr *ASTMaker::makeImplicitCast(const Expr *Arg, QualType Ty, 1730b57cec5SDimitry Andric CastKind CK) { 1740b57cec5SDimitry Andric return ImplicitCastExpr::Create(C, Ty, 1750b57cec5SDimitry Andric /* CastKind=*/CK, 1760b57cec5SDimitry Andric /* Expr=*/const_cast<Expr *>(Arg), 1770b57cec5SDimitry Andric /* CXXCastPath=*/nullptr, 178fe6060f1SDimitry Andric /* ExprValueKind=*/VK_PRValue, 179e8d8bef9SDimitry Andric /* FPFeatures */ FPOptionsOverride()); 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 18281ad6265SDimitry Andric CastExpr *ASTMaker::makeReferenceCast(const Expr *Arg, QualType Ty) { 18381ad6265SDimitry Andric assert(Ty->isReferenceType()); 18481ad6265SDimitry Andric return CXXStaticCastExpr::Create( 18581ad6265SDimitry Andric C, Ty.getNonReferenceType(), 18681ad6265SDimitry Andric Ty->isLValueReferenceType() ? VK_LValue : VK_XValue, CK_NoOp, 18781ad6265SDimitry Andric const_cast<Expr *>(Arg), /*CXXCastPath=*/nullptr, 18881ad6265SDimitry Andric /*Written=*/C.getTrivialTypeSourceInfo(Ty), FPOptionsOverride(), 18981ad6265SDimitry Andric SourceLocation(), SourceLocation(), SourceRange()); 19081ad6265SDimitry Andric } 19181ad6265SDimitry Andric 1920b57cec5SDimitry Andric Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) { 1930b57cec5SDimitry Andric if (Arg->getType() == Ty) 1940b57cec5SDimitry Andric return const_cast<Expr*>(Arg); 195e8d8bef9SDimitry Andric return makeImplicitCast(Arg, Ty, CK_IntegralCast); 1960b57cec5SDimitry Andric } 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) { 199e8d8bef9SDimitry Andric return makeImplicitCast(Arg, C.BoolTy, CK_IntegralToBoolean); 2000b57cec5SDimitry Andric } 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) { 2030b57cec5SDimitry Andric QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy; 2040b57cec5SDimitry Andric return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation()); 2050b57cec5SDimitry Andric } 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric ObjCIvarRefExpr *ASTMaker::makeObjCIvarRef(const Expr *Base, 2080b57cec5SDimitry Andric const ObjCIvarDecl *IVar) { 2090b57cec5SDimitry Andric return new (C) ObjCIvarRefExpr(const_cast<ObjCIvarDecl*>(IVar), 2100b57cec5SDimitry Andric IVar->getType(), SourceLocation(), 2110b57cec5SDimitry Andric SourceLocation(), const_cast<Expr*>(Base), 2120b57cec5SDimitry Andric /*arrow=*/true, /*free=*/false); 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) { 2160b57cec5SDimitry Andric return ReturnStmt::Create(C, SourceLocation(), const_cast<Expr *>(RetVal), 2170b57cec5SDimitry Andric /* NRVOCandidate=*/nullptr); 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric IntegerLiteral *ASTMaker::makeIntegerLiteral(uint64_t Value, QualType Ty) { 2210b57cec5SDimitry Andric llvm::APInt APValue = llvm::APInt(C.getTypeSize(Ty), Value); 2220b57cec5SDimitry Andric return IntegerLiteral::Create(C, APValue, Ty, SourceLocation()); 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric MemberExpr *ASTMaker::makeMemberExpression(Expr *base, ValueDecl *MemberDecl, 2260b57cec5SDimitry Andric bool IsArrow, 2270b57cec5SDimitry Andric ExprValueKind ValueKind) { 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric DeclAccessPair FoundDecl = DeclAccessPair::make(MemberDecl, AS_public); 2300b57cec5SDimitry Andric return MemberExpr::Create( 2310b57cec5SDimitry Andric C, base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(), 2320b57cec5SDimitry Andric SourceLocation(), MemberDecl, FoundDecl, 2330b57cec5SDimitry Andric DeclarationNameInfo(MemberDecl->getDeclName(), SourceLocation()), 2340b57cec5SDimitry Andric /* TemplateArgumentListInfo=*/ nullptr, MemberDecl->getType(), ValueKind, 2350b57cec5SDimitry Andric OK_Ordinary, NOUR_None); 2360b57cec5SDimitry Andric } 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric ValueDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) { 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric CXXBasePaths Paths( 2410b57cec5SDimitry Andric /* FindAmbiguities=*/false, 2420b57cec5SDimitry Andric /* RecordPaths=*/false, 2430b57cec5SDimitry Andric /* DetectVirtual=*/ false); 2440b57cec5SDimitry Andric const IdentifierInfo &II = C.Idents.get(Name); 2450b57cec5SDimitry Andric DeclarationName DeclName = C.DeclarationNames.getIdentifier(&II); 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric DeclContextLookupResult Decls = RD->lookup(DeclName); 2480b57cec5SDimitry Andric for (NamedDecl *FoundDecl : Decls) 2490b57cec5SDimitry Andric if (!FoundDecl->getDeclContext()->isFunctionOrMethod()) 2500b57cec5SDimitry Andric return cast<ValueDecl>(FoundDecl); 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric return nullptr; 2530b57cec5SDimitry Andric } 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2560b57cec5SDimitry Andric // Creation functions for faux ASTs. 2570b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2580b57cec5SDimitry Andric 2590b57cec5SDimitry Andric typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D); 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric static CallExpr *create_call_once_funcptr_call(ASTContext &C, ASTMaker M, 2620b57cec5SDimitry Andric const ParmVarDecl *Callback, 2630b57cec5SDimitry Andric ArrayRef<Expr *> CallArgs) { 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric QualType Ty = Callback->getType(); 2660b57cec5SDimitry Andric DeclRefExpr *Call = M.makeDeclRefExpr(Callback); 2670b57cec5SDimitry Andric Expr *SubExpr; 2680b57cec5SDimitry Andric if (Ty->isRValueReferenceType()) { 2690b57cec5SDimitry Andric SubExpr = M.makeImplicitCast( 2700b57cec5SDimitry Andric Call, Ty.getNonReferenceType(), CK_LValueToRValue); 2710b57cec5SDimitry Andric } else if (Ty->isLValueReferenceType() && 2720b57cec5SDimitry Andric Call->getType()->isFunctionType()) { 2730b57cec5SDimitry Andric Ty = C.getPointerType(Ty.getNonReferenceType()); 2740b57cec5SDimitry Andric SubExpr = M.makeImplicitCast(Call, Ty, CK_FunctionToPointerDecay); 2750b57cec5SDimitry Andric } else if (Ty->isLValueReferenceType() 2760b57cec5SDimitry Andric && Call->getType()->isPointerType() 2770b57cec5SDimitry Andric && Call->getType()->getPointeeType()->isFunctionType()){ 2780b57cec5SDimitry Andric SubExpr = Call; 2790b57cec5SDimitry Andric } else { 2800b57cec5SDimitry Andric llvm_unreachable("Unexpected state"); 2810b57cec5SDimitry Andric } 2820b57cec5SDimitry Andric 283fe6060f1SDimitry Andric return CallExpr::Create(C, SubExpr, CallArgs, C.VoidTy, VK_PRValue, 284e8d8bef9SDimitry Andric SourceLocation(), FPOptionsOverride()); 2850b57cec5SDimitry Andric } 2860b57cec5SDimitry Andric 2870b57cec5SDimitry Andric static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M, 2880b57cec5SDimitry Andric const ParmVarDecl *Callback, 2890b57cec5SDimitry Andric CXXRecordDecl *CallbackDecl, 2900b57cec5SDimitry Andric ArrayRef<Expr *> CallArgs) { 2910b57cec5SDimitry Andric assert(CallbackDecl != nullptr); 2920b57cec5SDimitry Andric assert(CallbackDecl->isLambda()); 2930b57cec5SDimitry Andric FunctionDecl *callOperatorDecl = CallbackDecl->getLambdaCallOperator(); 2940b57cec5SDimitry Andric assert(callOperatorDecl != nullptr); 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric DeclRefExpr *callOperatorDeclRef = 2970b57cec5SDimitry Andric DeclRefExpr::Create(/* Ctx =*/ C, 2980b57cec5SDimitry Andric /* QualifierLoc =*/ NestedNameSpecifierLoc(), 2990b57cec5SDimitry Andric /* TemplateKWLoc =*/ SourceLocation(), 3000b57cec5SDimitry Andric const_cast<FunctionDecl *>(callOperatorDecl), 3010b57cec5SDimitry Andric /* RefersToEnclosingVariableOrCapture=*/ false, 3020b57cec5SDimitry Andric /* NameLoc =*/ SourceLocation(), 3030b57cec5SDimitry Andric /* T =*/ callOperatorDecl->getType(), 3040b57cec5SDimitry Andric /* VK =*/ VK_LValue); 3050b57cec5SDimitry Andric 3060b57cec5SDimitry Andric return CXXOperatorCallExpr::Create( 3070b57cec5SDimitry Andric /*AstContext=*/C, OO_Call, callOperatorDeclRef, 3080b57cec5SDimitry Andric /*Args=*/CallArgs, 3090b57cec5SDimitry Andric /*QualType=*/C.VoidTy, 310fe6060f1SDimitry Andric /*ExprValueType=*/VK_PRValue, 3115ffd83dbSDimitry Andric /*SourceLocation=*/SourceLocation(), 3125ffd83dbSDimitry Andric /*FPFeatures=*/FPOptionsOverride()); 3130b57cec5SDimitry Andric } 3140b57cec5SDimitry Andric 31581ad6265SDimitry Andric /// Create a fake body for 'std::move' or 'std::forward'. This is just: 31681ad6265SDimitry Andric /// 31781ad6265SDimitry Andric /// \code 31881ad6265SDimitry Andric /// return static_cast<return_type>(param); 31981ad6265SDimitry Andric /// \endcode 32081ad6265SDimitry Andric static Stmt *create_std_move_forward(ASTContext &C, const FunctionDecl *D) { 32181ad6265SDimitry Andric LLVM_DEBUG(llvm::dbgs() << "Generating body for std::move / std::forward\n"); 32281ad6265SDimitry Andric 32381ad6265SDimitry Andric ASTMaker M(C); 32481ad6265SDimitry Andric 32581ad6265SDimitry Andric QualType ReturnType = D->getType()->castAs<FunctionType>()->getReturnType(); 32681ad6265SDimitry Andric Expr *Param = M.makeDeclRefExpr(D->getParamDecl(0)); 32781ad6265SDimitry Andric Expr *Cast = M.makeReferenceCast(Param, ReturnType); 32881ad6265SDimitry Andric return M.makeReturn(Cast); 32981ad6265SDimitry Andric } 33081ad6265SDimitry Andric 3310b57cec5SDimitry Andric /// Create a fake body for std::call_once. 3320b57cec5SDimitry Andric /// Emulates the following function body: 3330b57cec5SDimitry Andric /// 3340b57cec5SDimitry Andric /// \code 3350b57cec5SDimitry Andric /// typedef struct once_flag_s { 3360b57cec5SDimitry Andric /// unsigned long __state = 0; 3370b57cec5SDimitry Andric /// } once_flag; 3380b57cec5SDimitry Andric /// template<class Callable> 3390b57cec5SDimitry Andric /// void call_once(once_flag& o, Callable func) { 3400b57cec5SDimitry Andric /// if (!o.__state) { 3410b57cec5SDimitry Andric /// func(); 3420b57cec5SDimitry Andric /// } 3430b57cec5SDimitry Andric /// o.__state = 1; 3440b57cec5SDimitry Andric /// } 3450b57cec5SDimitry Andric /// \endcode 3460b57cec5SDimitry Andric static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) { 3470b57cec5SDimitry Andric LLVM_DEBUG(llvm::dbgs() << "Generating body for call_once\n"); 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric // We need at least two parameters. 3500b57cec5SDimitry Andric if (D->param_size() < 2) 3510b57cec5SDimitry Andric return nullptr; 3520b57cec5SDimitry Andric 3530b57cec5SDimitry Andric ASTMaker M(C); 3540b57cec5SDimitry Andric 3550b57cec5SDimitry Andric const ParmVarDecl *Flag = D->getParamDecl(0); 3560b57cec5SDimitry Andric const ParmVarDecl *Callback = D->getParamDecl(1); 3570b57cec5SDimitry Andric 3580b57cec5SDimitry Andric if (!Callback->getType()->isReferenceType()) { 3590b57cec5SDimitry Andric llvm::dbgs() << "libcxx03 std::call_once implementation, skipping.\n"; 3600b57cec5SDimitry Andric return nullptr; 3610b57cec5SDimitry Andric } 3620b57cec5SDimitry Andric if (!Flag->getType()->isReferenceType()) { 3630b57cec5SDimitry Andric llvm::dbgs() << "unknown std::call_once implementation, skipping.\n"; 3640b57cec5SDimitry Andric return nullptr; 3650b57cec5SDimitry Andric } 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric QualType CallbackType = Callback->getType().getNonReferenceType(); 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric // Nullable pointer, non-null iff function is a CXXRecordDecl. 3700b57cec5SDimitry Andric CXXRecordDecl *CallbackRecordDecl = CallbackType->getAsCXXRecordDecl(); 3710b57cec5SDimitry Andric QualType FlagType = Flag->getType().getNonReferenceType(); 3720b57cec5SDimitry Andric auto *FlagRecordDecl = FlagType->getAsRecordDecl(); 3730b57cec5SDimitry Andric 3740b57cec5SDimitry Andric if (!FlagRecordDecl) { 3750b57cec5SDimitry Andric LLVM_DEBUG(llvm::dbgs() << "Flag field is not a record: " 3760b57cec5SDimitry Andric << "unknown std::call_once implementation, " 3770b57cec5SDimitry Andric << "ignoring the call.\n"); 3780b57cec5SDimitry Andric return nullptr; 3790b57cec5SDimitry Andric } 3800b57cec5SDimitry Andric 3810b57cec5SDimitry Andric // We initially assume libc++ implementation of call_once, 3820b57cec5SDimitry Andric // where the once_flag struct has a field `__state_`. 3830b57cec5SDimitry Andric ValueDecl *FlagFieldDecl = M.findMemberField(FlagRecordDecl, "__state_"); 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric // Otherwise, try libstdc++ implementation, with a field 3860b57cec5SDimitry Andric // `_M_once` 3870b57cec5SDimitry Andric if (!FlagFieldDecl) { 3880b57cec5SDimitry Andric FlagFieldDecl = M.findMemberField(FlagRecordDecl, "_M_once"); 3890b57cec5SDimitry Andric } 3900b57cec5SDimitry Andric 3910b57cec5SDimitry Andric if (!FlagFieldDecl) { 3920b57cec5SDimitry Andric LLVM_DEBUG(llvm::dbgs() << "No field _M_once or __state_ found on " 3930b57cec5SDimitry Andric << "std::once_flag struct: unknown std::call_once " 3940b57cec5SDimitry Andric << "implementation, ignoring the call."); 3950b57cec5SDimitry Andric return nullptr; 3960b57cec5SDimitry Andric } 3970b57cec5SDimitry Andric 3980b57cec5SDimitry Andric bool isLambdaCall = CallbackRecordDecl && CallbackRecordDecl->isLambda(); 3990b57cec5SDimitry Andric if (CallbackRecordDecl && !isLambdaCall) { 4000b57cec5SDimitry Andric LLVM_DEBUG(llvm::dbgs() 4010b57cec5SDimitry Andric << "Not supported: synthesizing body for functors when " 4020b57cec5SDimitry Andric << "body farming std::call_once, ignoring the call."); 4030b57cec5SDimitry Andric return nullptr; 4040b57cec5SDimitry Andric } 4050b57cec5SDimitry Andric 4060b57cec5SDimitry Andric SmallVector<Expr *, 5> CallArgs; 4070b57cec5SDimitry Andric const FunctionProtoType *CallbackFunctionType; 4080b57cec5SDimitry Andric if (isLambdaCall) { 4090b57cec5SDimitry Andric 4100b57cec5SDimitry Andric // Lambda requires callback itself inserted as a first parameter. 4110b57cec5SDimitry Andric CallArgs.push_back( 4120b57cec5SDimitry Andric M.makeDeclRefExpr(Callback, 4130b57cec5SDimitry Andric /* RefersToEnclosingVariableOrCapture=*/ true)); 4140b57cec5SDimitry Andric CallbackFunctionType = CallbackRecordDecl->getLambdaCallOperator() 4150b57cec5SDimitry Andric ->getType() 4160b57cec5SDimitry Andric ->getAs<FunctionProtoType>(); 4170b57cec5SDimitry Andric } else if (!CallbackType->getPointeeType().isNull()) { 4180b57cec5SDimitry Andric CallbackFunctionType = 4190b57cec5SDimitry Andric CallbackType->getPointeeType()->getAs<FunctionProtoType>(); 4200b57cec5SDimitry Andric } else { 4210b57cec5SDimitry Andric CallbackFunctionType = CallbackType->getAs<FunctionProtoType>(); 4220b57cec5SDimitry Andric } 4230b57cec5SDimitry Andric 4240b57cec5SDimitry Andric if (!CallbackFunctionType) 4250b57cec5SDimitry Andric return nullptr; 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric // First two arguments are used for the flag and for the callback. 4280b57cec5SDimitry Andric if (D->getNumParams() != CallbackFunctionType->getNumParams() + 2) { 4290b57cec5SDimitry Andric LLVM_DEBUG(llvm::dbgs() << "Types of params of the callback do not match " 4300b57cec5SDimitry Andric << "params passed to std::call_once, " 4310b57cec5SDimitry Andric << "ignoring the call\n"); 4320b57cec5SDimitry Andric return nullptr; 4330b57cec5SDimitry Andric } 4340b57cec5SDimitry Andric 4350b57cec5SDimitry Andric // All arguments past first two ones are passed to the callback, 4360b57cec5SDimitry Andric // and we turn lvalues into rvalues if the argument is not passed by 4370b57cec5SDimitry Andric // reference. 4380b57cec5SDimitry Andric for (unsigned int ParamIdx = 2; ParamIdx < D->getNumParams(); ParamIdx++) { 4390b57cec5SDimitry Andric const ParmVarDecl *PDecl = D->getParamDecl(ParamIdx); 440a7dea167SDimitry Andric assert(PDecl); 441a7dea167SDimitry Andric if (CallbackFunctionType->getParamType(ParamIdx - 2) 4420b57cec5SDimitry Andric .getNonReferenceType() 4430b57cec5SDimitry Andric .getCanonicalType() != 4440b57cec5SDimitry Andric PDecl->getType().getNonReferenceType().getCanonicalType()) { 4450b57cec5SDimitry Andric LLVM_DEBUG(llvm::dbgs() << "Types of params of the callback do not match " 4460b57cec5SDimitry Andric << "params passed to std::call_once, " 4470b57cec5SDimitry Andric << "ignoring the call\n"); 4480b57cec5SDimitry Andric return nullptr; 4490b57cec5SDimitry Andric } 4500b57cec5SDimitry Andric Expr *ParamExpr = M.makeDeclRefExpr(PDecl); 4510b57cec5SDimitry Andric if (!CallbackFunctionType->getParamType(ParamIdx - 2)->isReferenceType()) { 4520b57cec5SDimitry Andric QualType PTy = PDecl->getType().getNonReferenceType(); 4530b57cec5SDimitry Andric ParamExpr = M.makeLvalueToRvalue(ParamExpr, PTy); 4540b57cec5SDimitry Andric } 4550b57cec5SDimitry Andric CallArgs.push_back(ParamExpr); 4560b57cec5SDimitry Andric } 4570b57cec5SDimitry Andric 4580b57cec5SDimitry Andric CallExpr *CallbackCall; 4590b57cec5SDimitry Andric if (isLambdaCall) { 4600b57cec5SDimitry Andric 4610b57cec5SDimitry Andric CallbackCall = create_call_once_lambda_call(C, M, Callback, 4620b57cec5SDimitry Andric CallbackRecordDecl, CallArgs); 4630b57cec5SDimitry Andric } else { 4640b57cec5SDimitry Andric 4650b57cec5SDimitry Andric // Function pointer case. 4660b57cec5SDimitry Andric CallbackCall = create_call_once_funcptr_call(C, M, Callback, CallArgs); 4670b57cec5SDimitry Andric } 4680b57cec5SDimitry Andric 4690b57cec5SDimitry Andric DeclRefExpr *FlagDecl = 4700b57cec5SDimitry Andric M.makeDeclRefExpr(Flag, 4710b57cec5SDimitry Andric /* RefersToEnclosingVariableOrCapture=*/true); 4720b57cec5SDimitry Andric 4730b57cec5SDimitry Andric 4740b57cec5SDimitry Andric MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FlagFieldDecl); 4750b57cec5SDimitry Andric assert(Deref->isLValue()); 4760b57cec5SDimitry Andric QualType DerefType = Deref->getType(); 4770b57cec5SDimitry Andric 4780b57cec5SDimitry Andric // Negation predicate. 4795ffd83dbSDimitry Andric UnaryOperator *FlagCheck = UnaryOperator::Create( 4805ffd83dbSDimitry Andric C, 4810b57cec5SDimitry Andric /* input=*/ 4820b57cec5SDimitry Andric M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType, 4830b57cec5SDimitry Andric CK_IntegralToBoolean), 4840b57cec5SDimitry Andric /* opc=*/UO_LNot, 4850b57cec5SDimitry Andric /* QualType=*/C.IntTy, 486fe6060f1SDimitry Andric /* ExprValueKind=*/VK_PRValue, 4870b57cec5SDimitry Andric /* ExprObjectKind=*/OK_Ordinary, SourceLocation(), 4885ffd83dbSDimitry Andric /* CanOverflow*/ false, FPOptionsOverride()); 4890b57cec5SDimitry Andric 4900b57cec5SDimitry Andric // Create assignment. 4910b57cec5SDimitry Andric BinaryOperator *FlagAssignment = M.makeAssignment( 4920b57cec5SDimitry Andric Deref, M.makeIntegralCast(M.makeIntegerLiteral(1, C.IntTy), DerefType), 4930b57cec5SDimitry Andric DerefType); 4940b57cec5SDimitry Andric 4950b57cec5SDimitry Andric auto *Out = 496349cc55cSDimitry Andric IfStmt::Create(C, SourceLocation(), IfStatementKind::Ordinary, 4970b57cec5SDimitry Andric /* Init=*/nullptr, 4980b57cec5SDimitry Andric /* Var=*/nullptr, 4990b57cec5SDimitry Andric /* Cond=*/FlagCheck, 500e8d8bef9SDimitry Andric /* LPL=*/SourceLocation(), 501e8d8bef9SDimitry Andric /* RPL=*/SourceLocation(), 5020b57cec5SDimitry Andric /* Then=*/M.makeCompound({CallbackCall, FlagAssignment})); 5030b57cec5SDimitry Andric 5040b57cec5SDimitry Andric return Out; 5050b57cec5SDimitry Andric } 5060b57cec5SDimitry Andric 5070b57cec5SDimitry Andric /// Create a fake body for dispatch_once. 5080b57cec5SDimitry Andric static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { 5090b57cec5SDimitry Andric // Check if we have at least two parameters. 5100b57cec5SDimitry Andric if (D->param_size() != 2) 5110b57cec5SDimitry Andric return nullptr; 5120b57cec5SDimitry Andric 5130b57cec5SDimitry Andric // Check if the first parameter is a pointer to integer type. 5140b57cec5SDimitry Andric const ParmVarDecl *Predicate = D->getParamDecl(0); 5150b57cec5SDimitry Andric QualType PredicateQPtrTy = Predicate->getType(); 5160b57cec5SDimitry Andric const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>(); 5170b57cec5SDimitry Andric if (!PredicatePtrTy) 5180b57cec5SDimitry Andric return nullptr; 5190b57cec5SDimitry Andric QualType PredicateTy = PredicatePtrTy->getPointeeType(); 5200b57cec5SDimitry Andric if (!PredicateTy->isIntegerType()) 5210b57cec5SDimitry Andric return nullptr; 5220b57cec5SDimitry Andric 5230b57cec5SDimitry Andric // Check if the second parameter is the proper block type. 5240b57cec5SDimitry Andric const ParmVarDecl *Block = D->getParamDecl(1); 5250b57cec5SDimitry Andric QualType Ty = Block->getType(); 5260b57cec5SDimitry Andric if (!isDispatchBlock(Ty)) 5270b57cec5SDimitry Andric return nullptr; 5280b57cec5SDimitry Andric 5290b57cec5SDimitry Andric // Everything checks out. Create a fakse body that checks the predicate, 5300b57cec5SDimitry Andric // sets it, and calls the block. Basically, an AST dump of: 5310b57cec5SDimitry Andric // 5320b57cec5SDimitry Andric // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) { 5330b57cec5SDimitry Andric // if (*predicate != ~0l) { 5340b57cec5SDimitry Andric // *predicate = ~0l; 5350b57cec5SDimitry Andric // block(); 5360b57cec5SDimitry Andric // } 5370b57cec5SDimitry Andric // } 5380b57cec5SDimitry Andric 5390b57cec5SDimitry Andric ASTMaker M(C); 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric // (1) Create the call. 5420b57cec5SDimitry Andric CallExpr *CE = CallExpr::Create( 5430b57cec5SDimitry Andric /*ASTContext=*/C, 5440b57cec5SDimitry Andric /*StmtClass=*/M.makeLvalueToRvalue(/*Expr=*/Block), 545bdd1243dSDimitry Andric /*Args=*/std::nullopt, 5460b57cec5SDimitry Andric /*QualType=*/C.VoidTy, 547fe6060f1SDimitry Andric /*ExprValueType=*/VK_PRValue, 548e8d8bef9SDimitry Andric /*SourceLocation=*/SourceLocation(), FPOptionsOverride()); 5490b57cec5SDimitry Andric 5500b57cec5SDimitry Andric // (2) Create the assignment to the predicate. 5510b57cec5SDimitry Andric Expr *DoneValue = 5525ffd83dbSDimitry Andric UnaryOperator::Create(C, M.makeIntegerLiteral(0, C.LongTy), UO_Not, 553fe6060f1SDimitry Andric C.LongTy, VK_PRValue, OK_Ordinary, SourceLocation(), 5545ffd83dbSDimitry Andric /*CanOverflow*/ false, FPOptionsOverride()); 5550b57cec5SDimitry Andric 5560b57cec5SDimitry Andric BinaryOperator *B = 5570b57cec5SDimitry Andric M.makeAssignment( 5580b57cec5SDimitry Andric M.makeDereference( 5590b57cec5SDimitry Andric M.makeLvalueToRvalue( 5600b57cec5SDimitry Andric M.makeDeclRefExpr(Predicate), PredicateQPtrTy), 5610b57cec5SDimitry Andric PredicateTy), 5620b57cec5SDimitry Andric M.makeIntegralCast(DoneValue, PredicateTy), 5630b57cec5SDimitry Andric PredicateTy); 5640b57cec5SDimitry Andric 5650b57cec5SDimitry Andric // (3) Create the compound statement. 5660b57cec5SDimitry Andric Stmt *Stmts[] = { B, CE }; 5670b57cec5SDimitry Andric CompoundStmt *CS = M.makeCompound(Stmts); 5680b57cec5SDimitry Andric 5690b57cec5SDimitry Andric // (4) Create the 'if' condition. 5700b57cec5SDimitry Andric ImplicitCastExpr *LValToRval = 5710b57cec5SDimitry Andric M.makeLvalueToRvalue( 5720b57cec5SDimitry Andric M.makeDereference( 5730b57cec5SDimitry Andric M.makeLvalueToRvalue( 5740b57cec5SDimitry Andric M.makeDeclRefExpr(Predicate), 5750b57cec5SDimitry Andric PredicateQPtrTy), 5760b57cec5SDimitry Andric PredicateTy), 5770b57cec5SDimitry Andric PredicateTy); 5780b57cec5SDimitry Andric 5790b57cec5SDimitry Andric Expr *GuardCondition = M.makeComparison(LValToRval, DoneValue, BO_NE); 5800b57cec5SDimitry Andric // (5) Create the 'if' statement. 581349cc55cSDimitry Andric auto *If = IfStmt::Create(C, SourceLocation(), IfStatementKind::Ordinary, 5820b57cec5SDimitry Andric /* Init=*/nullptr, 5830b57cec5SDimitry Andric /* Var=*/nullptr, 5840b57cec5SDimitry Andric /* Cond=*/GuardCondition, 585e8d8bef9SDimitry Andric /* LPL=*/SourceLocation(), 586e8d8bef9SDimitry Andric /* RPL=*/SourceLocation(), 5870b57cec5SDimitry Andric /* Then=*/CS); 5880b57cec5SDimitry Andric return If; 5890b57cec5SDimitry Andric } 5900b57cec5SDimitry Andric 5910b57cec5SDimitry Andric /// Create a fake body for dispatch_sync. 5920b57cec5SDimitry Andric static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) { 5930b57cec5SDimitry Andric // Check if we have at least two parameters. 5940b57cec5SDimitry Andric if (D->param_size() != 2) 5950b57cec5SDimitry Andric return nullptr; 5960b57cec5SDimitry Andric 5970b57cec5SDimitry Andric // Check if the second parameter is a block. 5980b57cec5SDimitry Andric const ParmVarDecl *PV = D->getParamDecl(1); 5990b57cec5SDimitry Andric QualType Ty = PV->getType(); 6000b57cec5SDimitry Andric if (!isDispatchBlock(Ty)) 6010b57cec5SDimitry Andric return nullptr; 6020b57cec5SDimitry Andric 6030b57cec5SDimitry Andric // Everything checks out. Create a fake body that just calls the block. 6040b57cec5SDimitry Andric // This is basically just an AST dump of: 6050b57cec5SDimitry Andric // 6060b57cec5SDimitry Andric // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) { 6070b57cec5SDimitry Andric // block(); 6080b57cec5SDimitry Andric // } 6090b57cec5SDimitry Andric // 6100b57cec5SDimitry Andric ASTMaker M(C); 6110b57cec5SDimitry Andric DeclRefExpr *DR = M.makeDeclRefExpr(PV); 6120b57cec5SDimitry Andric ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty); 613bdd1243dSDimitry Andric CallExpr *CE = CallExpr::Create(C, ICE, std::nullopt, C.VoidTy, VK_PRValue, 614e8d8bef9SDimitry Andric SourceLocation(), FPOptionsOverride()); 6150b57cec5SDimitry Andric return CE; 6160b57cec5SDimitry Andric } 6170b57cec5SDimitry Andric 6180b57cec5SDimitry Andric static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D) 6190b57cec5SDimitry Andric { 6200b57cec5SDimitry Andric // There are exactly 3 arguments. 6210b57cec5SDimitry Andric if (D->param_size() != 3) 6220b57cec5SDimitry Andric return nullptr; 6230b57cec5SDimitry Andric 6240b57cec5SDimitry Andric // Signature: 6250b57cec5SDimitry Andric // _Bool OSAtomicCompareAndSwapPtr(void *__oldValue, 6260b57cec5SDimitry Andric // void *__newValue, 6270b57cec5SDimitry Andric // void * volatile *__theValue) 6280b57cec5SDimitry Andric // Generate body: 6290b57cec5SDimitry Andric // if (oldValue == *theValue) { 6300b57cec5SDimitry Andric // *theValue = newValue; 6310b57cec5SDimitry Andric // return YES; 6320b57cec5SDimitry Andric // } 6330b57cec5SDimitry Andric // else return NO; 6340b57cec5SDimitry Andric 6350b57cec5SDimitry Andric QualType ResultTy = D->getReturnType(); 6360b57cec5SDimitry Andric bool isBoolean = ResultTy->isBooleanType(); 6370b57cec5SDimitry Andric if (!isBoolean && !ResultTy->isIntegralType(C)) 6380b57cec5SDimitry Andric return nullptr; 6390b57cec5SDimitry Andric 6400b57cec5SDimitry Andric const ParmVarDecl *OldValue = D->getParamDecl(0); 6410b57cec5SDimitry Andric QualType OldValueTy = OldValue->getType(); 6420b57cec5SDimitry Andric 6430b57cec5SDimitry Andric const ParmVarDecl *NewValue = D->getParamDecl(1); 6440b57cec5SDimitry Andric QualType NewValueTy = NewValue->getType(); 6450b57cec5SDimitry Andric 6460b57cec5SDimitry Andric assert(OldValueTy == NewValueTy); 6470b57cec5SDimitry Andric 6480b57cec5SDimitry Andric const ParmVarDecl *TheValue = D->getParamDecl(2); 6490b57cec5SDimitry Andric QualType TheValueTy = TheValue->getType(); 6500b57cec5SDimitry Andric const PointerType *PT = TheValueTy->getAs<PointerType>(); 6510b57cec5SDimitry Andric if (!PT) 6520b57cec5SDimitry Andric return nullptr; 6530b57cec5SDimitry Andric QualType PointeeTy = PT->getPointeeType(); 6540b57cec5SDimitry Andric 6550b57cec5SDimitry Andric ASTMaker M(C); 6560b57cec5SDimitry Andric // Construct the comparison. 6570b57cec5SDimitry Andric Expr *Comparison = 6580b57cec5SDimitry Andric M.makeComparison( 6590b57cec5SDimitry Andric M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy), 6600b57cec5SDimitry Andric M.makeLvalueToRvalue( 6610b57cec5SDimitry Andric M.makeDereference( 6620b57cec5SDimitry Andric M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy), 6630b57cec5SDimitry Andric PointeeTy), 6640b57cec5SDimitry Andric PointeeTy), 6650b57cec5SDimitry Andric BO_EQ); 6660b57cec5SDimitry Andric 6670b57cec5SDimitry Andric // Construct the body of the IfStmt. 6680b57cec5SDimitry Andric Stmt *Stmts[2]; 6690b57cec5SDimitry Andric Stmts[0] = 6700b57cec5SDimitry Andric M.makeAssignment( 6710b57cec5SDimitry Andric M.makeDereference( 6720b57cec5SDimitry Andric M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy), 6730b57cec5SDimitry Andric PointeeTy), 6740b57cec5SDimitry Andric M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy), 6750b57cec5SDimitry Andric NewValueTy); 6760b57cec5SDimitry Andric 6770b57cec5SDimitry Andric Expr *BoolVal = M.makeObjCBool(true); 6780b57cec5SDimitry Andric Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal) 6790b57cec5SDimitry Andric : M.makeIntegralCast(BoolVal, ResultTy); 6800b57cec5SDimitry Andric Stmts[1] = M.makeReturn(RetVal); 6810b57cec5SDimitry Andric CompoundStmt *Body = M.makeCompound(Stmts); 6820b57cec5SDimitry Andric 6830b57cec5SDimitry Andric // Construct the else clause. 6840b57cec5SDimitry Andric BoolVal = M.makeObjCBool(false); 6850b57cec5SDimitry Andric RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal) 6860b57cec5SDimitry Andric : M.makeIntegralCast(BoolVal, ResultTy); 6870b57cec5SDimitry Andric Stmt *Else = M.makeReturn(RetVal); 6880b57cec5SDimitry Andric 6890b57cec5SDimitry Andric /// Construct the If. 690e8d8bef9SDimitry Andric auto *If = 691349cc55cSDimitry Andric IfStmt::Create(C, SourceLocation(), IfStatementKind::Ordinary, 6920b57cec5SDimitry Andric /* Init=*/nullptr, 693e8d8bef9SDimitry Andric /* Var=*/nullptr, Comparison, 694e8d8bef9SDimitry Andric /* LPL=*/SourceLocation(), 695e8d8bef9SDimitry Andric /* RPL=*/SourceLocation(), Body, SourceLocation(), Else); 6960b57cec5SDimitry Andric 6970b57cec5SDimitry Andric return If; 6980b57cec5SDimitry Andric } 6990b57cec5SDimitry Andric 7000b57cec5SDimitry Andric Stmt *BodyFarm::getBody(const FunctionDecl *D) { 701bdd1243dSDimitry Andric std::optional<Stmt *> &Val = Bodies[D]; 70281ad6265SDimitry Andric if (Val) 703bdd1243dSDimitry Andric return *Val; 7040b57cec5SDimitry Andric 7050b57cec5SDimitry Andric Val = nullptr; 7060b57cec5SDimitry Andric 7070b57cec5SDimitry Andric if (D->getIdentifier() == nullptr) 7080b57cec5SDimitry Andric return nullptr; 7090b57cec5SDimitry Andric 7100b57cec5SDimitry Andric StringRef Name = D->getName(); 7110b57cec5SDimitry Andric if (Name.empty()) 7120b57cec5SDimitry Andric return nullptr; 7130b57cec5SDimitry Andric 7140b57cec5SDimitry Andric FunctionFarmer FF; 7150b57cec5SDimitry Andric 71681ad6265SDimitry Andric if (unsigned BuiltinID = D->getBuiltinID()) { 71781ad6265SDimitry Andric switch (BuiltinID) { 71881ad6265SDimitry Andric case Builtin::BIas_const: 71981ad6265SDimitry Andric case Builtin::BIforward: 72006c3fb27SDimitry Andric case Builtin::BIforward_like: 72181ad6265SDimitry Andric case Builtin::BImove: 72281ad6265SDimitry Andric case Builtin::BImove_if_noexcept: 72381ad6265SDimitry Andric FF = create_std_move_forward; 72481ad6265SDimitry Andric break; 72581ad6265SDimitry Andric default: 72681ad6265SDimitry Andric FF = nullptr; 72781ad6265SDimitry Andric break; 72881ad6265SDimitry Andric } 729*5f757f3fSDimitry Andric } else if (Name.starts_with("OSAtomicCompareAndSwap") || 730*5f757f3fSDimitry Andric Name.starts_with("objc_atomicCompareAndSwap")) { 7310b57cec5SDimitry Andric FF = create_OSAtomicCompareAndSwap; 7320b57cec5SDimitry Andric } else if (Name == "call_once" && D->getDeclContext()->isStdNamespace()) { 7330b57cec5SDimitry Andric FF = create_call_once; 7340b57cec5SDimitry Andric } else { 7350b57cec5SDimitry Andric FF = llvm::StringSwitch<FunctionFarmer>(Name) 7360b57cec5SDimitry Andric .Case("dispatch_sync", create_dispatch_sync) 7370b57cec5SDimitry Andric .Case("dispatch_once", create_dispatch_once) 7380b57cec5SDimitry Andric .Default(nullptr); 7390b57cec5SDimitry Andric } 7400b57cec5SDimitry Andric 7410b57cec5SDimitry Andric if (FF) { Val = FF(C, D); } 7420b57cec5SDimitry Andric else if (Injector) { Val = Injector->getBody(D); } 74381ad6265SDimitry Andric return *Val; 7440b57cec5SDimitry Andric } 7450b57cec5SDimitry Andric 7460b57cec5SDimitry Andric static const ObjCIvarDecl *findBackingIvar(const ObjCPropertyDecl *Prop) { 7470b57cec5SDimitry Andric const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl(); 7480b57cec5SDimitry Andric 7490b57cec5SDimitry Andric if (IVar) 7500b57cec5SDimitry Andric return IVar; 7510b57cec5SDimitry Andric 7520b57cec5SDimitry Andric // When a readonly property is shadowed in a class extensions with a 7530b57cec5SDimitry Andric // a readwrite property, the instance variable belongs to the shadowing 7540b57cec5SDimitry Andric // property rather than the shadowed property. If there is no instance 7550b57cec5SDimitry Andric // variable on a readonly property, check to see whether the property is 7560b57cec5SDimitry Andric // shadowed and if so try to get the instance variable from shadowing 7570b57cec5SDimitry Andric // property. 7580b57cec5SDimitry Andric if (!Prop->isReadOnly()) 7590b57cec5SDimitry Andric return nullptr; 7600b57cec5SDimitry Andric 7610b57cec5SDimitry Andric auto *Container = cast<ObjCContainerDecl>(Prop->getDeclContext()); 7620b57cec5SDimitry Andric const ObjCInterfaceDecl *PrimaryInterface = nullptr; 7630b57cec5SDimitry Andric if (auto *InterfaceDecl = dyn_cast<ObjCInterfaceDecl>(Container)) { 7640b57cec5SDimitry Andric PrimaryInterface = InterfaceDecl; 7650b57cec5SDimitry Andric } else if (auto *CategoryDecl = dyn_cast<ObjCCategoryDecl>(Container)) { 7660b57cec5SDimitry Andric PrimaryInterface = CategoryDecl->getClassInterface(); 7670b57cec5SDimitry Andric } else if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container)) { 7680b57cec5SDimitry Andric PrimaryInterface = ImplDecl->getClassInterface(); 7690b57cec5SDimitry Andric } else { 7700b57cec5SDimitry Andric return nullptr; 7710b57cec5SDimitry Andric } 7720b57cec5SDimitry Andric 7730b57cec5SDimitry Andric // FindPropertyVisibleInPrimaryClass() looks first in class extensions, so it 7740b57cec5SDimitry Andric // is guaranteed to find the shadowing property, if it exists, rather than 7750b57cec5SDimitry Andric // the shadowed property. 7760b57cec5SDimitry Andric auto *ShadowingProp = PrimaryInterface->FindPropertyVisibleInPrimaryClass( 7770b57cec5SDimitry Andric Prop->getIdentifier(), Prop->getQueryKind()); 7780b57cec5SDimitry Andric if (ShadowingProp && ShadowingProp != Prop) { 7790b57cec5SDimitry Andric IVar = ShadowingProp->getPropertyIvarDecl(); 7800b57cec5SDimitry Andric } 7810b57cec5SDimitry Andric 7820b57cec5SDimitry Andric return IVar; 7830b57cec5SDimitry Andric } 7840b57cec5SDimitry Andric 7850b57cec5SDimitry Andric static Stmt *createObjCPropertyGetter(ASTContext &Ctx, 786480093f4SDimitry Andric const ObjCMethodDecl *MD) { 7870b57cec5SDimitry Andric // First, find the backing ivar. 788480093f4SDimitry Andric const ObjCIvarDecl *IVar = nullptr; 789fe6060f1SDimitry Andric const ObjCPropertyDecl *Prop = nullptr; 790480093f4SDimitry Andric 791480093f4SDimitry Andric // Property accessor stubs sometimes do not correspond to any property decl 792480093f4SDimitry Andric // in the current interface (but in a superclass). They still have a 793480093f4SDimitry Andric // corresponding property impl decl in this case. 794480093f4SDimitry Andric if (MD->isSynthesizedAccessorStub()) { 795480093f4SDimitry Andric const ObjCInterfaceDecl *IntD = MD->getClassInterface(); 796480093f4SDimitry Andric const ObjCImplementationDecl *ImpD = IntD->getImplementation(); 797480093f4SDimitry Andric for (const auto *PI : ImpD->property_impls()) { 798fe6060f1SDimitry Andric if (const ObjCPropertyDecl *Candidate = PI->getPropertyDecl()) { 799fe6060f1SDimitry Andric if (Candidate->getGetterName() == MD->getSelector()) { 800fe6060f1SDimitry Andric Prop = Candidate; 801fe6060f1SDimitry Andric IVar = Prop->getPropertyIvarDecl(); 802fe6060f1SDimitry Andric } 803480093f4SDimitry Andric } 804480093f4SDimitry Andric } 805480093f4SDimitry Andric } 806480093f4SDimitry Andric 807480093f4SDimitry Andric if (!IVar) { 808fe6060f1SDimitry Andric Prop = MD->findPropertyDecl(); 809*5f757f3fSDimitry Andric IVar = Prop ? findBackingIvar(Prop) : nullptr; 810fe6060f1SDimitry Andric } 811fe6060f1SDimitry Andric 812fe6060f1SDimitry Andric if (!IVar || !Prop) 8130b57cec5SDimitry Andric return nullptr; 8140b57cec5SDimitry Andric 8150b57cec5SDimitry Andric // Ignore weak variables, which have special behavior. 8165ffd83dbSDimitry Andric if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak) 8170b57cec5SDimitry Andric return nullptr; 8180b57cec5SDimitry Andric 8190b57cec5SDimitry Andric // Look to see if Sema has synthesized a body for us. This happens in 8200b57cec5SDimitry Andric // Objective-C++ because the return value may be a C++ class type with a 8210b57cec5SDimitry Andric // non-trivial copy constructor. We can only do this if we can find the 8220b57cec5SDimitry Andric // @synthesize for this property, though (or if we know it's been auto- 8230b57cec5SDimitry Andric // synthesized). 8240b57cec5SDimitry Andric const ObjCImplementationDecl *ImplDecl = 8250b57cec5SDimitry Andric IVar->getContainingInterface()->getImplementation(); 8260b57cec5SDimitry Andric if (ImplDecl) { 8270b57cec5SDimitry Andric for (const auto *I : ImplDecl->property_impls()) { 8280b57cec5SDimitry Andric if (I->getPropertyDecl() != Prop) 8290b57cec5SDimitry Andric continue; 8300b57cec5SDimitry Andric 8310b57cec5SDimitry Andric if (I->getGetterCXXConstructor()) { 8320b57cec5SDimitry Andric ASTMaker M(Ctx); 8330b57cec5SDimitry Andric return M.makeReturn(I->getGetterCXXConstructor()); 8340b57cec5SDimitry Andric } 8350b57cec5SDimitry Andric } 8360b57cec5SDimitry Andric } 8370b57cec5SDimitry Andric 8385e801ac6SDimitry Andric // We expect that the property is the same type as the ivar, or a reference to 8395e801ac6SDimitry Andric // it, and that it is either an object pointer or trivially copyable. 8400b57cec5SDimitry Andric if (!Ctx.hasSameUnqualifiedType(IVar->getType(), 8410b57cec5SDimitry Andric Prop->getType().getNonReferenceType())) 8420b57cec5SDimitry Andric return nullptr; 8430b57cec5SDimitry Andric if (!IVar->getType()->isObjCLifetimeType() && 8440b57cec5SDimitry Andric !IVar->getType().isTriviallyCopyableType(Ctx)) 8450b57cec5SDimitry Andric return nullptr; 8460b57cec5SDimitry Andric 8470b57cec5SDimitry Andric // Generate our body: 8480b57cec5SDimitry Andric // return self->_ivar; 8490b57cec5SDimitry Andric ASTMaker M(Ctx); 8500b57cec5SDimitry Andric 851480093f4SDimitry Andric const VarDecl *selfVar = MD->getSelfDecl(); 8520b57cec5SDimitry Andric if (!selfVar) 8530b57cec5SDimitry Andric return nullptr; 8540b57cec5SDimitry Andric 855fe6060f1SDimitry Andric Expr *loadedIVar = M.makeObjCIvarRef( 856fe6060f1SDimitry Andric M.makeLvalueToRvalue(M.makeDeclRefExpr(selfVar), selfVar->getType()), 8570b57cec5SDimitry Andric IVar); 8580b57cec5SDimitry Andric 859480093f4SDimitry Andric if (!MD->getReturnType()->isReferenceType()) 8600b57cec5SDimitry Andric loadedIVar = M.makeLvalueToRvalue(loadedIVar, IVar->getType()); 8610b57cec5SDimitry Andric 8620b57cec5SDimitry Andric return M.makeReturn(loadedIVar); 8630b57cec5SDimitry Andric } 8640b57cec5SDimitry Andric 8650b57cec5SDimitry Andric Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) { 8660b57cec5SDimitry Andric // We currently only know how to synthesize property accessors. 8670b57cec5SDimitry Andric if (!D->isPropertyAccessor()) 8680b57cec5SDimitry Andric return nullptr; 8690b57cec5SDimitry Andric 8700b57cec5SDimitry Andric D = D->getCanonicalDecl(); 8710b57cec5SDimitry Andric 8720b57cec5SDimitry Andric // We should not try to synthesize explicitly redefined accessors. 8730b57cec5SDimitry Andric // We do not know for sure how they behave. 8740b57cec5SDimitry Andric if (!D->isImplicit()) 8750b57cec5SDimitry Andric return nullptr; 8760b57cec5SDimitry Andric 877bdd1243dSDimitry Andric std::optional<Stmt *> &Val = Bodies[D]; 87881ad6265SDimitry Andric if (Val) 879bdd1243dSDimitry Andric return *Val; 8800b57cec5SDimitry Andric Val = nullptr; 8810b57cec5SDimitry Andric 8820b57cec5SDimitry Andric // For now, we only synthesize getters. 8830b57cec5SDimitry Andric // Synthesizing setters would cause false negatives in the 8840b57cec5SDimitry Andric // RetainCountChecker because the method body would bind the parameter 8850b57cec5SDimitry Andric // to an instance variable, causing it to escape. This would prevent 8860b57cec5SDimitry Andric // warning in the following common scenario: 8870b57cec5SDimitry Andric // 8880b57cec5SDimitry Andric // id foo = [[NSObject alloc] init]; 8890b57cec5SDimitry Andric // self.foo = foo; // We should warn that foo leaks here. 8900b57cec5SDimitry Andric // 8910b57cec5SDimitry Andric if (D->param_size() != 0) 8920b57cec5SDimitry Andric return nullptr; 8930b57cec5SDimitry Andric 894480093f4SDimitry Andric // If the property was defined in an extension, search the extensions for 895480093f4SDimitry Andric // overrides. 896480093f4SDimitry Andric const ObjCInterfaceDecl *OID = D->getClassInterface(); 897480093f4SDimitry Andric if (dyn_cast<ObjCInterfaceDecl>(D->getParent()) != OID) 898480093f4SDimitry Andric for (auto *Ext : OID->known_extensions()) { 899480093f4SDimitry Andric auto *OMD = Ext->getInstanceMethod(D->getSelector()); 900480093f4SDimitry Andric if (OMD && !OMD->isImplicit()) 901480093f4SDimitry Andric return nullptr; 902480093f4SDimitry Andric } 903480093f4SDimitry Andric 904480093f4SDimitry Andric Val = createObjCPropertyGetter(C, D); 9050b57cec5SDimitry Andric 90681ad6265SDimitry Andric return *Val; 9070b57cec5SDimitry Andric } 908