blob: be8bf52d029617c846b8005f3e41189461496133 [file] [log] [blame]
Ted Kremeneka43df952012-09-21 00:09:11 +00001//== 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
Ted Kremenek0a4c0982012-09-21 17:54:32 +000023//===----------------------------------------------------------------------===//
24// Helper creation functions for constructing faux ASTs.
25//===----------------------------------------------------------------------===//
Ted Kremeneka43df952012-09-21 00:09:11 +000026
Ted Kremenekcc85d212012-09-21 00:52:24 +000027static 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
Ted Kremenek016c33d2012-09-21 17:54:35 +000044namespace {
45class ASTMaker {
46public:
47 ASTMaker(ASTContext &C) : C(C) {}
48
Ted Kremeneka6d62a12012-09-21 18:13:23 +000049 /// Create a new DeclRefExpr for the referenced variable.
Ted Kremenek016c33d2012-09-21 17:54:35 +000050 DeclRefExpr *makeDeclRefExpr(const VarDecl *D);
51
Ted Kremeneka6d62a12012-09-21 18:13:23 +000052 /// Create an implicit cast for an integer conversion.
53 ImplicitCastExpr *makeIntegralCast(const Expr *Arg, QualType Ty);
54
Ted Kremenek9ba05cd2012-09-21 18:13:27 +000055 // Create an implicit cast for lvalue-to-rvaluate conversions.
56 ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty);
57
Ted Kremenek016c33d2012-09-21 17:54:35 +000058private:
59 ASTContext &C;
60};
61}
62
63DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) {
64 DeclRefExpr *DR =
65 DeclRefExpr::Create(/* Ctx = */ C,
66 /* QualifierLoc = */ NestedNameSpecifierLoc(),
67 /* TemplateKWLoc = */ SourceLocation(),
68 /* D = */ const_cast<VarDecl*>(D),
69 /* isEnclosingLocal = */ false,
70 /* NameLoc = */ SourceLocation(),
71 /* T = */ D->getType(),
72 /* VK = */ VK_LValue);
73 return DR;
74}
75
Ted Kremenek9ba05cd2012-09-21 18:13:27 +000076ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
77 return ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
78 const_cast<Expr*>(Arg), 0, VK_RValue);
79}
80
Ted Kremeneka6d62a12012-09-21 18:13:23 +000081ImplicitCastExpr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
82 return ImplicitCastExpr::Create(C, Ty, CK_IntegralCast,
83 const_cast<Expr*>(Arg), 0, VK_RValue);
84}
85
Ted Kremenek0a4c0982012-09-21 17:54:32 +000086//===----------------------------------------------------------------------===//
87// Creation functions for faux ASTs.
88//===----------------------------------------------------------------------===//
89
90typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
91
Ted Kremenekcc85d212012-09-21 00:52:24 +000092/// Create a fake body for dispatch_once.
93static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
94 // Check if we have at least two parameters.
95 if (D->param_size() != 2)
96 return 0;
97
98 // Check if the first parameter is a pointer to integer type.
99 const ParmVarDecl *Predicate = D->getParamDecl(0);
100 QualType PredicateQPtrTy = Predicate->getType();
101 const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();
102 if (!PredicatePtrTy)
103 return 0;
104 QualType PredicateTy = PredicatePtrTy->getPointeeType();
105 if (!PredicateTy->isIntegerType())
106 return 0;
107
108 // Check if the second parameter is the proper block type.
109 const ParmVarDecl *Block = D->getParamDecl(1);
110 QualType Ty = Block->getType();
111 if (!isDispatchBlock(Ty))
112 return 0;
113
114 // Everything checks out. Create a fakse body that checks the predicate,
115 // sets it, and calls the block. Basically, an AST dump of:
116 //
117 // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
118 // if (!*predicate) {
119 // *predicate = 1;
120 // block();
121 // }
122 // }
123
Ted Kremenek016c33d2012-09-21 17:54:35 +0000124 ASTMaker M(C);
125
Ted Kremenekcc85d212012-09-21 00:52:24 +0000126 // (1) Create the call.
Ted Kremenek016c33d2012-09-21 17:54:35 +0000127 DeclRefExpr *DR = M.makeDeclRefExpr(Block);
Ted Kremenek9ba05cd2012-09-21 18:13:27 +0000128 ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
Ted Kremenekcc85d212012-09-21 00:52:24 +0000129 CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
130 VK_RValue, SourceLocation());
131
132 // (2) Create the assignment to the predicate.
133 IntegerLiteral *IL =
134 IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), (uint64_t) 1),
135 C.IntTy, SourceLocation());
Ted Kremeneka6d62a12012-09-21 18:13:23 +0000136 ICE = M.makeIntegralCast(IL, PredicateTy);
Ted Kremenek016c33d2012-09-21 17:54:35 +0000137 DR = M.makeDeclRefExpr(Predicate);
Ted Kremenek9ba05cd2012-09-21 18:13:27 +0000138 ImplicitCastExpr *LValToRval = M.makeLvalueToRvalue(DR, PredicateQPtrTy);
Ted Kremenekcc85d212012-09-21 00:52:24 +0000139 UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_Deref, PredicateTy,
140 VK_LValue, OK_Ordinary,
141 SourceLocation());
142 BinaryOperator *B = new (C) BinaryOperator(UO, ICE, BO_Assign,
143 PredicateTy, VK_RValue,
144 OK_Ordinary,
145 SourceLocation());
146 // (3) Create the compound statement.
147 Stmt *Stmts[2];
148 Stmts[0] = B;
149 Stmts[1] = CE;
150 CompoundStmt *CS = new (C) CompoundStmt(C, Stmts, 2, SourceLocation(),
151 SourceLocation());
152
153 // (4) Create the 'if' condition.
Ted Kremenek016c33d2012-09-21 17:54:35 +0000154 DR = M.makeDeclRefExpr(Predicate);
Ted Kremenek9ba05cd2012-09-21 18:13:27 +0000155 LValToRval = M.makeLvalueToRvalue(DR, PredicateQPtrTy);
Ted Kremenekcc85d212012-09-21 00:52:24 +0000156 UO = new (C) UnaryOperator(LValToRval, UO_Deref, PredicateTy,
157 VK_LValue, OK_Ordinary,
158 SourceLocation());
Ted Kremenek9ba05cd2012-09-21 18:13:27 +0000159 LValToRval = M.makeLvalueToRvalue(UO, PredicateTy);
Ted Kremenekcc85d212012-09-21 00:52:24 +0000160 UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy,
161 VK_RValue, OK_Ordinary, SourceLocation());
162
163 // (5) Create the 'if' statement.
164 IfStmt *If = new (C) IfStmt(C, SourceLocation(), 0, UO, CS);
165 return If;
166}
167
Ted Kremeneka43df952012-09-21 00:09:11 +0000168/// Create a fake body for dispatch_sync.
169static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
170 // Check if we have at least two parameters.
171 if (D->param_size() != 2)
172 return 0;
173
174 // Check if the second parameter is a block.
175 const ParmVarDecl *PV = D->getParamDecl(1);
176 QualType Ty = PV->getType();
Ted Kremenekcc85d212012-09-21 00:52:24 +0000177 if (!isDispatchBlock(Ty))
Ted Kremeneka43df952012-09-21 00:09:11 +0000178 return 0;
Ted Kremenek016c33d2012-09-21 17:54:35 +0000179
Ted Kremeneka43df952012-09-21 00:09:11 +0000180 // Everything checks out. Create a fake body that just calls the block.
181 // This is basically just an AST dump of:
182 //
183 // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) {
184 // block();
185 // }
Ted Kremenek016c33d2012-09-21 17:54:35 +0000186 //
187 ASTMaker M(C);
188 DeclRefExpr *DR = M.makeDeclRefExpr(PV);
Ted Kremeneka43df952012-09-21 00:09:11 +0000189 ImplicitCastExpr *ICE = ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
190 DR, 0, VK_RValue);
191 CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
192 VK_RValue, SourceLocation());
193 return CE;
194}
195
196Stmt *BodyFarm::getBody(const FunctionDecl *D) {
197 D = D->getCanonicalDecl();
198
199 llvm::Optional<Stmt *> &Val = Bodies[D];
200 if (Val.hasValue())
201 return Val.getValue();
202
203 Val = 0;
204
205 if (D->getIdentifier() == 0)
206 return 0;
207
208 StringRef Name = D->getName();
209 if (Name.empty())
210 return 0;
211
212 FunctionFarmer FF =
213 llvm::StringSwitch<FunctionFarmer>(Name)
214 .Case("dispatch_sync", create_dispatch_sync)
Ted Kremenekcc85d212012-09-21 00:52:24 +0000215 .Case("dispatch_once", create_dispatch_once)
Ted Kremeneka43df952012-09-21 00:09:11 +0000216 .Default(NULL);
217
218 if (FF) {
219 Val = FF(C, D);
220 }
221
222 return Val.getValue();
223}
224