blob: f7fbcc933dcbbffd18b5e68dba5c10232adae1c8 [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 Kremenek016c33d2012-09-21 17:54:35 +000055private:
56 ASTContext &C;
57};
58}
59
60DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) {
61 DeclRefExpr *DR =
62 DeclRefExpr::Create(/* Ctx = */ C,
63 /* QualifierLoc = */ NestedNameSpecifierLoc(),
64 /* TemplateKWLoc = */ SourceLocation(),
65 /* D = */ const_cast<VarDecl*>(D),
66 /* isEnclosingLocal = */ false,
67 /* NameLoc = */ SourceLocation(),
68 /* T = */ D->getType(),
69 /* VK = */ VK_LValue);
70 return DR;
71}
72
Ted Kremeneka6d62a12012-09-21 18:13:23 +000073ImplicitCastExpr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
74 return ImplicitCastExpr::Create(C, Ty, CK_IntegralCast,
75 const_cast<Expr*>(Arg), 0, VK_RValue);
76}
77
Ted Kremenek0a4c0982012-09-21 17:54:32 +000078//===----------------------------------------------------------------------===//
79// Creation functions for faux ASTs.
80//===----------------------------------------------------------------------===//
81
82typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
83
Ted Kremenekcc85d212012-09-21 00:52:24 +000084/// Create a fake body for dispatch_once.
85static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
86 // Check if we have at least two parameters.
87 if (D->param_size() != 2)
88 return 0;
89
90 // Check if the first parameter is a pointer to integer type.
91 const ParmVarDecl *Predicate = D->getParamDecl(0);
92 QualType PredicateQPtrTy = Predicate->getType();
93 const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();
94 if (!PredicatePtrTy)
95 return 0;
96 QualType PredicateTy = PredicatePtrTy->getPointeeType();
97 if (!PredicateTy->isIntegerType())
98 return 0;
99
100 // Check if the second parameter is the proper block type.
101 const ParmVarDecl *Block = D->getParamDecl(1);
102 QualType Ty = Block->getType();
103 if (!isDispatchBlock(Ty))
104 return 0;
105
106 // Everything checks out. Create a fakse body that checks the predicate,
107 // sets it, and calls the block. Basically, an AST dump of:
108 //
109 // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
110 // if (!*predicate) {
111 // *predicate = 1;
112 // block();
113 // }
114 // }
115
Ted Kremenek016c33d2012-09-21 17:54:35 +0000116 ASTMaker M(C);
117
Ted Kremenekcc85d212012-09-21 00:52:24 +0000118 // (1) Create the call.
Ted Kremenek016c33d2012-09-21 17:54:35 +0000119 DeclRefExpr *DR = M.makeDeclRefExpr(Block);
Ted Kremenekcc85d212012-09-21 00:52:24 +0000120 ImplicitCastExpr *ICE = ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
121 DR, 0, VK_RValue);
122 CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
123 VK_RValue, SourceLocation());
124
125 // (2) Create the assignment to the predicate.
126 IntegerLiteral *IL =
127 IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), (uint64_t) 1),
128 C.IntTy, SourceLocation());
Ted Kremeneka6d62a12012-09-21 18:13:23 +0000129 ICE = M.makeIntegralCast(IL, PredicateTy);
Ted Kremenek016c33d2012-09-21 17:54:35 +0000130 DR = M.makeDeclRefExpr(Predicate);
Ted Kremenekcc85d212012-09-21 00:52:24 +0000131 ImplicitCastExpr *LValToRval =
132 ImplicitCastExpr::Create(C, PredicateQPtrTy, CK_LValueToRValue, DR,
133 0, VK_RValue);
134 UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_Deref, PredicateTy,
135 VK_LValue, OK_Ordinary,
136 SourceLocation());
137 BinaryOperator *B = new (C) BinaryOperator(UO, ICE, BO_Assign,
138 PredicateTy, VK_RValue,
139 OK_Ordinary,
140 SourceLocation());
141 // (3) Create the compound statement.
142 Stmt *Stmts[2];
143 Stmts[0] = B;
144 Stmts[1] = CE;
145 CompoundStmt *CS = new (C) CompoundStmt(C, Stmts, 2, SourceLocation(),
146 SourceLocation());
147
148 // (4) Create the 'if' condition.
Ted Kremenek016c33d2012-09-21 17:54:35 +0000149 DR = M.makeDeclRefExpr(Predicate);
Ted Kremenekcc85d212012-09-21 00:52:24 +0000150 LValToRval = ImplicitCastExpr::Create(C, PredicateQPtrTy, CK_LValueToRValue,
151 DR, 0, VK_RValue);
152 UO = new (C) UnaryOperator(LValToRval, UO_Deref, PredicateTy,
153 VK_LValue, OK_Ordinary,
154 SourceLocation());
155 LValToRval = ImplicitCastExpr::Create(C, PredicateTy, CK_LValueToRValue,
156 UO, 0, VK_RValue);
157 UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy,
158 VK_RValue, OK_Ordinary, SourceLocation());
159
160 // (5) Create the 'if' statement.
161 IfStmt *If = new (C) IfStmt(C, SourceLocation(), 0, UO, CS);
162 return If;
163}
164
Ted Kremeneka43df952012-09-21 00:09:11 +0000165/// Create a fake body for dispatch_sync.
166static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
167 // Check if we have at least two parameters.
168 if (D->param_size() != 2)
169 return 0;
170
171 // Check if the second parameter is a block.
172 const ParmVarDecl *PV = D->getParamDecl(1);
173 QualType Ty = PV->getType();
Ted Kremenekcc85d212012-09-21 00:52:24 +0000174 if (!isDispatchBlock(Ty))
Ted Kremeneka43df952012-09-21 00:09:11 +0000175 return 0;
Ted Kremenek016c33d2012-09-21 17:54:35 +0000176
Ted Kremeneka43df952012-09-21 00:09:11 +0000177 // Everything checks out. Create a fake body that just calls the block.
178 // This is basically just an AST dump of:
179 //
180 // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) {
181 // block();
182 // }
Ted Kremenek016c33d2012-09-21 17:54:35 +0000183 //
184 ASTMaker M(C);
185 DeclRefExpr *DR = M.makeDeclRefExpr(PV);
Ted Kremeneka43df952012-09-21 00:09:11 +0000186 ImplicitCastExpr *ICE = ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
187 DR, 0, VK_RValue);
188 CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
189 VK_RValue, SourceLocation());
190 return CE;
191}
192
193Stmt *BodyFarm::getBody(const FunctionDecl *D) {
194 D = D->getCanonicalDecl();
195
196 llvm::Optional<Stmt *> &Val = Bodies[D];
197 if (Val.hasValue())
198 return Val.getValue();
199
200 Val = 0;
201
202 if (D->getIdentifier() == 0)
203 return 0;
204
205 StringRef Name = D->getName();
206 if (Name.empty())
207 return 0;
208
209 FunctionFarmer FF =
210 llvm::StringSwitch<FunctionFarmer>(Name)
211 .Case("dispatch_sync", create_dispatch_sync)
Ted Kremenekcc85d212012-09-21 00:52:24 +0000212 .Case("dispatch_once", create_dispatch_once)
Ted Kremeneka43df952012-09-21 00:09:11 +0000213 .Default(NULL);
214
215 if (FF) {
216 Val = FF(C, D);
217 }
218
219 return Val.getValue();
220}
221