1f4a2713aSLionel Sambuc //== BodyFarm.cpp - Factory for conjuring up fake bodies ----------*- C++ -*-//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc // The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // BodyFarm is a factory for creating faux implementations for functions/methods
11f4a2713aSLionel Sambuc // for analysis purposes.
12f4a2713aSLionel Sambuc //
13f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
14f4a2713aSLionel Sambuc
15f4a2713aSLionel Sambuc #include "BodyFarm.h"
16f4a2713aSLionel Sambuc #include "clang/AST/ASTContext.h"
17f4a2713aSLionel Sambuc #include "clang/AST/Decl.h"
18f4a2713aSLionel Sambuc #include "clang/AST/Expr.h"
19f4a2713aSLionel Sambuc #include "clang/AST/ExprObjC.h"
20*0a6a1f1dSLionel Sambuc #include "clang/Analysis/CodeInjector.h"
21f4a2713aSLionel Sambuc #include "llvm/ADT/StringSwitch.h"
22f4a2713aSLionel Sambuc
23f4a2713aSLionel Sambuc using namespace clang;
24f4a2713aSLionel Sambuc
25f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
26f4a2713aSLionel Sambuc // Helper creation functions for constructing faux ASTs.
27f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
28f4a2713aSLionel Sambuc
isDispatchBlock(QualType Ty)29f4a2713aSLionel Sambuc static bool isDispatchBlock(QualType Ty) {
30f4a2713aSLionel Sambuc // Is it a block pointer?
31f4a2713aSLionel Sambuc const BlockPointerType *BPT = Ty->getAs<BlockPointerType>();
32f4a2713aSLionel Sambuc if (!BPT)
33f4a2713aSLionel Sambuc return false;
34f4a2713aSLionel Sambuc
35f4a2713aSLionel Sambuc // Check if the block pointer type takes no arguments and
36f4a2713aSLionel Sambuc // returns void.
37f4a2713aSLionel Sambuc const FunctionProtoType *FT =
38f4a2713aSLionel Sambuc BPT->getPointeeType()->getAs<FunctionProtoType>();
39*0a6a1f1dSLionel Sambuc if (!FT || !FT->getReturnType()->isVoidType() || FT->getNumParams() != 0)
40f4a2713aSLionel Sambuc return false;
41f4a2713aSLionel Sambuc
42f4a2713aSLionel Sambuc return true;
43f4a2713aSLionel Sambuc }
44f4a2713aSLionel Sambuc
45f4a2713aSLionel Sambuc namespace {
46f4a2713aSLionel Sambuc class ASTMaker {
47f4a2713aSLionel Sambuc public:
ASTMaker(ASTContext & C)48f4a2713aSLionel Sambuc ASTMaker(ASTContext &C) : C(C) {}
49f4a2713aSLionel Sambuc
50f4a2713aSLionel Sambuc /// Create a new BinaryOperator representing a simple assignment.
51f4a2713aSLionel Sambuc BinaryOperator *makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty);
52f4a2713aSLionel Sambuc
53f4a2713aSLionel Sambuc /// Create a new BinaryOperator representing a comparison.
54f4a2713aSLionel Sambuc BinaryOperator *makeComparison(const Expr *LHS, const Expr *RHS,
55f4a2713aSLionel Sambuc BinaryOperator::Opcode Op);
56f4a2713aSLionel Sambuc
57f4a2713aSLionel Sambuc /// Create a new compound stmt using the provided statements.
58f4a2713aSLionel Sambuc CompoundStmt *makeCompound(ArrayRef<Stmt*>);
59f4a2713aSLionel Sambuc
60f4a2713aSLionel Sambuc /// Create a new DeclRefExpr for the referenced variable.
61f4a2713aSLionel Sambuc DeclRefExpr *makeDeclRefExpr(const VarDecl *D);
62f4a2713aSLionel Sambuc
63f4a2713aSLionel Sambuc /// Create a new UnaryOperator representing a dereference.
64f4a2713aSLionel Sambuc UnaryOperator *makeDereference(const Expr *Arg, QualType Ty);
65f4a2713aSLionel Sambuc
66f4a2713aSLionel Sambuc /// Create an implicit cast for an integer conversion.
67f4a2713aSLionel Sambuc Expr *makeIntegralCast(const Expr *Arg, QualType Ty);
68f4a2713aSLionel Sambuc
69f4a2713aSLionel Sambuc /// Create an implicit cast to a builtin boolean type.
70f4a2713aSLionel Sambuc ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg);
71f4a2713aSLionel Sambuc
72f4a2713aSLionel Sambuc // Create an implicit cast for lvalue-to-rvaluate conversions.
73f4a2713aSLionel Sambuc ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty);
74f4a2713aSLionel Sambuc
75f4a2713aSLionel Sambuc /// Create an Objective-C bool literal.
76f4a2713aSLionel Sambuc ObjCBoolLiteralExpr *makeObjCBool(bool Val);
77f4a2713aSLionel Sambuc
78*0a6a1f1dSLionel Sambuc /// Create an Objective-C ivar reference.
79*0a6a1f1dSLionel Sambuc ObjCIvarRefExpr *makeObjCIvarRef(const Expr *Base, const ObjCIvarDecl *IVar);
80*0a6a1f1dSLionel Sambuc
81f4a2713aSLionel Sambuc /// Create a Return statement.
82f4a2713aSLionel Sambuc ReturnStmt *makeReturn(const Expr *RetVal);
83f4a2713aSLionel Sambuc
84f4a2713aSLionel Sambuc private:
85f4a2713aSLionel Sambuc ASTContext &C;
86f4a2713aSLionel Sambuc };
87f4a2713aSLionel Sambuc }
88f4a2713aSLionel Sambuc
makeAssignment(const Expr * LHS,const Expr * RHS,QualType Ty)89f4a2713aSLionel Sambuc BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS,
90f4a2713aSLionel Sambuc QualType Ty) {
91f4a2713aSLionel Sambuc return new (C) BinaryOperator(const_cast<Expr*>(LHS), const_cast<Expr*>(RHS),
92f4a2713aSLionel Sambuc BO_Assign, Ty, VK_RValue,
93f4a2713aSLionel Sambuc OK_Ordinary, SourceLocation(), false);
94f4a2713aSLionel Sambuc }
95f4a2713aSLionel Sambuc
makeComparison(const Expr * LHS,const Expr * RHS,BinaryOperator::Opcode Op)96f4a2713aSLionel Sambuc BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,
97f4a2713aSLionel Sambuc BinaryOperator::Opcode Op) {
98f4a2713aSLionel Sambuc assert(BinaryOperator::isLogicalOp(Op) ||
99f4a2713aSLionel Sambuc BinaryOperator::isComparisonOp(Op));
100f4a2713aSLionel Sambuc return new (C) BinaryOperator(const_cast<Expr*>(LHS),
101f4a2713aSLionel Sambuc const_cast<Expr*>(RHS),
102f4a2713aSLionel Sambuc Op,
103f4a2713aSLionel Sambuc C.getLogicalOperationType(),
104f4a2713aSLionel Sambuc VK_RValue,
105f4a2713aSLionel Sambuc OK_Ordinary, SourceLocation(), false);
106f4a2713aSLionel Sambuc }
107f4a2713aSLionel Sambuc
makeCompound(ArrayRef<Stmt * > Stmts)108f4a2713aSLionel Sambuc CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {
109f4a2713aSLionel Sambuc return new (C) CompoundStmt(C, Stmts, SourceLocation(), SourceLocation());
110f4a2713aSLionel Sambuc }
111f4a2713aSLionel Sambuc
makeDeclRefExpr(const VarDecl * D)112f4a2713aSLionel Sambuc DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) {
113f4a2713aSLionel Sambuc DeclRefExpr *DR =
114f4a2713aSLionel Sambuc DeclRefExpr::Create(/* Ctx = */ C,
115f4a2713aSLionel Sambuc /* QualifierLoc = */ NestedNameSpecifierLoc(),
116f4a2713aSLionel Sambuc /* TemplateKWLoc = */ SourceLocation(),
117f4a2713aSLionel Sambuc /* D = */ const_cast<VarDecl*>(D),
118*0a6a1f1dSLionel Sambuc /* RefersToEnclosingVariableOrCapture = */ false,
119f4a2713aSLionel Sambuc /* NameLoc = */ SourceLocation(),
120f4a2713aSLionel Sambuc /* T = */ D->getType(),
121f4a2713aSLionel Sambuc /* VK = */ VK_LValue);
122f4a2713aSLionel Sambuc return DR;
123f4a2713aSLionel Sambuc }
124f4a2713aSLionel Sambuc
makeDereference(const Expr * Arg,QualType Ty)125f4a2713aSLionel Sambuc UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {
126f4a2713aSLionel Sambuc return new (C) UnaryOperator(const_cast<Expr*>(Arg), UO_Deref, Ty,
127f4a2713aSLionel Sambuc VK_LValue, OK_Ordinary, SourceLocation());
128f4a2713aSLionel Sambuc }
129f4a2713aSLionel Sambuc
makeLvalueToRvalue(const Expr * Arg,QualType Ty)130f4a2713aSLionel Sambuc ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
131f4a2713aSLionel Sambuc return ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
132*0a6a1f1dSLionel Sambuc const_cast<Expr*>(Arg), nullptr, VK_RValue);
133f4a2713aSLionel Sambuc }
134f4a2713aSLionel Sambuc
makeIntegralCast(const Expr * Arg,QualType Ty)135f4a2713aSLionel Sambuc Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
136f4a2713aSLionel Sambuc if (Arg->getType() == Ty)
137f4a2713aSLionel Sambuc return const_cast<Expr*>(Arg);
138f4a2713aSLionel Sambuc
139f4a2713aSLionel Sambuc return ImplicitCastExpr::Create(C, Ty, CK_IntegralCast,
140*0a6a1f1dSLionel Sambuc const_cast<Expr*>(Arg), nullptr, VK_RValue);
141f4a2713aSLionel Sambuc }
142f4a2713aSLionel Sambuc
makeIntegralCastToBoolean(const Expr * Arg)143f4a2713aSLionel Sambuc ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) {
144f4a2713aSLionel Sambuc return ImplicitCastExpr::Create(C, C.BoolTy, CK_IntegralToBoolean,
145*0a6a1f1dSLionel Sambuc const_cast<Expr*>(Arg), nullptr, VK_RValue);
146f4a2713aSLionel Sambuc }
147f4a2713aSLionel Sambuc
makeObjCBool(bool Val)148f4a2713aSLionel Sambuc ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) {
149f4a2713aSLionel Sambuc QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy;
150f4a2713aSLionel Sambuc return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation());
151f4a2713aSLionel Sambuc }
152f4a2713aSLionel Sambuc
makeObjCIvarRef(const Expr * Base,const ObjCIvarDecl * IVar)153*0a6a1f1dSLionel Sambuc ObjCIvarRefExpr *ASTMaker::makeObjCIvarRef(const Expr *Base,
154*0a6a1f1dSLionel Sambuc const ObjCIvarDecl *IVar) {
155*0a6a1f1dSLionel Sambuc return new (C) ObjCIvarRefExpr(const_cast<ObjCIvarDecl*>(IVar),
156*0a6a1f1dSLionel Sambuc IVar->getType(), SourceLocation(),
157*0a6a1f1dSLionel Sambuc SourceLocation(), const_cast<Expr*>(Base),
158*0a6a1f1dSLionel Sambuc /*arrow=*/true, /*free=*/false);
159*0a6a1f1dSLionel Sambuc }
160*0a6a1f1dSLionel Sambuc
161*0a6a1f1dSLionel Sambuc
makeReturn(const Expr * RetVal)162f4a2713aSLionel Sambuc ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) {
163*0a6a1f1dSLionel Sambuc return new (C) ReturnStmt(SourceLocation(), const_cast<Expr*>(RetVal),
164*0a6a1f1dSLionel Sambuc nullptr);
165f4a2713aSLionel Sambuc }
166f4a2713aSLionel Sambuc
167f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
168f4a2713aSLionel Sambuc // Creation functions for faux ASTs.
169f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
170f4a2713aSLionel Sambuc
171f4a2713aSLionel Sambuc typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
172f4a2713aSLionel Sambuc
173f4a2713aSLionel Sambuc /// Create a fake body for dispatch_once.
create_dispatch_once(ASTContext & C,const FunctionDecl * D)174f4a2713aSLionel Sambuc static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
175f4a2713aSLionel Sambuc // Check if we have at least two parameters.
176f4a2713aSLionel Sambuc if (D->param_size() != 2)
177*0a6a1f1dSLionel Sambuc return nullptr;
178f4a2713aSLionel Sambuc
179f4a2713aSLionel Sambuc // Check if the first parameter is a pointer to integer type.
180f4a2713aSLionel Sambuc const ParmVarDecl *Predicate = D->getParamDecl(0);
181f4a2713aSLionel Sambuc QualType PredicateQPtrTy = Predicate->getType();
182f4a2713aSLionel Sambuc const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();
183f4a2713aSLionel Sambuc if (!PredicatePtrTy)
184*0a6a1f1dSLionel Sambuc return nullptr;
185f4a2713aSLionel Sambuc QualType PredicateTy = PredicatePtrTy->getPointeeType();
186f4a2713aSLionel Sambuc if (!PredicateTy->isIntegerType())
187*0a6a1f1dSLionel Sambuc return nullptr;
188f4a2713aSLionel Sambuc
189f4a2713aSLionel Sambuc // Check if the second parameter is the proper block type.
190f4a2713aSLionel Sambuc const ParmVarDecl *Block = D->getParamDecl(1);
191f4a2713aSLionel Sambuc QualType Ty = Block->getType();
192f4a2713aSLionel Sambuc if (!isDispatchBlock(Ty))
193*0a6a1f1dSLionel Sambuc return nullptr;
194f4a2713aSLionel Sambuc
195f4a2713aSLionel Sambuc // Everything checks out. Create a fakse body that checks the predicate,
196f4a2713aSLionel Sambuc // sets it, and calls the block. Basically, an AST dump of:
197f4a2713aSLionel Sambuc //
198f4a2713aSLionel Sambuc // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
199f4a2713aSLionel Sambuc // if (!*predicate) {
200f4a2713aSLionel Sambuc // *predicate = 1;
201f4a2713aSLionel Sambuc // block();
202f4a2713aSLionel Sambuc // }
203f4a2713aSLionel Sambuc // }
204f4a2713aSLionel Sambuc
205f4a2713aSLionel Sambuc ASTMaker M(C);
206f4a2713aSLionel Sambuc
207f4a2713aSLionel Sambuc // (1) Create the call.
208f4a2713aSLionel Sambuc DeclRefExpr *DR = M.makeDeclRefExpr(Block);
209f4a2713aSLionel Sambuc ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
210f4a2713aSLionel Sambuc CallExpr *CE = new (C) CallExpr(C, ICE, None, C.VoidTy, VK_RValue,
211f4a2713aSLionel Sambuc SourceLocation());
212f4a2713aSLionel Sambuc
213f4a2713aSLionel Sambuc // (2) Create the assignment to the predicate.
214f4a2713aSLionel Sambuc IntegerLiteral *IL =
215f4a2713aSLionel Sambuc IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), (uint64_t) 1),
216f4a2713aSLionel Sambuc C.IntTy, SourceLocation());
217f4a2713aSLionel Sambuc BinaryOperator *B =
218f4a2713aSLionel Sambuc M.makeAssignment(
219f4a2713aSLionel Sambuc M.makeDereference(
220f4a2713aSLionel Sambuc M.makeLvalueToRvalue(
221f4a2713aSLionel Sambuc M.makeDeclRefExpr(Predicate), PredicateQPtrTy),
222f4a2713aSLionel Sambuc PredicateTy),
223f4a2713aSLionel Sambuc M.makeIntegralCast(IL, PredicateTy),
224f4a2713aSLionel Sambuc PredicateTy);
225f4a2713aSLionel Sambuc
226f4a2713aSLionel Sambuc // (3) Create the compound statement.
227*0a6a1f1dSLionel Sambuc Stmt *Stmts[] = { B, CE };
228*0a6a1f1dSLionel Sambuc CompoundStmt *CS = M.makeCompound(Stmts);
229f4a2713aSLionel Sambuc
230f4a2713aSLionel Sambuc // (4) Create the 'if' condition.
231f4a2713aSLionel Sambuc ImplicitCastExpr *LValToRval =
232f4a2713aSLionel Sambuc M.makeLvalueToRvalue(
233f4a2713aSLionel Sambuc M.makeDereference(
234f4a2713aSLionel Sambuc M.makeLvalueToRvalue(
235f4a2713aSLionel Sambuc M.makeDeclRefExpr(Predicate),
236f4a2713aSLionel Sambuc PredicateQPtrTy),
237f4a2713aSLionel Sambuc PredicateTy),
238f4a2713aSLionel Sambuc PredicateTy);
239f4a2713aSLionel Sambuc
240f4a2713aSLionel Sambuc UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy,
241f4a2713aSLionel Sambuc VK_RValue, OK_Ordinary,
242f4a2713aSLionel Sambuc SourceLocation());
243f4a2713aSLionel Sambuc
244f4a2713aSLionel Sambuc // (5) Create the 'if' statement.
245*0a6a1f1dSLionel Sambuc IfStmt *If = new (C) IfStmt(C, SourceLocation(), nullptr, UO, CS);
246f4a2713aSLionel Sambuc return If;
247f4a2713aSLionel Sambuc }
248f4a2713aSLionel Sambuc
249f4a2713aSLionel Sambuc /// Create a fake body for dispatch_sync.
create_dispatch_sync(ASTContext & C,const FunctionDecl * D)250f4a2713aSLionel Sambuc static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
251f4a2713aSLionel Sambuc // Check if we have at least two parameters.
252f4a2713aSLionel Sambuc if (D->param_size() != 2)
253*0a6a1f1dSLionel Sambuc return nullptr;
254f4a2713aSLionel Sambuc
255f4a2713aSLionel Sambuc // Check if the second parameter is a block.
256f4a2713aSLionel Sambuc const ParmVarDecl *PV = D->getParamDecl(1);
257f4a2713aSLionel Sambuc QualType Ty = PV->getType();
258f4a2713aSLionel Sambuc if (!isDispatchBlock(Ty))
259*0a6a1f1dSLionel Sambuc return nullptr;
260f4a2713aSLionel Sambuc
261f4a2713aSLionel Sambuc // Everything checks out. Create a fake body that just calls the block.
262f4a2713aSLionel Sambuc // This is basically just an AST dump of:
263f4a2713aSLionel Sambuc //
264f4a2713aSLionel Sambuc // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) {
265f4a2713aSLionel Sambuc // block();
266f4a2713aSLionel Sambuc // }
267f4a2713aSLionel Sambuc //
268f4a2713aSLionel Sambuc ASTMaker M(C);
269f4a2713aSLionel Sambuc DeclRefExpr *DR = M.makeDeclRefExpr(PV);
270f4a2713aSLionel Sambuc ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
271f4a2713aSLionel Sambuc CallExpr *CE = new (C) CallExpr(C, ICE, None, C.VoidTy, VK_RValue,
272f4a2713aSLionel Sambuc SourceLocation());
273f4a2713aSLionel Sambuc return CE;
274f4a2713aSLionel Sambuc }
275f4a2713aSLionel Sambuc
create_OSAtomicCompareAndSwap(ASTContext & C,const FunctionDecl * D)276f4a2713aSLionel Sambuc static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
277f4a2713aSLionel Sambuc {
278f4a2713aSLionel Sambuc // There are exactly 3 arguments.
279f4a2713aSLionel Sambuc if (D->param_size() != 3)
280*0a6a1f1dSLionel Sambuc return nullptr;
281f4a2713aSLionel Sambuc
282f4a2713aSLionel Sambuc // Signature:
283f4a2713aSLionel Sambuc // _Bool OSAtomicCompareAndSwapPtr(void *__oldValue,
284f4a2713aSLionel Sambuc // void *__newValue,
285f4a2713aSLionel Sambuc // void * volatile *__theValue)
286f4a2713aSLionel Sambuc // Generate body:
287f4a2713aSLionel Sambuc // if (oldValue == *theValue) {
288f4a2713aSLionel Sambuc // *theValue = newValue;
289f4a2713aSLionel Sambuc // return YES;
290f4a2713aSLionel Sambuc // }
291f4a2713aSLionel Sambuc // else return NO;
292f4a2713aSLionel Sambuc
293*0a6a1f1dSLionel Sambuc QualType ResultTy = D->getReturnType();
294f4a2713aSLionel Sambuc bool isBoolean = ResultTy->isBooleanType();
295f4a2713aSLionel Sambuc if (!isBoolean && !ResultTy->isIntegralType(C))
296*0a6a1f1dSLionel Sambuc return nullptr;
297f4a2713aSLionel Sambuc
298f4a2713aSLionel Sambuc const ParmVarDecl *OldValue = D->getParamDecl(0);
299f4a2713aSLionel Sambuc QualType OldValueTy = OldValue->getType();
300f4a2713aSLionel Sambuc
301f4a2713aSLionel Sambuc const ParmVarDecl *NewValue = D->getParamDecl(1);
302f4a2713aSLionel Sambuc QualType NewValueTy = NewValue->getType();
303f4a2713aSLionel Sambuc
304f4a2713aSLionel Sambuc assert(OldValueTy == NewValueTy);
305f4a2713aSLionel Sambuc
306f4a2713aSLionel Sambuc const ParmVarDecl *TheValue = D->getParamDecl(2);
307f4a2713aSLionel Sambuc QualType TheValueTy = TheValue->getType();
308f4a2713aSLionel Sambuc const PointerType *PT = TheValueTy->getAs<PointerType>();
309f4a2713aSLionel Sambuc if (!PT)
310*0a6a1f1dSLionel Sambuc return nullptr;
311f4a2713aSLionel Sambuc QualType PointeeTy = PT->getPointeeType();
312f4a2713aSLionel Sambuc
313f4a2713aSLionel Sambuc ASTMaker M(C);
314f4a2713aSLionel Sambuc // Construct the comparison.
315f4a2713aSLionel Sambuc Expr *Comparison =
316f4a2713aSLionel Sambuc M.makeComparison(
317f4a2713aSLionel Sambuc M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy),
318f4a2713aSLionel Sambuc M.makeLvalueToRvalue(
319f4a2713aSLionel Sambuc M.makeDereference(
320f4a2713aSLionel Sambuc M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
321f4a2713aSLionel Sambuc PointeeTy),
322f4a2713aSLionel Sambuc PointeeTy),
323f4a2713aSLionel Sambuc BO_EQ);
324f4a2713aSLionel Sambuc
325f4a2713aSLionel Sambuc // Construct the body of the IfStmt.
326f4a2713aSLionel Sambuc Stmt *Stmts[2];
327f4a2713aSLionel Sambuc Stmts[0] =
328f4a2713aSLionel Sambuc M.makeAssignment(
329f4a2713aSLionel Sambuc M.makeDereference(
330f4a2713aSLionel Sambuc M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
331f4a2713aSLionel Sambuc PointeeTy),
332f4a2713aSLionel Sambuc M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy),
333f4a2713aSLionel Sambuc NewValueTy);
334f4a2713aSLionel Sambuc
335f4a2713aSLionel Sambuc Expr *BoolVal = M.makeObjCBool(true);
336f4a2713aSLionel Sambuc Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
337f4a2713aSLionel Sambuc : M.makeIntegralCast(BoolVal, ResultTy);
338f4a2713aSLionel Sambuc Stmts[1] = M.makeReturn(RetVal);
339*0a6a1f1dSLionel Sambuc CompoundStmt *Body = M.makeCompound(Stmts);
340f4a2713aSLionel Sambuc
341f4a2713aSLionel Sambuc // Construct the else clause.
342f4a2713aSLionel Sambuc BoolVal = M.makeObjCBool(false);
343f4a2713aSLionel Sambuc RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
344f4a2713aSLionel Sambuc : M.makeIntegralCast(BoolVal, ResultTy);
345f4a2713aSLionel Sambuc Stmt *Else = M.makeReturn(RetVal);
346f4a2713aSLionel Sambuc
347f4a2713aSLionel Sambuc /// Construct the If.
348f4a2713aSLionel Sambuc Stmt *If =
349*0a6a1f1dSLionel Sambuc new (C) IfStmt(C, SourceLocation(), nullptr, Comparison, Body,
350f4a2713aSLionel Sambuc SourceLocation(), Else);
351f4a2713aSLionel Sambuc
352f4a2713aSLionel Sambuc return If;
353f4a2713aSLionel Sambuc }
354f4a2713aSLionel Sambuc
getBody(const FunctionDecl * D)355f4a2713aSLionel Sambuc Stmt *BodyFarm::getBody(const FunctionDecl *D) {
356f4a2713aSLionel Sambuc D = D->getCanonicalDecl();
357f4a2713aSLionel Sambuc
358f4a2713aSLionel Sambuc Optional<Stmt *> &Val = Bodies[D];
359f4a2713aSLionel Sambuc if (Val.hasValue())
360f4a2713aSLionel Sambuc return Val.getValue();
361f4a2713aSLionel Sambuc
362*0a6a1f1dSLionel Sambuc Val = nullptr;
363f4a2713aSLionel Sambuc
364*0a6a1f1dSLionel Sambuc if (D->getIdentifier() == nullptr)
365*0a6a1f1dSLionel Sambuc return nullptr;
366f4a2713aSLionel Sambuc
367f4a2713aSLionel Sambuc StringRef Name = D->getName();
368f4a2713aSLionel Sambuc if (Name.empty())
369*0a6a1f1dSLionel Sambuc return nullptr;
370f4a2713aSLionel Sambuc
371f4a2713aSLionel Sambuc FunctionFarmer FF;
372f4a2713aSLionel Sambuc
373f4a2713aSLionel Sambuc if (Name.startswith("OSAtomicCompareAndSwap") ||
374f4a2713aSLionel Sambuc Name.startswith("objc_atomicCompareAndSwap")) {
375f4a2713aSLionel Sambuc FF = create_OSAtomicCompareAndSwap;
376f4a2713aSLionel Sambuc }
377f4a2713aSLionel Sambuc else {
378f4a2713aSLionel Sambuc FF = llvm::StringSwitch<FunctionFarmer>(Name)
379f4a2713aSLionel Sambuc .Case("dispatch_sync", create_dispatch_sync)
380f4a2713aSLionel Sambuc .Case("dispatch_once", create_dispatch_once)
381*0a6a1f1dSLionel Sambuc .Default(nullptr);
382f4a2713aSLionel Sambuc }
383f4a2713aSLionel Sambuc
384f4a2713aSLionel Sambuc if (FF) { Val = FF(C, D); }
385*0a6a1f1dSLionel Sambuc else if (Injector) { Val = Injector->getBody(D); }
386*0a6a1f1dSLionel Sambuc return Val.getValue();
387*0a6a1f1dSLionel Sambuc }
388*0a6a1f1dSLionel Sambuc
createObjCPropertyGetter(ASTContext & Ctx,const ObjCPropertyDecl * Prop)389*0a6a1f1dSLionel Sambuc static Stmt *createObjCPropertyGetter(ASTContext &Ctx,
390*0a6a1f1dSLionel Sambuc const ObjCPropertyDecl *Prop) {
391*0a6a1f1dSLionel Sambuc // First, find the backing ivar.
392*0a6a1f1dSLionel Sambuc const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl();
393*0a6a1f1dSLionel Sambuc if (!IVar)
394*0a6a1f1dSLionel Sambuc return nullptr;
395*0a6a1f1dSLionel Sambuc
396*0a6a1f1dSLionel Sambuc // Ignore weak variables, which have special behavior.
397*0a6a1f1dSLionel Sambuc if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)
398*0a6a1f1dSLionel Sambuc return nullptr;
399*0a6a1f1dSLionel Sambuc
400*0a6a1f1dSLionel Sambuc // Look to see if Sema has synthesized a body for us. This happens in
401*0a6a1f1dSLionel Sambuc // Objective-C++ because the return value may be a C++ class type with a
402*0a6a1f1dSLionel Sambuc // non-trivial copy constructor. We can only do this if we can find the
403*0a6a1f1dSLionel Sambuc // @synthesize for this property, though (or if we know it's been auto-
404*0a6a1f1dSLionel Sambuc // synthesized).
405*0a6a1f1dSLionel Sambuc const ObjCImplementationDecl *ImplDecl =
406*0a6a1f1dSLionel Sambuc IVar->getContainingInterface()->getImplementation();
407*0a6a1f1dSLionel Sambuc if (ImplDecl) {
408*0a6a1f1dSLionel Sambuc for (const auto *I : ImplDecl->property_impls()) {
409*0a6a1f1dSLionel Sambuc if (I->getPropertyDecl() != Prop)
410*0a6a1f1dSLionel Sambuc continue;
411*0a6a1f1dSLionel Sambuc
412*0a6a1f1dSLionel Sambuc if (I->getGetterCXXConstructor()) {
413*0a6a1f1dSLionel Sambuc ASTMaker M(Ctx);
414*0a6a1f1dSLionel Sambuc return M.makeReturn(I->getGetterCXXConstructor());
415*0a6a1f1dSLionel Sambuc }
416*0a6a1f1dSLionel Sambuc }
417*0a6a1f1dSLionel Sambuc }
418*0a6a1f1dSLionel Sambuc
419*0a6a1f1dSLionel Sambuc // Sanity check that the property is the same type as the ivar, or a
420*0a6a1f1dSLionel Sambuc // reference to it, and that it is either an object pointer or trivially
421*0a6a1f1dSLionel Sambuc // copyable.
422*0a6a1f1dSLionel Sambuc if (!Ctx.hasSameUnqualifiedType(IVar->getType(),
423*0a6a1f1dSLionel Sambuc Prop->getType().getNonReferenceType()))
424*0a6a1f1dSLionel Sambuc return nullptr;
425*0a6a1f1dSLionel Sambuc if (!IVar->getType()->isObjCLifetimeType() &&
426*0a6a1f1dSLionel Sambuc !IVar->getType().isTriviallyCopyableType(Ctx))
427*0a6a1f1dSLionel Sambuc return nullptr;
428*0a6a1f1dSLionel Sambuc
429*0a6a1f1dSLionel Sambuc // Generate our body:
430*0a6a1f1dSLionel Sambuc // return self->_ivar;
431*0a6a1f1dSLionel Sambuc ASTMaker M(Ctx);
432*0a6a1f1dSLionel Sambuc
433*0a6a1f1dSLionel Sambuc const VarDecl *selfVar = Prop->getGetterMethodDecl()->getSelfDecl();
434*0a6a1f1dSLionel Sambuc
435*0a6a1f1dSLionel Sambuc Expr *loadedIVar =
436*0a6a1f1dSLionel Sambuc M.makeObjCIvarRef(
437*0a6a1f1dSLionel Sambuc M.makeLvalueToRvalue(
438*0a6a1f1dSLionel Sambuc M.makeDeclRefExpr(selfVar),
439*0a6a1f1dSLionel Sambuc selfVar->getType()),
440*0a6a1f1dSLionel Sambuc IVar);
441*0a6a1f1dSLionel Sambuc
442*0a6a1f1dSLionel Sambuc if (!Prop->getType()->isReferenceType())
443*0a6a1f1dSLionel Sambuc loadedIVar = M.makeLvalueToRvalue(loadedIVar, IVar->getType());
444*0a6a1f1dSLionel Sambuc
445*0a6a1f1dSLionel Sambuc return M.makeReturn(loadedIVar);
446*0a6a1f1dSLionel Sambuc }
447*0a6a1f1dSLionel Sambuc
getBody(const ObjCMethodDecl * D)448*0a6a1f1dSLionel Sambuc Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
449*0a6a1f1dSLionel Sambuc // We currently only know how to synthesize property accessors.
450*0a6a1f1dSLionel Sambuc if (!D->isPropertyAccessor())
451*0a6a1f1dSLionel Sambuc return nullptr;
452*0a6a1f1dSLionel Sambuc
453*0a6a1f1dSLionel Sambuc D = D->getCanonicalDecl();
454*0a6a1f1dSLionel Sambuc
455*0a6a1f1dSLionel Sambuc Optional<Stmt *> &Val = Bodies[D];
456*0a6a1f1dSLionel Sambuc if (Val.hasValue())
457*0a6a1f1dSLionel Sambuc return Val.getValue();
458*0a6a1f1dSLionel Sambuc Val = nullptr;
459*0a6a1f1dSLionel Sambuc
460*0a6a1f1dSLionel Sambuc const ObjCPropertyDecl *Prop = D->findPropertyDecl();
461*0a6a1f1dSLionel Sambuc if (!Prop)
462*0a6a1f1dSLionel Sambuc return nullptr;
463*0a6a1f1dSLionel Sambuc
464*0a6a1f1dSLionel Sambuc // For now, we only synthesize getters.
465*0a6a1f1dSLionel Sambuc if (D->param_size() != 0)
466*0a6a1f1dSLionel Sambuc return nullptr;
467*0a6a1f1dSLionel Sambuc
468*0a6a1f1dSLionel Sambuc Val = createObjCPropertyGetter(C, Prop);
469*0a6a1f1dSLionel Sambuc
470f4a2713aSLionel Sambuc return Val.getValue();
471f4a2713aSLionel Sambuc }
472f4a2713aSLionel Sambuc
473