brintos

brintos / llvm-project-archived public Read only

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