clang API Documentation

BodyFarm.cpp
Go to the documentation of this file.
00001 //== BodyFarm.cpp  - Factory for conjuring up fake bodies ----------*- C++ -*-//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // BodyFarm is a factory for creating faux implementations for functions/methods
00011 // for analysis purposes.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "BodyFarm.h"
00016 #include "clang/Analysis/CodeInjector.h"
00017 #include "clang/AST/ASTContext.h"
00018 #include "clang/AST/Decl.h"
00019 #include "clang/AST/Expr.h"
00020 #include "clang/AST/ExprObjC.h"
00021 #include "llvm/ADT/StringSwitch.h"
00022 
00023 using namespace clang;
00024 
00025 //===----------------------------------------------------------------------===//
00026 // Helper creation functions for constructing faux ASTs.
00027 //===----------------------------------------------------------------------===//
00028 
00029 static bool isDispatchBlock(QualType Ty) {
00030   // Is it a block pointer?
00031   const BlockPointerType *BPT = Ty->getAs<BlockPointerType>();
00032   if (!BPT)
00033     return false;
00034 
00035   // Check if the block pointer type takes no arguments and
00036   // returns void.
00037   const FunctionProtoType *FT =
00038   BPT->getPointeeType()->getAs<FunctionProtoType>();
00039   if (!FT || !FT->getReturnType()->isVoidType() || FT->getNumParams() != 0)
00040     return false;
00041 
00042   return true;
00043 }
00044 
00045 namespace {
00046 class ASTMaker {
00047 public:
00048   ASTMaker(ASTContext &C) : C(C) {}
00049   
00050   /// Create a new BinaryOperator representing a simple assignment.
00051   BinaryOperator *makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty);
00052   
00053   /// Create a new BinaryOperator representing a comparison.
00054   BinaryOperator *makeComparison(const Expr *LHS, const Expr *RHS,
00055                                  BinaryOperator::Opcode Op);
00056   
00057   /// Create a new compound stmt using the provided statements.
00058   CompoundStmt *makeCompound(ArrayRef<Stmt*>);
00059   
00060   /// Create a new DeclRefExpr for the referenced variable.
00061   DeclRefExpr *makeDeclRefExpr(const VarDecl *D);
00062   
00063   /// Create a new UnaryOperator representing a dereference.
00064   UnaryOperator *makeDereference(const Expr *Arg, QualType Ty);
00065   
00066   /// Create an implicit cast for an integer conversion.
00067   Expr *makeIntegralCast(const Expr *Arg, QualType Ty);
00068   
00069   /// Create an implicit cast to a builtin boolean type.
00070   ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg);
00071   
00072   // Create an implicit cast for lvalue-to-rvaluate conversions.
00073   ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty);
00074   
00075   /// Create an Objective-C bool literal.
00076   ObjCBoolLiteralExpr *makeObjCBool(bool Val);
00077 
00078   /// Create an Objective-C ivar reference.
00079   ObjCIvarRefExpr *makeObjCIvarRef(const Expr *Base, const ObjCIvarDecl *IVar);
00080   
00081   /// Create a Return statement.
00082   ReturnStmt *makeReturn(const Expr *RetVal);
00083   
00084 private:
00085   ASTContext &C;
00086 };
00087 }
00088 
00089 BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS,
00090                                          QualType Ty) {
00091  return new (C) BinaryOperator(const_cast<Expr*>(LHS), const_cast<Expr*>(RHS),
00092                                BO_Assign, Ty, VK_RValue,
00093                                OK_Ordinary, SourceLocation(), false);
00094 }
00095 
00096 BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,
00097                                          BinaryOperator::Opcode Op) {
00098   assert(BinaryOperator::isLogicalOp(Op) ||
00099          BinaryOperator::isComparisonOp(Op));
00100   return new (C) BinaryOperator(const_cast<Expr*>(LHS),
00101                                 const_cast<Expr*>(RHS),
00102                                 Op,
00103                                 C.getLogicalOperationType(),
00104                                 VK_RValue,
00105                                 OK_Ordinary, SourceLocation(), false);
00106 }
00107 
00108 CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {
00109   return new (C) CompoundStmt(C, Stmts, SourceLocation(), SourceLocation());
00110 }
00111 
00112 DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) {
00113   DeclRefExpr *DR =
00114     DeclRefExpr::Create(/* Ctx = */ C,
00115                         /* QualifierLoc = */ NestedNameSpecifierLoc(),
00116                         /* TemplateKWLoc = */ SourceLocation(),
00117                         /* D = */ const_cast<VarDecl*>(D),
00118                         /* isEnclosingLocal = */ false,
00119                         /* NameLoc = */ SourceLocation(),
00120                         /* T = */ D->getType(),
00121                         /* VK = */ VK_LValue);
00122   return DR;
00123 }
00124 
00125 UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {
00126   return new (C) UnaryOperator(const_cast<Expr*>(Arg), UO_Deref, Ty,
00127                                VK_LValue, OK_Ordinary, SourceLocation());
00128 }
00129 
00130 ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
00131   return ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
00132                                   const_cast<Expr*>(Arg), nullptr, VK_RValue);
00133 }
00134 
00135 Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
00136   if (Arg->getType() == Ty)
00137     return const_cast<Expr*>(Arg);
00138 
00139   return ImplicitCastExpr::Create(C, Ty, CK_IntegralCast,
00140                                   const_cast<Expr*>(Arg), nullptr, VK_RValue);
00141 }
00142 
00143 ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) {
00144   return ImplicitCastExpr::Create(C, C.BoolTy, CK_IntegralToBoolean,
00145                                   const_cast<Expr*>(Arg), nullptr, VK_RValue);
00146 }
00147 
00148 ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) {
00149   QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy;
00150   return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation());
00151 }
00152 
00153 ObjCIvarRefExpr *ASTMaker::makeObjCIvarRef(const Expr *Base,
00154                                            const ObjCIvarDecl *IVar) {
00155   return new (C) ObjCIvarRefExpr(const_cast<ObjCIvarDecl*>(IVar),
00156                                  IVar->getType(), SourceLocation(),
00157                                  SourceLocation(), const_cast<Expr*>(Base),
00158                                  /*arrow=*/true, /*free=*/false);
00159 }
00160 
00161 
00162 ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) {
00163   return new (C) ReturnStmt(SourceLocation(), const_cast<Expr*>(RetVal),
00164                             nullptr);
00165 }
00166 
00167 //===----------------------------------------------------------------------===//
00168 // Creation functions for faux ASTs.
00169 //===----------------------------------------------------------------------===//
00170 
00171 typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
00172 
00173 /// Create a fake body for dispatch_once.
00174 static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
00175   // Check if we have at least two parameters.
00176   if (D->param_size() != 2)
00177     return nullptr;
00178 
00179   // Check if the first parameter is a pointer to integer type.
00180   const ParmVarDecl *Predicate = D->getParamDecl(0);
00181   QualType PredicateQPtrTy = Predicate->getType();
00182   const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();
00183   if (!PredicatePtrTy)
00184     return nullptr;
00185   QualType PredicateTy = PredicatePtrTy->getPointeeType();
00186   if (!PredicateTy->isIntegerType())
00187     return nullptr;
00188 
00189   // Check if the second parameter is the proper block type.
00190   const ParmVarDecl *Block = D->getParamDecl(1);
00191   QualType Ty = Block->getType();
00192   if (!isDispatchBlock(Ty))
00193     return nullptr;
00194 
00195   // Everything checks out.  Create a fakse body that checks the predicate,
00196   // sets it, and calls the block.  Basically, an AST dump of:
00197   //
00198   // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
00199   //  if (!*predicate) {
00200   //    *predicate = 1;
00201   //    block();
00202   //  }
00203   // }
00204   
00205   ASTMaker M(C);
00206   
00207   // (1) Create the call.
00208   DeclRefExpr *DR = M.makeDeclRefExpr(Block);
00209   ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
00210   CallExpr *CE = new (C) CallExpr(C, ICE, None, C.VoidTy, VK_RValue,
00211                                   SourceLocation());
00212 
00213   // (2) Create the assignment to the predicate.
00214   IntegerLiteral *IL =
00215     IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), (uint64_t) 1),
00216                            C.IntTy, SourceLocation());
00217   BinaryOperator *B =
00218     M.makeAssignment(
00219        M.makeDereference(
00220           M.makeLvalueToRvalue(
00221             M.makeDeclRefExpr(Predicate), PredicateQPtrTy),
00222             PredicateTy),
00223        M.makeIntegralCast(IL, PredicateTy),
00224        PredicateTy);
00225   
00226   // (3) Create the compound statement.
00227   Stmt *Stmts[] = { B, CE };
00228   CompoundStmt *CS = M.makeCompound(Stmts);
00229   
00230   // (4) Create the 'if' condition.
00231   ImplicitCastExpr *LValToRval =
00232     M.makeLvalueToRvalue(
00233       M.makeDereference(
00234         M.makeLvalueToRvalue(
00235           M.makeDeclRefExpr(Predicate),
00236           PredicateQPtrTy),
00237         PredicateTy),
00238     PredicateTy);
00239   
00240   UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy,
00241                                            VK_RValue, OK_Ordinary,
00242                                            SourceLocation());
00243   
00244   // (5) Create the 'if' statement.
00245   IfStmt *If = new (C) IfStmt(C, SourceLocation(), nullptr, UO, CS);
00246   return If;
00247 }
00248 
00249 /// Create a fake body for dispatch_sync.
00250 static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
00251   // Check if we have at least two parameters.
00252   if (D->param_size() != 2)
00253     return nullptr;
00254 
00255   // Check if the second parameter is a block.
00256   const ParmVarDecl *PV = D->getParamDecl(1);
00257   QualType Ty = PV->getType();
00258   if (!isDispatchBlock(Ty))
00259     return nullptr;
00260 
00261   // Everything checks out.  Create a fake body that just calls the block.
00262   // This is basically just an AST dump of:
00263   //
00264   // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) {
00265   //   block();
00266   // }
00267   //  
00268   ASTMaker M(C);
00269   DeclRefExpr *DR = M.makeDeclRefExpr(PV);
00270   ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
00271   CallExpr *CE = new (C) CallExpr(C, ICE, None, C.VoidTy, VK_RValue,
00272                                   SourceLocation());
00273   return CE;
00274 }
00275 
00276 static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
00277 {
00278   // There are exactly 3 arguments.
00279   if (D->param_size() != 3)
00280     return nullptr;
00281 
00282   // Signature:
00283   // _Bool OSAtomicCompareAndSwapPtr(void *__oldValue,
00284   //                                 void *__newValue,
00285   //                                 void * volatile *__theValue)
00286   // Generate body:
00287   //   if (oldValue == *theValue) {
00288   //    *theValue = newValue;
00289   //    return YES;
00290   //   }
00291   //   else return NO;
00292 
00293   QualType ResultTy = D->getReturnType();
00294   bool isBoolean = ResultTy->isBooleanType();
00295   if (!isBoolean && !ResultTy->isIntegralType(C))
00296     return nullptr;
00297 
00298   const ParmVarDecl *OldValue = D->getParamDecl(0);
00299   QualType OldValueTy = OldValue->getType();
00300 
00301   const ParmVarDecl *NewValue = D->getParamDecl(1);
00302   QualType NewValueTy = NewValue->getType();
00303   
00304   assert(OldValueTy == NewValueTy);
00305   
00306   const ParmVarDecl *TheValue = D->getParamDecl(2);
00307   QualType TheValueTy = TheValue->getType();
00308   const PointerType *PT = TheValueTy->getAs<PointerType>();
00309   if (!PT)
00310     return nullptr;
00311   QualType PointeeTy = PT->getPointeeType();
00312   
00313   ASTMaker M(C);
00314   // Construct the comparison.
00315   Expr *Comparison =
00316     M.makeComparison(
00317       M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy),
00318       M.makeLvalueToRvalue(
00319         M.makeDereference(
00320           M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
00321           PointeeTy),
00322         PointeeTy),
00323       BO_EQ);
00324 
00325   // Construct the body of the IfStmt.
00326   Stmt *Stmts[2];
00327   Stmts[0] =
00328     M.makeAssignment(
00329       M.makeDereference(
00330         M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
00331         PointeeTy),
00332       M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy),
00333       NewValueTy);
00334   
00335   Expr *BoolVal = M.makeObjCBool(true);
00336   Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
00337                            : M.makeIntegralCast(BoolVal, ResultTy);
00338   Stmts[1] = M.makeReturn(RetVal);
00339   CompoundStmt *Body = M.makeCompound(Stmts);
00340   
00341   // Construct the else clause.
00342   BoolVal = M.makeObjCBool(false);
00343   RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
00344                      : M.makeIntegralCast(BoolVal, ResultTy);
00345   Stmt *Else = M.makeReturn(RetVal);
00346   
00347   /// Construct the If.
00348   Stmt *If =
00349     new (C) IfStmt(C, SourceLocation(), nullptr, Comparison, Body,
00350                    SourceLocation(), Else);
00351 
00352   return If;  
00353 }
00354 
00355 Stmt *BodyFarm::getBody(const FunctionDecl *D) {
00356   D = D->getCanonicalDecl();
00357   
00358   Optional<Stmt *> &Val = Bodies[D];
00359   if (Val.hasValue())
00360     return Val.getValue();
00361 
00362   Val = nullptr;
00363 
00364   if (D->getIdentifier() == nullptr)
00365     return nullptr;
00366 
00367   StringRef Name = D->getName();
00368   if (Name.empty())
00369     return nullptr;
00370 
00371   FunctionFarmer FF;
00372 
00373   if (Name.startswith("OSAtomicCompareAndSwap") ||
00374       Name.startswith("objc_atomicCompareAndSwap")) {
00375     FF = create_OSAtomicCompareAndSwap;
00376   }
00377   else {
00378     FF = llvm::StringSwitch<FunctionFarmer>(Name)
00379           .Case("dispatch_sync", create_dispatch_sync)
00380           .Case("dispatch_once", create_dispatch_once)
00381           .Default(nullptr);
00382   }
00383   
00384   if (FF) { Val = FF(C, D); }
00385   else if (Injector) { Val = Injector->getBody(D); }
00386   return Val.getValue();
00387 }
00388 
00389 static Stmt *createObjCPropertyGetter(ASTContext &Ctx,
00390                                       const ObjCPropertyDecl *Prop) {
00391   // First, find the backing ivar.
00392   const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl();
00393   if (!IVar)
00394     return nullptr;
00395 
00396   // Ignore weak variables, which have special behavior.
00397   if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)
00398     return nullptr;
00399 
00400   // Look to see if Sema has synthesized a body for us. This happens in
00401   // Objective-C++ because the return value may be a C++ class type with a
00402   // non-trivial copy constructor. We can only do this if we can find the
00403   // @synthesize for this property, though (or if we know it's been auto-
00404   // synthesized).
00405   const ObjCImplementationDecl *ImplDecl =
00406     IVar->getContainingInterface()->getImplementation();
00407   if (ImplDecl) {
00408     for (const auto *I : ImplDecl->property_impls()) {
00409       if (I->getPropertyDecl() != Prop)
00410         continue;
00411 
00412       if (I->getGetterCXXConstructor()) {
00413         ASTMaker M(Ctx);
00414         return M.makeReturn(I->getGetterCXXConstructor());
00415       }
00416     }
00417   }
00418 
00419   // Sanity check that the property is the same type as the ivar, or a
00420   // reference to it, and that it is either an object pointer or trivially
00421   // copyable.
00422   if (!Ctx.hasSameUnqualifiedType(IVar->getType(),
00423                                   Prop->getType().getNonReferenceType()))
00424     return nullptr;
00425   if (!IVar->getType()->isObjCLifetimeType() &&
00426       !IVar->getType().isTriviallyCopyableType(Ctx))
00427     return nullptr;
00428 
00429   // Generate our body:
00430   //   return self->_ivar;
00431   ASTMaker M(Ctx);
00432 
00433   const VarDecl *selfVar = Prop->getGetterMethodDecl()->getSelfDecl();
00434 
00435   Expr *loadedIVar =
00436     M.makeObjCIvarRef(
00437       M.makeLvalueToRvalue(
00438         M.makeDeclRefExpr(selfVar),
00439         selfVar->getType()),
00440       IVar);
00441 
00442   if (!Prop->getType()->isReferenceType())
00443     loadedIVar = M.makeLvalueToRvalue(loadedIVar, IVar->getType());
00444 
00445   return M.makeReturn(loadedIVar);
00446 }
00447 
00448 Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
00449   // We currently only know how to synthesize property accessors.
00450   if (!D->isPropertyAccessor())
00451     return nullptr;
00452 
00453   D = D->getCanonicalDecl();
00454 
00455   Optional<Stmt *> &Val = Bodies[D];
00456   if (Val.hasValue())
00457     return Val.getValue();
00458   Val = nullptr;
00459 
00460   const ObjCPropertyDecl *Prop = D->findPropertyDecl();
00461   if (!Prop)
00462     return nullptr;
00463 
00464   // For now, we only synthesize getters.
00465   if (D->param_size() != 0)
00466     return nullptr;
00467 
00468   Val = createObjCPropertyGetter(C, Prop);
00469 
00470   return Val.getValue();
00471 }
00472