]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp
MFC r244628:
[FreeBSD/stable/9.git] / contrib / llvm / tools / clang / lib / Analysis / BodyFarm.cpp
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 "clang/AST/ExprObjC.h"
20 #include "BodyFarm.h"
21
22 using namespace clang;
23
24 //===----------------------------------------------------------------------===//
25 // Helper creation functions for constructing faux ASTs.
26 //===----------------------------------------------------------------------===//
27
28 static bool isDispatchBlock(QualType Ty) {
29   // Is it a block pointer?
30   const BlockPointerType *BPT = Ty->getAs<BlockPointerType>();
31   if (!BPT)
32     return false;
33
34   // Check if the block pointer type takes no arguments and
35   // returns void.
36   const FunctionProtoType *FT =
37   BPT->getPointeeType()->getAs<FunctionProtoType>();
38   if (!FT || !FT->getResultType()->isVoidType()  ||
39       FT->getNumArgs() != 0)
40     return false;
41
42   return true;
43 }
44
45 namespace {
46 class ASTMaker {
47 public:
48   ASTMaker(ASTContext &C) : C(C) {}
49   
50   /// Create a new BinaryOperator representing a simple assignment.
51   BinaryOperator *makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty);
52   
53   /// Create a new BinaryOperator representing a comparison.
54   BinaryOperator *makeComparison(const Expr *LHS, const Expr *RHS,
55                                  BinaryOperator::Opcode Op);
56   
57   /// Create a new compound stmt using the provided statements.
58   CompoundStmt *makeCompound(ArrayRef<Stmt*>);
59   
60   /// Create a new DeclRefExpr for the referenced variable.
61   DeclRefExpr *makeDeclRefExpr(const VarDecl *D);
62   
63   /// Create a new UnaryOperator representing a dereference.
64   UnaryOperator *makeDereference(const Expr *Arg, QualType Ty);
65   
66   /// Create an implicit cast for an integer conversion.
67   Expr *makeIntegralCast(const Expr *Arg, QualType Ty);
68   
69   /// Create an implicit cast to a builtin boolean type.
70   ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg);
71   
72   // Create an implicit cast for lvalue-to-rvaluate conversions.
73   ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty);
74   
75   /// Create an Objective-C bool literal.
76   ObjCBoolLiteralExpr *makeObjCBool(bool Val);
77   
78   /// Create a Return statement.
79   ReturnStmt *makeReturn(const Expr *RetVal);
80   
81 private:
82   ASTContext &C;
83 };
84 }
85
86 BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS,
87                                          QualType Ty) {
88  return new (C) BinaryOperator(const_cast<Expr*>(LHS), const_cast<Expr*>(RHS),
89                                BO_Assign, Ty, VK_RValue,
90                                OK_Ordinary, SourceLocation(), false);
91 }
92
93 BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,
94                                          BinaryOperator::Opcode Op) {
95   assert(BinaryOperator::isLogicalOp(Op) ||
96          BinaryOperator::isComparisonOp(Op));
97   return new (C) BinaryOperator(const_cast<Expr*>(LHS),
98                                 const_cast<Expr*>(RHS),
99                                 Op,
100                                 C.getLogicalOperationType(),
101                                 VK_RValue,
102                                 OK_Ordinary, SourceLocation(), false);
103 }
104
105 CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {
106   return new (C) CompoundStmt(C, const_cast<Stmt**>(Stmts.data()),
107                               Stmts.size(),
108                               SourceLocation(), SourceLocation());
109 }
110
111 DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) {
112   DeclRefExpr *DR =
113     DeclRefExpr::Create(/* Ctx = */ C,
114                         /* QualifierLoc = */ NestedNameSpecifierLoc(),
115                         /* TemplateKWLoc = */ SourceLocation(),
116                         /* D = */ const_cast<VarDecl*>(D),
117                         /* isEnclosingLocal = */ false,
118                         /* NameLoc = */ SourceLocation(),
119                         /* T = */ D->getType(),
120                         /* VK = */ VK_LValue);
121   return DR;
122 }
123
124 UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {
125   return new (C) UnaryOperator(const_cast<Expr*>(Arg), UO_Deref, Ty,
126                                VK_LValue, OK_Ordinary, SourceLocation());
127 }
128
129 ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
130   return ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
131                                   const_cast<Expr*>(Arg), 0, VK_RValue);
132 }
133
134 Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
135   if (Arg->getType() == Ty)
136     return const_cast<Expr*>(Arg);
137   
138   return ImplicitCastExpr::Create(C, Ty, CK_IntegralCast,
139                                   const_cast<Expr*>(Arg), 0, VK_RValue);
140 }
141
142 ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) {
143   return ImplicitCastExpr::Create(C, C.BoolTy, CK_IntegralToBoolean,
144                                   const_cast<Expr*>(Arg), 0, VK_RValue);
145 }
146
147 ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) {
148   QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy;
149   return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation());
150 }
151
152 ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) {
153   return new (C) ReturnStmt(SourceLocation(), const_cast<Expr*>(RetVal), 0);
154 }
155
156 //===----------------------------------------------------------------------===//
157 // Creation functions for faux ASTs.
158 //===----------------------------------------------------------------------===//
159
160 typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
161
162 /// Create a fake body for dispatch_once.
163 static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
164   // Check if we have at least two parameters.
165   if (D->param_size() != 2)
166     return 0;
167
168   // Check if the first parameter is a pointer to integer type.
169   const ParmVarDecl *Predicate = D->getParamDecl(0);
170   QualType PredicateQPtrTy = Predicate->getType();
171   const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();
172   if (!PredicatePtrTy)
173     return 0;
174   QualType PredicateTy = PredicatePtrTy->getPointeeType();
175   if (!PredicateTy->isIntegerType())
176     return 0;
177   
178   // Check if the second parameter is the proper block type.
179   const ParmVarDecl *Block = D->getParamDecl(1);
180   QualType Ty = Block->getType();
181   if (!isDispatchBlock(Ty))
182     return 0;
183   
184   // Everything checks out.  Create a fakse body that checks the predicate,
185   // sets it, and calls the block.  Basically, an AST dump of:
186   //
187   // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
188   //  if (!*predicate) {
189   //    *predicate = 1;
190   //    block();
191   //  }
192   // }
193   
194   ASTMaker M(C);
195   
196   // (1) Create the call.
197   DeclRefExpr *DR = M.makeDeclRefExpr(Block);
198   ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
199   CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
200                                   VK_RValue, SourceLocation());
201
202   // (2) Create the assignment to the predicate.
203   IntegerLiteral *IL =
204     IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), (uint64_t) 1),
205                            C.IntTy, SourceLocation());
206   BinaryOperator *B =
207     M.makeAssignment(
208        M.makeDereference(
209           M.makeLvalueToRvalue(
210             M.makeDeclRefExpr(Predicate), PredicateQPtrTy),
211             PredicateTy),
212        M.makeIntegralCast(IL, PredicateTy),
213        PredicateTy);
214   
215   // (3) Create the compound statement.
216   Stmt *Stmts[2];
217   Stmts[0] = B;
218   Stmts[1] = CE;
219   CompoundStmt *CS = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2));
220   
221   // (4) Create the 'if' condition.
222   ImplicitCastExpr *LValToRval =
223     M.makeLvalueToRvalue(
224       M.makeDereference(
225         M.makeLvalueToRvalue(
226           M.makeDeclRefExpr(Predicate),
227           PredicateQPtrTy),
228         PredicateTy),
229     PredicateTy);
230   
231   UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy,
232                                            VK_RValue, OK_Ordinary,
233                                            SourceLocation());
234   
235   // (5) Create the 'if' statement.
236   IfStmt *If = new (C) IfStmt(C, SourceLocation(), 0, UO, CS);
237   return If;
238 }
239
240 /// Create a fake body for dispatch_sync.
241 static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
242   // Check if we have at least two parameters.
243   if (D->param_size() != 2)
244     return 0;
245   
246   // Check if the second parameter is a block.
247   const ParmVarDecl *PV = D->getParamDecl(1);
248   QualType Ty = PV->getType();
249   if (!isDispatchBlock(Ty))
250     return 0;
251   
252   // Everything checks out.  Create a fake body that just calls the block.
253   // This is basically just an AST dump of:
254   //
255   // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) {
256   //   block();
257   // }
258   //  
259   ASTMaker M(C);
260   DeclRefExpr *DR = M.makeDeclRefExpr(PV);
261   ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
262   CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
263                                   VK_RValue, SourceLocation());
264   return CE;
265 }
266
267 static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
268 {
269   // There are exactly 3 arguments.
270   if (D->param_size() != 3)
271     return 0;
272   
273   // Body for:
274   //   if (oldValue == *theValue) {
275   //    *theValue = newValue;
276   //    return YES;
277   //   }
278   //   else return NO;
279   
280   QualType ResultTy = D->getResultType();
281   bool isBoolean = ResultTy->isBooleanType();
282   if (!isBoolean && !ResultTy->isIntegralType(C))
283     return 0;
284   
285   const ParmVarDecl *OldValue = D->getParamDecl(0);
286   QualType OldValueTy = OldValue->getType();
287
288   const ParmVarDecl *NewValue = D->getParamDecl(1);
289   QualType NewValueTy = NewValue->getType();
290   
291   assert(OldValueTy == NewValueTy);
292   
293   const ParmVarDecl *TheValue = D->getParamDecl(2);
294   QualType TheValueTy = TheValue->getType();
295   const PointerType *PT = TheValueTy->getAs<PointerType>();
296   if (!PT)
297     return 0;
298   QualType PointeeTy = PT->getPointeeType();
299   
300   ASTMaker M(C);
301   // Construct the comparison.
302   Expr *Comparison =
303     M.makeComparison(
304       M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy),
305       M.makeLvalueToRvalue(
306         M.makeDereference(
307           M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
308           PointeeTy),
309         PointeeTy),
310       BO_EQ);
311
312   // Construct the body of the IfStmt.
313   Stmt *Stmts[2];
314   Stmts[0] =
315     M.makeAssignment(
316       M.makeDereference(
317         M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
318         PointeeTy),
319       M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy),
320       NewValueTy);
321   
322   Expr *BoolVal = M.makeObjCBool(true);
323   Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
324                            : M.makeIntegralCast(BoolVal, ResultTy);
325   Stmts[1] = M.makeReturn(RetVal);
326   CompoundStmt *Body = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2));
327   
328   // Construct the else clause.
329   BoolVal = M.makeObjCBool(false);
330   RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
331                      : M.makeIntegralCast(BoolVal, ResultTy);
332   Stmt *Else = M.makeReturn(RetVal);
333   
334   /// Construct the If.
335   Stmt *If =
336     new (C) IfStmt(C, SourceLocation(), 0, Comparison, Body,
337                    SourceLocation(), Else);
338   
339   return If;  
340 }
341
342 Stmt *BodyFarm::getBody(const FunctionDecl *D) {
343   D = D->getCanonicalDecl();
344   
345   llvm::Optional<Stmt *> &Val = Bodies[D];
346   if (Val.hasValue())
347     return Val.getValue();
348   
349   Val = 0;
350   
351   if (D->getIdentifier() == 0)
352     return 0;
353
354   StringRef Name = D->getName();
355   if (Name.empty())
356     return 0;
357
358   FunctionFarmer FF;
359
360   if (Name.startswith("OSAtomicCompareAndSwap") ||
361       Name.startswith("objc_atomicCompareAndSwap")) {
362     FF = create_OSAtomicCompareAndSwap;
363   }
364   else {
365     FF = llvm::StringSwitch<FunctionFarmer>(Name)
366           .Case("dispatch_sync", create_dispatch_sync)
367           .Case("dispatch_once", create_dispatch_once)
368         .Default(NULL);
369   }
370   
371   if (FF) { Val = FF(C, D); }
372   return Val.getValue();
373 }
374