blob: 2faacd4ea3e04b38bf0fb8ce9e5eb692cb699c25 [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 Kremenek0b5c5e42012-09-21 18:33:52 +000052 /// Create a new UnaryOperator representing a dereference.
53 UnaryOperator *makeDereference(const Expr *Arg, QualType Ty);
54
Ted Kremeneka6d62a12012-09-21 18:13:23 +000055 /// Create an implicit cast for an integer conversion.
56 ImplicitCastExpr *makeIntegralCast(const Expr *Arg, QualType Ty);
57
Ted Kremenek9ba05cd2012-09-21 18:13:27 +000058 // Create an implicit cast for lvalue-to-rvaluate conversions.
59 ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty);
60
Ted Kremenek016c33d2012-09-21 17:54:35 +000061private:
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
Ted Kremenek0b5c5e42012-09-21 18:33:52 +000079UnaryOperator *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
Ted Kremenek9ba05cd2012-09-21 18:13:27 +000084ImplicitCastExpr *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
Ted Kremeneka6d62a12012-09-21 18:13:23 +000089ImplicitCastExpr *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
Ted Kremenek0a4c0982012-09-21 17:54:32 +000094//===----------------------------------------------------------------------===//
95// Creation functions for faux ASTs.
96//===----------------------------------------------------------------------===//
97
98typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
99
Ted Kremenekcc85d212012-09-21 00:52:24 +0000100/// 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
Ted Kremenek016c33d2012-09-21 17:54:35 +0000132 ASTMaker M(C);
133
Ted Kremenekcc85d212012-09-21 00:52:24 +0000134 // (1) Create the call.
Ted Kremenek016c33d2012-09-21 17:54:35 +0000135 DeclRefExpr *DR = M.makeDeclRefExpr(Block);
Ted Kremenek9ba05cd2012-09-21 18:13:27 +0000136 ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
Ted Kremenekcc85d212012-09-21 00:52:24 +0000137 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());
Ted Kremeneka6d62a12012-09-21 18:13:23 +0000144 ICE = M.makeIntegralCast(IL, PredicateTy);
Ted Kremenek016c33d2012-09-21 17:54:35 +0000145 DR = M.makeDeclRefExpr(Predicate);
Ted Kremenek9ba05cd2012-09-21 18:13:27 +0000146 ImplicitCastExpr *LValToRval = M.makeLvalueToRvalue(DR, PredicateQPtrTy);
Ted Kremenek0b5c5e42012-09-21 18:33:52 +0000147 UnaryOperator *UO = M.makeDereference(LValToRval, PredicateTy);
Ted Kremenekcc85d212012-09-21 00:52:24 +0000148 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.
Ted Kremenek016c33d2012-09-21 17:54:35 +0000160 DR = M.makeDeclRefExpr(Predicate);
Ted Kremenek9ba05cd2012-09-21 18:13:27 +0000161 LValToRval = M.makeLvalueToRvalue(DR, PredicateQPtrTy);
Ted Kremenek0b5c5e42012-09-21 18:33:52 +0000162 UO = M.makeDereference(LValToRval, PredicateTy);
Ted Kremenek9ba05cd2012-09-21 18:13:27 +0000163 LValToRval = M.makeLvalueToRvalue(UO, PredicateTy);
Ted Kremenekcc85d212012-09-21 00:52:24 +0000164 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
Ted Kremeneka43df952012-09-21 00:09:11 +0000172/// 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();
Ted Kremenekcc85d212012-09-21 00:52:24 +0000181 if (!isDispatchBlock(Ty))
Ted Kremeneka43df952012-09-21 00:09:11 +0000182 return 0;
Ted Kremenek016c33d2012-09-21 17:54:35 +0000183
Ted Kremeneka43df952012-09-21 00:09:11 +0000184 // 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 // }
Ted Kremenek016c33d2012-09-21 17:54:35 +0000190 //
191 ASTMaker M(C);
192 DeclRefExpr *DR = M.makeDeclRefExpr(PV);
Ted Kremenek0b5c5e42012-09-21 18:33:52 +0000193 ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
Ted Kremeneka43df952012-09-21 00:09:11 +0000194 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)
Ted Kremenekcc85d212012-09-21 00:52:24 +0000218 .Case("dispatch_once", create_dispatch_once)
Ted Kremeneka43df952012-09-21 00:09:11 +0000219 .Default(NULL);
220
221 if (FF) {
222 Val = FF(C, D);
223 }
224
225 return Val.getValue();
226}
227