BodyFarm.cpp revision 0b5c5e487bbbdeb2a7688e6c753d3b2a7c337604
1//== BodyFarm.cpp  - Factory for conjuring up fake bodies ----------*- C++ -*-//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// BodyFarm is a factory for creating faux implementations for functions/methods
11// for analysis purposes.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/ADT/StringSwitch.h"
16#include "clang/AST/ASTContext.h"
17#include "clang/AST/Expr.h"
18#include "clang/AST/Decl.h"
19#include "BodyFarm.h"
20
21using namespace clang;
22
23//===----------------------------------------------------------------------===//
24// Helper creation functions for constructing faux ASTs.
25//===----------------------------------------------------------------------===//
26
27static bool isDispatchBlock(QualType Ty) {
28  // Is it a block pointer?
29  const BlockPointerType *BPT = Ty->getAs<BlockPointerType>();
30  if (!BPT)
31    return false;
32
33  // Check if the block pointer type takes no arguments and
34  // returns void.
35  const FunctionProtoType *FT =
36  BPT->getPointeeType()->getAs<FunctionProtoType>();
37  if (!FT || !FT->getResultType()->isVoidType()  ||
38      FT->getNumArgs() != 0)
39    return false;
40
41  return true;
42}
43
44namespace {
45class ASTMaker {
46public:
47  ASTMaker(ASTContext &C) : C(C) {}
48
49  /// Create a new DeclRefExpr for the referenced variable.
50  DeclRefExpr *makeDeclRefExpr(const VarDecl *D);
51
52  /// Create a new UnaryOperator representing a dereference.
53  UnaryOperator *makeDereference(const Expr *Arg, QualType Ty);
54
55  /// Create an implicit cast for an integer conversion.
56  ImplicitCastExpr *makeIntegralCast(const Expr *Arg, QualType Ty);
57
58  // Create an implicit cast for lvalue-to-rvaluate conversions.
59  ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty);
60
61private:
62  ASTContext &C;
63};
64}
65
66DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) {
67  DeclRefExpr *DR =
68    DeclRefExpr::Create(/* Ctx = */ C,
69                        /* QualifierLoc = */ NestedNameSpecifierLoc(),
70                        /* TemplateKWLoc = */ SourceLocation(),
71                        /* D = */ const_cast<VarDecl*>(D),
72                        /* isEnclosingLocal = */ false,
73                        /* NameLoc = */ SourceLocation(),
74                        /* T = */ D->getType(),
75                        /* VK = */ VK_LValue);
76  return DR;
77}
78
79UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {
80  return new (C) UnaryOperator(const_cast<Expr*>(Arg), UO_Deref, Ty,
81                               VK_LValue, OK_Ordinary, SourceLocation());
82}
83
84ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
85  return ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
86                                  const_cast<Expr*>(Arg), 0, VK_RValue);
87}
88
89ImplicitCastExpr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
90  return ImplicitCastExpr::Create(C, Ty, CK_IntegralCast,
91                                  const_cast<Expr*>(Arg), 0, VK_RValue);
92}
93
94//===----------------------------------------------------------------------===//
95// Creation functions for faux ASTs.
96//===----------------------------------------------------------------------===//
97
98typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
99
100/// Create a fake body for dispatch_once.
101static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
102  // Check if we have at least two parameters.
103  if (D->param_size() != 2)
104    return 0;
105
106  // Check if the first parameter is a pointer to integer type.
107  const ParmVarDecl *Predicate = D->getParamDecl(0);
108  QualType PredicateQPtrTy = Predicate->getType();
109  const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();
110  if (!PredicatePtrTy)
111    return 0;
112  QualType PredicateTy = PredicatePtrTy->getPointeeType();
113  if (!PredicateTy->isIntegerType())
114    return 0;
115
116  // Check if the second parameter is the proper block type.
117  const ParmVarDecl *Block = D->getParamDecl(1);
118  QualType Ty = Block->getType();
119  if (!isDispatchBlock(Ty))
120    return 0;
121
122  // Everything checks out.  Create a fakse body that checks the predicate,
123  // sets it, and calls the block.  Basically, an AST dump of:
124  //
125  // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
126  //  if (!*predicate) {
127  //    *predicate = 1;
128  //    block();
129  //  }
130  // }
131
132  ASTMaker M(C);
133
134  // (1) Create the call.
135  DeclRefExpr *DR = M.makeDeclRefExpr(Block);
136  ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
137  CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
138                                  VK_RValue, SourceLocation());
139
140  // (2) Create the assignment to the predicate.
141  IntegerLiteral *IL =
142    IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), (uint64_t) 1),
143                           C.IntTy, SourceLocation());
144  ICE = M.makeIntegralCast(IL, PredicateTy);
145  DR = M.makeDeclRefExpr(Predicate);
146  ImplicitCastExpr *LValToRval = M.makeLvalueToRvalue(DR, PredicateQPtrTy);
147  UnaryOperator *UO = M.makeDereference(LValToRval, PredicateTy);
148  BinaryOperator *B = new (C) BinaryOperator(UO, ICE, BO_Assign,
149                                             PredicateTy, VK_RValue,
150                                             OK_Ordinary,
151                                             SourceLocation());
152  // (3) Create the compound statement.
153  Stmt *Stmts[2];
154  Stmts[0] = B;
155  Stmts[1] = CE;
156  CompoundStmt *CS = new (C) CompoundStmt(C, Stmts, 2, SourceLocation(),
157                                          SourceLocation());
158
159  // (4) Create the 'if' condition.
160  DR = M.makeDeclRefExpr(Predicate);
161  LValToRval = M.makeLvalueToRvalue(DR, PredicateQPtrTy);
162  UO = M.makeDereference(LValToRval, PredicateTy);
163  LValToRval = M.makeLvalueToRvalue(UO, PredicateTy);
164  UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy,
165                             VK_RValue, OK_Ordinary, SourceLocation());
166
167  // (5) Create the 'if' statement.
168  IfStmt *If = new (C) IfStmt(C, SourceLocation(), 0, UO, CS);
169  return If;
170}
171
172/// Create a fake body for dispatch_sync.
173static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
174  // Check if we have at least two parameters.
175  if (D->param_size() != 2)
176    return 0;
177
178  // Check if the second parameter is a block.
179  const ParmVarDecl *PV = D->getParamDecl(1);
180  QualType Ty = PV->getType();
181  if (!isDispatchBlock(Ty))
182    return 0;
183
184  // Everything checks out.  Create a fake body that just calls the block.
185  // This is basically just an AST dump of:
186  //
187  // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) {
188  //   block();
189  // }
190  //
191  ASTMaker M(C);
192  DeclRefExpr *DR = M.makeDeclRefExpr(PV);
193  ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
194  CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
195                                  VK_RValue, SourceLocation());
196  return CE;
197}
198
199Stmt *BodyFarm::getBody(const FunctionDecl *D) {
200  D = D->getCanonicalDecl();
201
202  llvm::Optional<Stmt *> &Val = Bodies[D];
203  if (Val.hasValue())
204    return Val.getValue();
205
206  Val = 0;
207
208  if (D->getIdentifier() == 0)
209    return 0;
210
211  StringRef Name = D->getName();
212  if (Name.empty())
213    return 0;
214
215  FunctionFarmer FF =
216    llvm::StringSwitch<FunctionFarmer>(Name)
217      .Case("dispatch_sync", create_dispatch_sync)
218      .Case("dispatch_once", create_dispatch_once)
219      .Default(NULL);
220
221  if (FF) {
222    Val = FF(C, D);
223  }
224
225  return Val.getValue();
226}
227
228