blob: fc874e0c8b14d0dd4d7f8806b28129ca307aa873 [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
49 DeclRefExpr *makeDeclRefExpr(const VarDecl *D);
50
51private:
52 ASTContext &C;
53};
54}
55
56DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) {
57 DeclRefExpr *DR =
58 DeclRefExpr::Create(/* Ctx = */ C,
59 /* QualifierLoc = */ NestedNameSpecifierLoc(),
60 /* TemplateKWLoc = */ SourceLocation(),
61 /* D = */ const_cast<VarDecl*>(D),
62 /* isEnclosingLocal = */ false,
63 /* NameLoc = */ SourceLocation(),
64 /* T = */ D->getType(),
65 /* VK = */ VK_LValue);
66 return DR;
67}
68
Ted Kremenek0a4c0982012-09-21 17:54:32 +000069//===----------------------------------------------------------------------===//
70// Creation functions for faux ASTs.
71//===----------------------------------------------------------------------===//
72
73typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
74
Ted Kremenekcc85d212012-09-21 00:52:24 +000075/// Create a fake body for dispatch_once.
76static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
77 // Check if we have at least two parameters.
78 if (D->param_size() != 2)
79 return 0;
80
81 // Check if the first parameter is a pointer to integer type.
82 const ParmVarDecl *Predicate = D->getParamDecl(0);
83 QualType PredicateQPtrTy = Predicate->getType();
84 const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();
85 if (!PredicatePtrTy)
86 return 0;
87 QualType PredicateTy = PredicatePtrTy->getPointeeType();
88 if (!PredicateTy->isIntegerType())
89 return 0;
90
91 // Check if the second parameter is the proper block type.
92 const ParmVarDecl *Block = D->getParamDecl(1);
93 QualType Ty = Block->getType();
94 if (!isDispatchBlock(Ty))
95 return 0;
96
97 // Everything checks out. Create a fakse body that checks the predicate,
98 // sets it, and calls the block. Basically, an AST dump of:
99 //
100 // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
101 // if (!*predicate) {
102 // *predicate = 1;
103 // block();
104 // }
105 // }
106
Ted Kremenek016c33d2012-09-21 17:54:35 +0000107 ASTMaker M(C);
108
Ted Kremenekcc85d212012-09-21 00:52:24 +0000109 // (1) Create the call.
Ted Kremenek016c33d2012-09-21 17:54:35 +0000110 DeclRefExpr *DR = M.makeDeclRefExpr(Block);
Ted Kremenekcc85d212012-09-21 00:52:24 +0000111 ImplicitCastExpr *ICE = ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
112 DR, 0, VK_RValue);
113 CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
114 VK_RValue, SourceLocation());
115
116 // (2) Create the assignment to the predicate.
117 IntegerLiteral *IL =
118 IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), (uint64_t) 1),
119 C.IntTy, SourceLocation());
120 ICE = ImplicitCastExpr::Create(C, PredicateTy, CK_IntegralCast, IL, 0,
121 VK_RValue);
Ted Kremenek016c33d2012-09-21 17:54:35 +0000122 DR = M.makeDeclRefExpr(Predicate);
Ted Kremenekcc85d212012-09-21 00:52:24 +0000123 ImplicitCastExpr *LValToRval =
124 ImplicitCastExpr::Create(C, PredicateQPtrTy, CK_LValueToRValue, DR,
125 0, VK_RValue);
126 UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_Deref, PredicateTy,
127 VK_LValue, OK_Ordinary,
128 SourceLocation());
129 BinaryOperator *B = new (C) BinaryOperator(UO, ICE, BO_Assign,
130 PredicateTy, VK_RValue,
131 OK_Ordinary,
132 SourceLocation());
133 // (3) Create the compound statement.
134 Stmt *Stmts[2];
135 Stmts[0] = B;
136 Stmts[1] = CE;
137 CompoundStmt *CS = new (C) CompoundStmt(C, Stmts, 2, SourceLocation(),
138 SourceLocation());
139
140 // (4) Create the 'if' condition.
Ted Kremenek016c33d2012-09-21 17:54:35 +0000141 DR = M.makeDeclRefExpr(Predicate);
Ted Kremenekcc85d212012-09-21 00:52:24 +0000142 LValToRval = ImplicitCastExpr::Create(C, PredicateQPtrTy, CK_LValueToRValue,
143 DR, 0, VK_RValue);
144 UO = new (C) UnaryOperator(LValToRval, UO_Deref, PredicateTy,
145 VK_LValue, OK_Ordinary,
146 SourceLocation());
147 LValToRval = ImplicitCastExpr::Create(C, PredicateTy, CK_LValueToRValue,
148 UO, 0, VK_RValue);
149 UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy,
150 VK_RValue, OK_Ordinary, SourceLocation());
151
152 // (5) Create the 'if' statement.
153 IfStmt *If = new (C) IfStmt(C, SourceLocation(), 0, UO, CS);
154 return If;
155}
156
Ted Kremeneka43df952012-09-21 00:09:11 +0000157/// Create a fake body for dispatch_sync.
158static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
159 // Check if we have at least two parameters.
160 if (D->param_size() != 2)
161 return 0;
162
163 // Check if the second parameter is a block.
164 const ParmVarDecl *PV = D->getParamDecl(1);
165 QualType Ty = PV->getType();
Ted Kremenekcc85d212012-09-21 00:52:24 +0000166 if (!isDispatchBlock(Ty))
Ted Kremeneka43df952012-09-21 00:09:11 +0000167 return 0;
Ted Kremenek016c33d2012-09-21 17:54:35 +0000168
Ted Kremeneka43df952012-09-21 00:09:11 +0000169 // Everything checks out. Create a fake body that just calls the block.
170 // This is basically just an AST dump of:
171 //
172 // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) {
173 // block();
174 // }
Ted Kremenek016c33d2012-09-21 17:54:35 +0000175 //
176 ASTMaker M(C);
177 DeclRefExpr *DR = M.makeDeclRefExpr(PV);
Ted Kremeneka43df952012-09-21 00:09:11 +0000178 ImplicitCastExpr *ICE = ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
179 DR, 0, VK_RValue);
180 CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
181 VK_RValue, SourceLocation());
182 return CE;
183}
184
185Stmt *BodyFarm::getBody(const FunctionDecl *D) {
186 D = D->getCanonicalDecl();
187
188 llvm::Optional<Stmt *> &Val = Bodies[D];
189 if (Val.hasValue())
190 return Val.getValue();
191
192 Val = 0;
193
194 if (D->getIdentifier() == 0)
195 return 0;
196
197 StringRef Name = D->getName();
198 if (Name.empty())
199 return 0;
200
201 FunctionFarmer FF =
202 llvm::StringSwitch<FunctionFarmer>(Name)
203 .Case("dispatch_sync", create_dispatch_sync)
Ted Kremenekcc85d212012-09-21 00:52:24 +0000204 .Case("dispatch_once", create_dispatch_once)
Ted Kremeneka43df952012-09-21 00:09:11 +0000205 .Default(NULL);
206
207 if (FF) {
208 Val = FF(C, D);
209 }
210
211 return Val.getValue();
212}
213