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