diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp | 164 |
1 files changed, 130 insertions, 34 deletions
diff --git a/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp b/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp index 4d5c2ee..316a18b 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp @@ -35,8 +35,7 @@ static bool isDispatchBlock(QualType Ty) { // returns void. const FunctionProtoType *FT = BPT->getPointeeType()->getAs<FunctionProtoType>(); - if (!FT || !FT->getResultType()->isVoidType() || - FT->getNumArgs() != 0) + if (!FT || !FT->getReturnType()->isVoidType() || FT->getNumParams() != 0) return false; return true; @@ -74,6 +73,9 @@ public: /// Create an Objective-C bool literal. ObjCBoolLiteralExpr *makeObjCBool(bool Val); + + /// Create an Objective-C ivar reference. + ObjCIvarRefExpr *makeObjCIvarRef(const Expr *Base, const ObjCIvarDecl *IVar); /// Create a Return statement. ReturnStmt *makeReturn(const Expr *RetVal); @@ -126,20 +128,20 @@ UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) { ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) { return ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue, - const_cast<Expr*>(Arg), 0, VK_RValue); + const_cast<Expr*>(Arg), nullptr, VK_RValue); } Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) { if (Arg->getType() == Ty) return const_cast<Expr*>(Arg); - + return ImplicitCastExpr::Create(C, Ty, CK_IntegralCast, - const_cast<Expr*>(Arg), 0, VK_RValue); + const_cast<Expr*>(Arg), nullptr, VK_RValue); } ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) { return ImplicitCastExpr::Create(C, C.BoolTy, CK_IntegralToBoolean, - const_cast<Expr*>(Arg), 0, VK_RValue); + const_cast<Expr*>(Arg), nullptr, VK_RValue); } ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) { @@ -147,8 +149,18 @@ ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) { return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation()); } +ObjCIvarRefExpr *ASTMaker::makeObjCIvarRef(const Expr *Base, + const ObjCIvarDecl *IVar) { + return new (C) ObjCIvarRefExpr(const_cast<ObjCIvarDecl*>(IVar), + IVar->getType(), SourceLocation(), + SourceLocation(), const_cast<Expr*>(Base), + /*arrow=*/true, /*free=*/false); +} + + ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) { - return new (C) ReturnStmt(SourceLocation(), const_cast<Expr*>(RetVal), 0); + return new (C) ReturnStmt(SourceLocation(), const_cast<Expr*>(RetVal), + nullptr); } //===----------------------------------------------------------------------===// @@ -161,24 +173,24 @@ typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D); static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { // Check if we have at least two parameters. if (D->param_size() != 2) - return 0; + return nullptr; // Check if the first parameter is a pointer to integer type. const ParmVarDecl *Predicate = D->getParamDecl(0); QualType PredicateQPtrTy = Predicate->getType(); const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>(); if (!PredicatePtrTy) - return 0; + return nullptr; QualType PredicateTy = PredicatePtrTy->getPointeeType(); if (!PredicateTy->isIntegerType()) - return 0; - + return nullptr; + // Check if the second parameter is the proper block type. const ParmVarDecl *Block = D->getParamDecl(1); QualType Ty = Block->getType(); if (!isDispatchBlock(Ty)) - return 0; - + return nullptr; + // Everything checks out. Create a fakse body that checks the predicate, // sets it, and calls the block. Basically, an AST dump of: // @@ -231,7 +243,7 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { SourceLocation()); // (5) Create the 'if' statement. - IfStmt *If = new (C) IfStmt(C, SourceLocation(), 0, UO, CS); + IfStmt *If = new (C) IfStmt(C, SourceLocation(), nullptr, UO, CS); return If; } @@ -239,14 +251,14 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) { // Check if we have at least two parameters. if (D->param_size() != 2) - return 0; - + return nullptr; + // Check if the second parameter is a block. const ParmVarDecl *PV = D->getParamDecl(1); QualType Ty = PV->getType(); if (!isDispatchBlock(Ty)) - return 0; - + return nullptr; + // Everything checks out. Create a fake body that just calls the block. // This is basically just an AST dump of: // @@ -266,8 +278,8 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D) { // There are exactly 3 arguments. if (D->param_size() != 3) - return 0; - + return nullptr; + // Signature: // _Bool OSAtomicCompareAndSwapPtr(void *__oldValue, // void *__newValue, @@ -278,12 +290,12 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D) // return YES; // } // else return NO; - - QualType ResultTy = D->getResultType(); + + QualType ResultTy = D->getReturnType(); bool isBoolean = ResultTy->isBooleanType(); if (!isBoolean && !ResultTy->isIntegralType(C)) - return 0; - + return nullptr; + const ParmVarDecl *OldValue = D->getParamDecl(0); QualType OldValueTy = OldValue->getType(); @@ -296,7 +308,7 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D) QualType TheValueTy = TheValue->getType(); const PointerType *PT = TheValueTy->getAs<PointerType>(); if (!PT) - return 0; + return nullptr; QualType PointeeTy = PT->getPointeeType(); ASTMaker M(C); @@ -335,9 +347,9 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D) /// Construct the If. Stmt *If = - new (C) IfStmt(C, SourceLocation(), 0, Comparison, Body, + new (C) IfStmt(C, SourceLocation(), nullptr, Comparison, Body, SourceLocation(), Else); - + return If; } @@ -347,15 +359,15 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) { Optional<Stmt *> &Val = Bodies[D]; if (Val.hasValue()) return Val.getValue(); - - Val = 0; - - if (D->getIdentifier() == 0) - return 0; + + Val = nullptr; + + if (D->getIdentifier() == nullptr) + return nullptr; StringRef Name = D->getName(); if (Name.empty()) - return 0; + return nullptr; FunctionFarmer FF; @@ -367,10 +379,94 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) { FF = llvm::StringSwitch<FunctionFarmer>(Name) .Case("dispatch_sync", create_dispatch_sync) .Case("dispatch_once", create_dispatch_once) - .Default(NULL); + .Default(nullptr); } if (FF) { Val = FF(C, D); } return Val.getValue(); } +static Stmt *createObjCPropertyGetter(ASTContext &Ctx, + const ObjCPropertyDecl *Prop) { + // First, find the backing ivar. + const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl(); + if (!IVar) + return nullptr; + + // Ignore weak variables, which have special behavior. + if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak) + return nullptr; + + // Look to see if Sema has synthesized a body for us. This happens in + // Objective-C++ because the return value may be a C++ class type with a + // non-trivial copy constructor. We can only do this if we can find the + // @synthesize for this property, though (or if we know it's been auto- + // synthesized). + const ObjCImplementationDecl *ImplDecl = + IVar->getContainingInterface()->getImplementation(); + if (ImplDecl) { + for (const auto *I : ImplDecl->property_impls()) { + if (I->getPropertyDecl() != Prop) + continue; + + if (I->getGetterCXXConstructor()) { + ASTMaker M(Ctx); + return M.makeReturn(I->getGetterCXXConstructor()); + } + } + } + + // Sanity check that the property is the same type as the ivar, or a + // reference to it, and that it is either an object pointer or trivially + // copyable. + if (!Ctx.hasSameUnqualifiedType(IVar->getType(), + Prop->getType().getNonReferenceType())) + return nullptr; + if (!IVar->getType()->isObjCLifetimeType() && + !IVar->getType().isTriviallyCopyableType(Ctx)) + return nullptr; + + // Generate our body: + // return self->_ivar; + ASTMaker M(Ctx); + + const VarDecl *selfVar = Prop->getGetterMethodDecl()->getSelfDecl(); + + Expr *loadedIVar = + M.makeObjCIvarRef( + M.makeLvalueToRvalue( + M.makeDeclRefExpr(selfVar), + selfVar->getType()), + IVar); + + if (!Prop->getType()->isReferenceType()) + loadedIVar = M.makeLvalueToRvalue(loadedIVar, IVar->getType()); + + return M.makeReturn(loadedIVar); +} + +Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) { + // We currently only know how to synthesize property accessors. + if (!D->isPropertyAccessor()) + return nullptr; + + D = D->getCanonicalDecl(); + + Optional<Stmt *> &Val = Bodies[D]; + if (Val.hasValue()) + return Val.getValue(); + Val = nullptr; + + const ObjCPropertyDecl *Prop = D->findPropertyDecl(); + if (!Prop) + return nullptr; + + // For now, we only synthesize getters. + if (D->param_size() != 0) + return nullptr; + + Val = createObjCPropertyGetter(C, Prop); + + return Val.getValue(); +} + |