1243791Sdim//== BodyFarm.cpp - Factory for conjuring up fake bodies ----------*- C++ -*-// 2243791Sdim// 3243791Sdim// The LLVM Compiler Infrastructure 4243791Sdim// 5243791Sdim// This file is distributed under the University of Illinois Open Source 6243791Sdim// License. See LICENSE.TXT for details. 7243791Sdim// 8243791Sdim//===----------------------------------------------------------------------===// 9243791Sdim// 10243791Sdim// BodyFarm is a factory for creating faux implementations for functions/methods 11243791Sdim// for analysis purposes. 12243791Sdim// 13243791Sdim//===----------------------------------------------------------------------===// 14243791Sdim 15252723Sdim#include "BodyFarm.h" 16243791Sdim#include "clang/AST/ASTContext.h" 17252723Sdim#include "clang/AST/Decl.h" 18243791Sdim#include "clang/AST/Expr.h" 19243791Sdim#include "clang/AST/ExprObjC.h" 20252723Sdim#include "llvm/ADT/StringSwitch.h" 21243791Sdim 22243791Sdimusing namespace clang; 23243791Sdim 24243791Sdim//===----------------------------------------------------------------------===// 25243791Sdim// Helper creation functions for constructing faux ASTs. 26243791Sdim//===----------------------------------------------------------------------===// 27243791Sdim 28243791Sdimstatic bool isDispatchBlock(QualType Ty) { 29243791Sdim // Is it a block pointer? 30243791Sdim const BlockPointerType *BPT = Ty->getAs<BlockPointerType>(); 31243791Sdim if (!BPT) 32243791Sdim return false; 33243791Sdim 34243791Sdim // Check if the block pointer type takes no arguments and 35243791Sdim // returns void. 36243791Sdim const FunctionProtoType *FT = 37243791Sdim BPT->getPointeeType()->getAs<FunctionProtoType>(); 38243791Sdim if (!FT || !FT->getResultType()->isVoidType() || 39243791Sdim FT->getNumArgs() != 0) 40243791Sdim return false; 41243791Sdim 42243791Sdim return true; 43243791Sdim} 44243791Sdim 45243791Sdimnamespace { 46243791Sdimclass ASTMaker { 47243791Sdimpublic: 48243791Sdim ASTMaker(ASTContext &C) : C(C) {} 49243791Sdim 50243791Sdim /// Create a new BinaryOperator representing a simple assignment. 51243791Sdim BinaryOperator *makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty); 52243791Sdim 53243791Sdim /// Create a new BinaryOperator representing a comparison. 54243791Sdim BinaryOperator *makeComparison(const Expr *LHS, const Expr *RHS, 55243791Sdim BinaryOperator::Opcode Op); 56243791Sdim 57243791Sdim /// Create a new compound stmt using the provided statements. 58243791Sdim CompoundStmt *makeCompound(ArrayRef<Stmt*>); 59243791Sdim 60243791Sdim /// Create a new DeclRefExpr for the referenced variable. 61243791Sdim DeclRefExpr *makeDeclRefExpr(const VarDecl *D); 62243791Sdim 63243791Sdim /// Create a new UnaryOperator representing a dereference. 64243791Sdim UnaryOperator *makeDereference(const Expr *Arg, QualType Ty); 65243791Sdim 66243791Sdim /// Create an implicit cast for an integer conversion. 67243791Sdim Expr *makeIntegralCast(const Expr *Arg, QualType Ty); 68243791Sdim 69243791Sdim /// Create an implicit cast to a builtin boolean type. 70243791Sdim ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg); 71243791Sdim 72243791Sdim // Create an implicit cast for lvalue-to-rvaluate conversions. 73243791Sdim ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty); 74243791Sdim 75243791Sdim /// Create an Objective-C bool literal. 76243791Sdim ObjCBoolLiteralExpr *makeObjCBool(bool Val); 77243791Sdim 78243791Sdim /// Create a Return statement. 79243791Sdim ReturnStmt *makeReturn(const Expr *RetVal); 80243791Sdim 81243791Sdimprivate: 82243791Sdim ASTContext &C; 83243791Sdim}; 84243791Sdim} 85243791Sdim 86243791SdimBinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS, 87243791Sdim QualType Ty) { 88243791Sdim return new (C) BinaryOperator(const_cast<Expr*>(LHS), const_cast<Expr*>(RHS), 89243791Sdim BO_Assign, Ty, VK_RValue, 90243791Sdim OK_Ordinary, SourceLocation(), false); 91243791Sdim} 92243791Sdim 93243791SdimBinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS, 94243791Sdim BinaryOperator::Opcode Op) { 95243791Sdim assert(BinaryOperator::isLogicalOp(Op) || 96243791Sdim BinaryOperator::isComparisonOp(Op)); 97243791Sdim return new (C) BinaryOperator(const_cast<Expr*>(LHS), 98243791Sdim const_cast<Expr*>(RHS), 99243791Sdim Op, 100243791Sdim C.getLogicalOperationType(), 101243791Sdim VK_RValue, 102243791Sdim OK_Ordinary, SourceLocation(), false); 103243791Sdim} 104243791Sdim 105243791SdimCompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) { 106252723Sdim return new (C) CompoundStmt(C, Stmts, SourceLocation(), SourceLocation()); 107243791Sdim} 108243791Sdim 109243791SdimDeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) { 110243791Sdim DeclRefExpr *DR = 111243791Sdim DeclRefExpr::Create(/* Ctx = */ C, 112243791Sdim /* QualifierLoc = */ NestedNameSpecifierLoc(), 113243791Sdim /* TemplateKWLoc = */ SourceLocation(), 114243791Sdim /* D = */ const_cast<VarDecl*>(D), 115243791Sdim /* isEnclosingLocal = */ false, 116243791Sdim /* NameLoc = */ SourceLocation(), 117243791Sdim /* T = */ D->getType(), 118243791Sdim /* VK = */ VK_LValue); 119243791Sdim return DR; 120243791Sdim} 121243791Sdim 122243791SdimUnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) { 123243791Sdim return new (C) UnaryOperator(const_cast<Expr*>(Arg), UO_Deref, Ty, 124243791Sdim VK_LValue, OK_Ordinary, SourceLocation()); 125243791Sdim} 126243791Sdim 127243791SdimImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) { 128243791Sdim return ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue, 129243791Sdim const_cast<Expr*>(Arg), 0, VK_RValue); 130243791Sdim} 131243791Sdim 132243791SdimExpr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) { 133243791Sdim if (Arg->getType() == Ty) 134243791Sdim return const_cast<Expr*>(Arg); 135243791Sdim 136243791Sdim return ImplicitCastExpr::Create(C, Ty, CK_IntegralCast, 137243791Sdim const_cast<Expr*>(Arg), 0, VK_RValue); 138243791Sdim} 139243791Sdim 140243791SdimImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) { 141243791Sdim return ImplicitCastExpr::Create(C, C.BoolTy, CK_IntegralToBoolean, 142243791Sdim const_cast<Expr*>(Arg), 0, VK_RValue); 143243791Sdim} 144243791Sdim 145243791SdimObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) { 146243791Sdim QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy; 147243791Sdim return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation()); 148243791Sdim} 149243791Sdim 150243791SdimReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) { 151243791Sdim return new (C) ReturnStmt(SourceLocation(), const_cast<Expr*>(RetVal), 0); 152243791Sdim} 153243791Sdim 154243791Sdim//===----------------------------------------------------------------------===// 155243791Sdim// Creation functions for faux ASTs. 156243791Sdim//===----------------------------------------------------------------------===// 157243791Sdim 158243791Sdimtypedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D); 159243791Sdim 160243791Sdim/// Create a fake body for dispatch_once. 161243791Sdimstatic Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { 162243791Sdim // Check if we have at least two parameters. 163243791Sdim if (D->param_size() != 2) 164243791Sdim return 0; 165243791Sdim 166243791Sdim // Check if the first parameter is a pointer to integer type. 167243791Sdim const ParmVarDecl *Predicate = D->getParamDecl(0); 168243791Sdim QualType PredicateQPtrTy = Predicate->getType(); 169243791Sdim const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>(); 170243791Sdim if (!PredicatePtrTy) 171243791Sdim return 0; 172243791Sdim QualType PredicateTy = PredicatePtrTy->getPointeeType(); 173243791Sdim if (!PredicateTy->isIntegerType()) 174243791Sdim return 0; 175243791Sdim 176243791Sdim // Check if the second parameter is the proper block type. 177243791Sdim const ParmVarDecl *Block = D->getParamDecl(1); 178243791Sdim QualType Ty = Block->getType(); 179243791Sdim if (!isDispatchBlock(Ty)) 180243791Sdim return 0; 181243791Sdim 182243791Sdim // Everything checks out. Create a fakse body that checks the predicate, 183243791Sdim // sets it, and calls the block. Basically, an AST dump of: 184243791Sdim // 185243791Sdim // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) { 186243791Sdim // if (!*predicate) { 187243791Sdim // *predicate = 1; 188243791Sdim // block(); 189243791Sdim // } 190243791Sdim // } 191243791Sdim 192243791Sdim ASTMaker M(C); 193243791Sdim 194243791Sdim // (1) Create the call. 195243791Sdim DeclRefExpr *DR = M.makeDeclRefExpr(Block); 196243791Sdim ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty); 197252723Sdim CallExpr *CE = new (C) CallExpr(C, ICE, None, C.VoidTy, VK_RValue, 198252723Sdim SourceLocation()); 199243791Sdim 200243791Sdim // (2) Create the assignment to the predicate. 201243791Sdim IntegerLiteral *IL = 202243791Sdim IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), (uint64_t) 1), 203243791Sdim C.IntTy, SourceLocation()); 204243791Sdim BinaryOperator *B = 205243791Sdim M.makeAssignment( 206243791Sdim M.makeDereference( 207243791Sdim M.makeLvalueToRvalue( 208243791Sdim M.makeDeclRefExpr(Predicate), PredicateQPtrTy), 209243791Sdim PredicateTy), 210243791Sdim M.makeIntegralCast(IL, PredicateTy), 211243791Sdim PredicateTy); 212243791Sdim 213243791Sdim // (3) Create the compound statement. 214243791Sdim Stmt *Stmts[2]; 215243791Sdim Stmts[0] = B; 216243791Sdim Stmts[1] = CE; 217243791Sdim CompoundStmt *CS = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2)); 218243791Sdim 219243791Sdim // (4) Create the 'if' condition. 220243791Sdim ImplicitCastExpr *LValToRval = 221243791Sdim M.makeLvalueToRvalue( 222243791Sdim M.makeDereference( 223243791Sdim M.makeLvalueToRvalue( 224243791Sdim M.makeDeclRefExpr(Predicate), 225243791Sdim PredicateQPtrTy), 226243791Sdim PredicateTy), 227243791Sdim PredicateTy); 228243791Sdim 229243791Sdim UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy, 230243791Sdim VK_RValue, OK_Ordinary, 231243791Sdim SourceLocation()); 232243791Sdim 233243791Sdim // (5) Create the 'if' statement. 234243791Sdim IfStmt *If = new (C) IfStmt(C, SourceLocation(), 0, UO, CS); 235243791Sdim return If; 236243791Sdim} 237243791Sdim 238243791Sdim/// Create a fake body for dispatch_sync. 239243791Sdimstatic Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) { 240243791Sdim // Check if we have at least two parameters. 241243791Sdim if (D->param_size() != 2) 242243791Sdim return 0; 243243791Sdim 244243791Sdim // Check if the second parameter is a block. 245243791Sdim const ParmVarDecl *PV = D->getParamDecl(1); 246243791Sdim QualType Ty = PV->getType(); 247243791Sdim if (!isDispatchBlock(Ty)) 248243791Sdim return 0; 249243791Sdim 250243791Sdim // Everything checks out. Create a fake body that just calls the block. 251243791Sdim // This is basically just an AST dump of: 252243791Sdim // 253243791Sdim // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) { 254243791Sdim // block(); 255243791Sdim // } 256243791Sdim // 257243791Sdim ASTMaker M(C); 258243791Sdim DeclRefExpr *DR = M.makeDeclRefExpr(PV); 259243791Sdim ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty); 260252723Sdim CallExpr *CE = new (C) CallExpr(C, ICE, None, C.VoidTy, VK_RValue, 261252723Sdim SourceLocation()); 262243791Sdim return CE; 263243791Sdim} 264243791Sdim 265243791Sdimstatic Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D) 266243791Sdim{ 267243791Sdim // There are exactly 3 arguments. 268243791Sdim if (D->param_size() != 3) 269243791Sdim return 0; 270243791Sdim 271252723Sdim // Signature: 272252723Sdim // _Bool OSAtomicCompareAndSwapPtr(void *__oldValue, 273252723Sdim // void *__newValue, 274252723Sdim // void * volatile *__theValue) 275252723Sdim // Generate body: 276243791Sdim // if (oldValue == *theValue) { 277243791Sdim // *theValue = newValue; 278243791Sdim // return YES; 279243791Sdim // } 280243791Sdim // else return NO; 281243791Sdim 282243791Sdim QualType ResultTy = D->getResultType(); 283243791Sdim bool isBoolean = ResultTy->isBooleanType(); 284243791Sdim if (!isBoolean && !ResultTy->isIntegralType(C)) 285243791Sdim return 0; 286243791Sdim 287243791Sdim const ParmVarDecl *OldValue = D->getParamDecl(0); 288243791Sdim QualType OldValueTy = OldValue->getType(); 289243791Sdim 290243791Sdim const ParmVarDecl *NewValue = D->getParamDecl(1); 291243791Sdim QualType NewValueTy = NewValue->getType(); 292243791Sdim 293243791Sdim assert(OldValueTy == NewValueTy); 294243791Sdim 295243791Sdim const ParmVarDecl *TheValue = D->getParamDecl(2); 296243791Sdim QualType TheValueTy = TheValue->getType(); 297243791Sdim const PointerType *PT = TheValueTy->getAs<PointerType>(); 298243791Sdim if (!PT) 299243791Sdim return 0; 300243791Sdim QualType PointeeTy = PT->getPointeeType(); 301243791Sdim 302243791Sdim ASTMaker M(C); 303243791Sdim // Construct the comparison. 304243791Sdim Expr *Comparison = 305243791Sdim M.makeComparison( 306243791Sdim M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy), 307243791Sdim M.makeLvalueToRvalue( 308243791Sdim M.makeDereference( 309243791Sdim M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy), 310243791Sdim PointeeTy), 311243791Sdim PointeeTy), 312243791Sdim BO_EQ); 313243791Sdim 314243791Sdim // Construct the body of the IfStmt. 315243791Sdim Stmt *Stmts[2]; 316243791Sdim Stmts[0] = 317243791Sdim M.makeAssignment( 318243791Sdim M.makeDereference( 319243791Sdim M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy), 320243791Sdim PointeeTy), 321243791Sdim M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy), 322243791Sdim NewValueTy); 323243791Sdim 324243791Sdim Expr *BoolVal = M.makeObjCBool(true); 325243791Sdim Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal) 326243791Sdim : M.makeIntegralCast(BoolVal, ResultTy); 327243791Sdim Stmts[1] = M.makeReturn(RetVal); 328243791Sdim CompoundStmt *Body = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2)); 329243791Sdim 330243791Sdim // Construct the else clause. 331243791Sdim BoolVal = M.makeObjCBool(false); 332243791Sdim RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal) 333243791Sdim : M.makeIntegralCast(BoolVal, ResultTy); 334243791Sdim Stmt *Else = M.makeReturn(RetVal); 335243791Sdim 336243791Sdim /// Construct the If. 337243791Sdim Stmt *If = 338243791Sdim new (C) IfStmt(C, SourceLocation(), 0, Comparison, Body, 339243791Sdim SourceLocation(), Else); 340243791Sdim 341243791Sdim return If; 342243791Sdim} 343243791Sdim 344243791SdimStmt *BodyFarm::getBody(const FunctionDecl *D) { 345243791Sdim D = D->getCanonicalDecl(); 346243791Sdim 347252723Sdim Optional<Stmt *> &Val = Bodies[D]; 348243791Sdim if (Val.hasValue()) 349243791Sdim return Val.getValue(); 350243791Sdim 351243791Sdim Val = 0; 352243791Sdim 353243791Sdim if (D->getIdentifier() == 0) 354243791Sdim return 0; 355243791Sdim 356243791Sdim StringRef Name = D->getName(); 357243791Sdim if (Name.empty()) 358243791Sdim return 0; 359243791Sdim 360243791Sdim FunctionFarmer FF; 361243791Sdim 362243791Sdim if (Name.startswith("OSAtomicCompareAndSwap") || 363243791Sdim Name.startswith("objc_atomicCompareAndSwap")) { 364243791Sdim FF = create_OSAtomicCompareAndSwap; 365243791Sdim } 366243791Sdim else { 367243791Sdim FF = llvm::StringSwitch<FunctionFarmer>(Name) 368243791Sdim .Case("dispatch_sync", create_dispatch_sync) 369243791Sdim .Case("dispatch_once", create_dispatch_once) 370243791Sdim .Default(NULL); 371243791Sdim } 372243791Sdim 373243791Sdim if (FF) { Val = FF(C, D); } 374243791Sdim return Val.getValue(); 375243791Sdim} 376243791Sdim 377