blob: 25e7fc4238492d8a585266ab17128b8e5377c81d [file] [log] [blame]
Steve Naroff1c9f81b2008-09-17 00:13:27 +00001//===--- RewriteBlocks.cpp ----------------------------------------------===//
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// Hacks and fun related to the closure rewriter.
11//
12//===----------------------------------------------------------------------===//
13
Eli Friedman39d7c4d2009-05-18 22:50:54 +000014#include "clang/Frontend/ASTConsumers.h"
Steve Naroff1c9f81b2008-09-17 00:13:27 +000015#include "clang/Rewrite/Rewriter.h"
16#include "clang/AST/AST.h"
17#include "clang/AST/ASTConsumer.h"
18#include "clang/Basic/SourceManager.h"
19#include "clang/Basic/IdentifierTable.h"
20#include "clang/Basic/Diagnostic.h"
21#include "clang/Basic/LangOptions.h"
22#include "llvm/Support/MemoryBuffer.h"
23#include "llvm/ADT/StringExtras.h"
24#include "llvm/ADT/SmallPtrSet.h"
Steve Naroff1c9f81b2008-09-17 00:13:27 +000025
26using namespace clang;
27using llvm::utostr;
28
29namespace {
30
31class RewriteBlocks : public ASTConsumer {
32 Rewriter Rewrite;
33 Diagnostic &Diags;
34 const LangOptions &LangOpts;
35 unsigned RewriteFailedDiag;
Steve Naroff1c9f81b2008-09-17 00:13:27 +000036
37 ASTContext *Context;
38 SourceManager *SM;
Chris Lattner2b2453a2009-01-17 06:22:33 +000039 FileID MainFileID;
Steve Naroff1c9f81b2008-09-17 00:13:27 +000040 const char *MainFileStart, *MainFileEnd;
41
42 // Block expressions.
43 llvm::SmallVector<BlockExpr *, 32> Blocks;
44 llvm::SmallVector<BlockDeclRefExpr *, 32> BlockDeclRefs;
45 llvm::DenseMap<BlockDeclRefExpr *, CallExpr *> BlockCallExprs;
Mike Stump1eb44332009-09-09 15:08:12 +000046
Steve Naroff1c9f81b2008-09-17 00:13:27 +000047 // Block related declarations.
48 llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDecls;
49 llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDecls;
Steve Naroff4e13b762008-10-03 20:28:15 +000050 llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls;
Steve Naroff70f95502008-10-04 17:06:23 +000051
52 llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs;
Mike Stump1eb44332009-09-09 15:08:12 +000053
Steve Naroff1c9f81b2008-09-17 00:13:27 +000054 // The function/method we are rewriting.
55 FunctionDecl *CurFunctionDef;
56 ObjCMethodDecl *CurMethodDef;
Mike Stump1eb44332009-09-09 15:08:12 +000057
Steve Naroff1c9f81b2008-09-17 00:13:27 +000058 bool IsHeader;
Mike Stump1eb44332009-09-09 15:08:12 +000059
Steve Naroffa0b75cf2008-10-02 23:30:43 +000060 std::string Preamble;
Steve Naroff1c9f81b2008-09-17 00:13:27 +000061public:
Mike Stump1eb44332009-09-09 15:08:12 +000062 RewriteBlocks(std::string inFile, Diagnostic &D,
Steve Naroff13188952008-09-18 14:10:13 +000063 const LangOptions &LOpts);
Steve Naroff1c9f81b2008-09-17 00:13:27 +000064 ~RewriteBlocks() {
Mike Stump1eb44332009-09-09 15:08:12 +000065 // Get the buffer corresponding to MainFileID.
Steve Naroff1c9f81b2008-09-17 00:13:27 +000066 // If we haven't changed it, then we are done.
Mike Stump1eb44332009-09-09 15:08:12 +000067 if (const RewriteBuffer *RewriteBuf =
Steve Naroff1c9f81b2008-09-17 00:13:27 +000068 Rewrite.getRewriteBufferFor(MainFileID)) {
69 std::string S(RewriteBuf->begin(), RewriteBuf->end());
70 printf("%s\n", S.c_str());
71 } else {
72 printf("No changes\n");
73 }
74 }
Mike Stump1eb44332009-09-09 15:08:12 +000075
Steve Naroff1c9f81b2008-09-17 00:13:27 +000076 void Initialize(ASTContext &context);
77
78 void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen);
79 void ReplaceText(SourceLocation Start, unsigned OrigLength,
80 const char *NewStr, unsigned NewLength);
81
82 // Top Level Driver code.
Chris Lattner682bf922009-03-29 16:50:03 +000083 virtual void HandleTopLevelDecl(DeclGroupRef D) {
84 for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
85 HandleTopLevelSingleDecl(*I);
86 }
87 void HandleTopLevelSingleDecl(Decl *D);
Steve Naroff1c9f81b2008-09-17 00:13:27 +000088 void HandleDeclInMainFile(Decl *D);
Mike Stump1eb44332009-09-09 15:08:12 +000089
90 // Top level
Steve Naroff1c9f81b2008-09-17 00:13:27 +000091 Stmt *RewriteFunctionBody(Stmt *S);
92 void InsertBlockLiteralsWithinFunction(FunctionDecl *FD);
93 void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD);
Mike Stump1eb44332009-09-09 15:08:12 +000094
Steve Naroff1c9f81b2008-09-17 00:13:27 +000095 // Block specific rewrite rules.
Steve Naroff70f95502008-10-04 17:06:23 +000096 std::string SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD=0);
Mike Stump1eb44332009-09-09 15:08:12 +000097
Steve Naroff1c9f81b2008-09-17 00:13:27 +000098 void RewriteBlockCall(CallExpr *Exp);
99 void RewriteBlockPointerDecl(NamedDecl *VD);
Steve Naroff5e52b172008-10-04 18:52:47 +0000100 void RewriteBlockDeclRefExpr(BlockDeclRefExpr *VD);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000101 void RewriteBlockPointerFunctionArgs(FunctionDecl *FD);
Mike Stump1eb44332009-09-09 15:08:12 +0000102
103 std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
Steve Naroff4e13b762008-10-03 20:28:15 +0000104 const char *funcName, std::string Tag);
Mike Stump1eb44332009-09-09 15:08:12 +0000105 std::string SynthesizeBlockFunc(BlockExpr *CE, int i,
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000106 const char *funcName, std::string Tag);
Mike Stump1eb44332009-09-09 15:08:12 +0000107 std::string SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
Steve Naroffacba0f22008-10-04 23:47:37 +0000108 bool hasCopyDisposeHelpers);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000109 std::string SynthesizeBlockCall(CallExpr *Exp);
110 void SynthesizeBlockLiterals(SourceLocation FunLocStart,
111 const char *FunName);
Mike Stump1eb44332009-09-09 15:08:12 +0000112
Steve Naroffd3f77902008-10-05 00:06:12 +0000113 void CollectBlockDeclRefInfo(BlockExpr *Exp);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000114 void GetBlockCallExprs(Stmt *S);
Steve Naroffacba0f22008-10-04 23:47:37 +0000115 void GetBlockDeclRefExprs(Stmt *S);
Mike Stump1eb44332009-09-09 15:08:12 +0000116
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000117 // We avoid calling Type::isBlockPointerType(), since it operates on the
118 // canonical type. We only care if the top-level type is a closure pointer.
119 bool isBlockPointerType(QualType T) { return isa<BlockPointerType>(T); }
Mike Stump1eb44332009-09-09 15:08:12 +0000120
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000121 // FIXME: This predicate seems like it would be useful to add to ASTContext.
122 bool isObjCType(QualType T) {
123 if (!LangOpts.ObjC1 && !LangOpts.ObjC2)
124 return false;
Mike Stump1eb44332009-09-09 15:08:12 +0000125
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000126 QualType OCT = Context->getCanonicalType(T).getUnqualifiedType();
Mike Stump1eb44332009-09-09 15:08:12 +0000127
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000128 if (OCT == Context->getCanonicalType(Context->getObjCIdType()) ||
129 OCT == Context->getCanonicalType(Context->getObjCClassType()))
130 return true;
Mike Stump1eb44332009-09-09 15:08:12 +0000131
Ted Kremenek6217b802009-07-29 21:53:49 +0000132 if (const PointerType *PT = OCT->getAs<PointerType>()) {
Mike Stump1eb44332009-09-09 15:08:12 +0000133 if (isa<ObjCInterfaceType>(PT->getPointeeType()) ||
Steve Naroffd1b3c2d2009-06-17 22:40:22 +0000134 PT->getPointeeType()->isObjCQualifiedIdType())
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000135 return true;
136 }
137 return false;
138 }
139 // ObjC rewrite methods.
140 void RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl);
141 void RewriteCategoryDecl(ObjCCategoryDecl *CatDecl);
142 void RewriteProtocolDecl(ObjCProtocolDecl *PDecl);
143 void RewriteMethodDecl(ObjCMethodDecl *MDecl);
Steve Naroffca743602008-10-15 18:38:58 +0000144
Douglas Gregor72564e72009-02-26 23:50:07 +0000145 void RewriteFunctionProtoType(QualType funcType, NamedDecl *D);
Steve Naroffca743602008-10-15 18:38:58 +0000146 void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND);
147 void RewriteCastExpr(CastExpr *CE);
Mike Stump1eb44332009-09-09 15:08:12 +0000148
Steve Naroffca743602008-10-15 18:38:58 +0000149 bool PointerTypeTakesAnyBlockArguments(QualType QT);
Steve Naroff1f6c3ae2008-09-24 17:22:34 +0000150 void GetExtentOfArgList(const char *Name, const char *&LParen, const char *&RParen);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000151};
Mike Stump1eb44332009-09-09 15:08:12 +0000152
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000153}
154
155static bool IsHeaderFile(const std::string &Filename) {
156 std::string::size_type DotPos = Filename.rfind('.');
Mike Stump1eb44332009-09-09 15:08:12 +0000157
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000158 if (DotPos == std::string::npos) {
159 // no file extension
Mike Stump1eb44332009-09-09 15:08:12 +0000160 return false;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000161 }
Mike Stump1eb44332009-09-09 15:08:12 +0000162
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000163 std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end());
164 // C header: .h
165 // C++ header: .hh or .H;
166 return Ext == "h" || Ext == "hh" || Ext == "H";
Mike Stump1eb44332009-09-09 15:08:12 +0000167}
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000168
Eli Friedman66d6f042009-05-18 22:20:00 +0000169RewriteBlocks::RewriteBlocks(std::string inFile,
Mike Stump1eb44332009-09-09 15:08:12 +0000170 Diagnostic &D, const LangOptions &LOpts) :
Steve Naroff13188952008-09-18 14:10:13 +0000171 Diags(D), LangOpts(LOpts) {
172 IsHeader = IsHeaderFile(inFile);
Steve Naroff13188952008-09-18 14:10:13 +0000173 CurFunctionDef = 0;
174 CurMethodDef = 0;
Mike Stump1eb44332009-09-09 15:08:12 +0000175 RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
Steve Naroff13188952008-09-18 14:10:13 +0000176 "rewriting failed");
Steve Naroff13188952008-09-18 14:10:13 +0000177}
178
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000179ASTConsumer *clang::CreateBlockRewriter(const std::string& InFile,
180 Diagnostic &Diags,
181 const LangOptions &LangOpts) {
Eli Friedman66d6f042009-05-18 22:20:00 +0000182 return new RewriteBlocks(InFile, Diags, LangOpts);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000183}
184
185void RewriteBlocks::Initialize(ASTContext &context) {
186 Context = &context;
187 SM = &Context->getSourceManager();
Mike Stump1eb44332009-09-09 15:08:12 +0000188
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000189 // Get the ID and start/end of the main file.
190 MainFileID = SM->getMainFileID();
191 const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID);
192 MainFileStart = MainBuf->getBufferStart();
193 MainFileEnd = MainBuf->getBufferEnd();
Mike Stump1eb44332009-09-09 15:08:12 +0000194
Chris Lattner2c78b872009-04-14 23:22:57 +0000195 Rewrite.setSourceMgr(Context->getSourceManager(), LangOpts);
Mike Stump1eb44332009-09-09 15:08:12 +0000196
Steve Naroffa0b75cf2008-10-02 23:30:43 +0000197 if (IsHeader)
198 Preamble = "#pragma once\n";
199 Preamble += "#ifndef BLOCK_IMPL\n";
200 Preamble += "#define BLOCK_IMPL\n";
201 Preamble += "struct __block_impl {\n";
202 Preamble += " void *isa;\n";
203 Preamble += " int Flags;\n";
204 Preamble += " int Size;\n";
205 Preamble += " void *FuncPtr;\n";
206 Preamble += "};\n";
207 Preamble += "enum {\n";
208 Preamble += " BLOCK_HAS_COPY_DISPOSE = (1<<25),\n";
209 Preamble += " BLOCK_IS_GLOBAL = (1<<28)\n";
210 Preamble += "};\n";
Mike Stump1eb44332009-09-09 15:08:12 +0000211 if (LangOpts.Microsoft)
Steve Naroffa0b75cf2008-10-02 23:30:43 +0000212 Preamble += "#define __OBJC_RW_EXTERN extern \"C\" __declspec(dllimport)\n";
213 else
214 Preamble += "#define __OBJC_RW_EXTERN extern\n";
215 Preamble += "// Runtime copy/destroy helper functions\n";
216 Preamble += "__OBJC_RW_EXTERN void _Block_copy_assign(void *, void *);\n";
217 Preamble += "__OBJC_RW_EXTERN void _Block_byref_assign_copy(void *, void *);\n";
218 Preamble += "__OBJC_RW_EXTERN void _Block_destroy(void *);\n";
219 Preamble += "__OBJC_RW_EXTERN void _Block_byref_release(void *);\n";
Steve Naroff48a8c612008-10-03 12:09:49 +0000220 Preamble += "__OBJC_RW_EXTERN void *_NSConcreteGlobalBlock;\n";
221 Preamble += "__OBJC_RW_EXTERN void *_NSConcreteStackBlock;\n";
Steve Naroffa0b75cf2008-10-02 23:30:43 +0000222 Preamble += "#endif\n";
Mike Stump1eb44332009-09-09 15:08:12 +0000223
224 InsertText(SM->getLocForStartOfFile(MainFileID),
Steve Naroffa0b75cf2008-10-02 23:30:43 +0000225 Preamble.c_str(), Preamble.size());
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000226}
227
Mike Stump1eb44332009-09-09 15:08:12 +0000228void RewriteBlocks::InsertText(SourceLocation Loc, const char *StrData,
229 unsigned StrLen) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000230 if (!Rewrite.InsertText(Loc, StrData, StrLen))
231 return;
232 Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag);
233}
234
235void RewriteBlocks::ReplaceText(SourceLocation Start, unsigned OrigLength,
236 const char *NewStr, unsigned NewLength) {
Daniel Dunbard7407dc2009-08-19 19:10:30 +0000237 if (!Rewrite.ReplaceText(Start, OrigLength,
238 llvm::StringRef(NewStr, NewLength)))
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000239 return;
240 Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag);
241}
242
243void RewriteBlocks::RewriteMethodDecl(ObjCMethodDecl *Method) {
244 bool haveBlockPtrs = false;
Mike Stump1eb44332009-09-09 15:08:12 +0000245 for (ObjCMethodDecl::param_iterator I = Method->param_begin(),
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000246 E = Method->param_end(); I != E; ++I)
247 if (isBlockPointerType((*I)->getType()))
248 haveBlockPtrs = true;
Mike Stump1eb44332009-09-09 15:08:12 +0000249
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000250 if (!haveBlockPtrs)
251 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000252
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000253 // Do a fuzzy rewrite.
254 // We have 1 or more arguments that have closure pointers.
255 SourceLocation Loc = Method->getLocStart();
256 SourceLocation LocEnd = Method->getLocEnd();
257 const char *startBuf = SM->getCharacterData(Loc);
258 const char *endBuf = SM->getCharacterData(LocEnd);
259
260 const char *methodPtr = startBuf;
Steve Naroff8af6a452008-10-02 17:12:56 +0000261 std::string Tag = "struct __block_impl *";
Mike Stump1eb44332009-09-09 15:08:12 +0000262
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000263 while (*methodPtr++ && (methodPtr != endBuf)) {
264 switch (*methodPtr) {
265 case ':':
266 methodPtr++;
267 if (*methodPtr == '(') {
268 const char *scanType = ++methodPtr;
269 bool foundBlockPointer = false;
270 unsigned parenCount = 1;
Mike Stump1eb44332009-09-09 15:08:12 +0000271
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000272 while (parenCount) {
273 switch (*scanType) {
Mike Stump1eb44332009-09-09 15:08:12 +0000274 case '(':
275 parenCount++;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000276 break;
Mike Stump1eb44332009-09-09 15:08:12 +0000277 case ')':
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000278 parenCount--;
279 break;
280 case '^':
281 foundBlockPointer = true;
282 break;
283 }
284 scanType++;
285 }
286 if (foundBlockPointer) {
287 // advance the location to startArgList.
288 Loc = Loc.getFileLocWithOffset(methodPtr-startBuf);
289 assert((Loc.isValid()) && "Invalid Loc");
290 ReplaceText(Loc, scanType-methodPtr-1, Tag.c_str(), Tag.size());
Mike Stump1eb44332009-09-09 15:08:12 +0000291
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000292 // Advance startBuf. Since the underlying buffer has changed,
293 // it's very important to advance startBuf (so we can correctly
294 // compute a relative Loc the next time around).
295 startBuf = methodPtr;
296 }
297 // Advance the method ptr to the end of the type.
298 methodPtr = scanType;
299 }
300 break;
301 }
302 }
303 return;
304}
305
306void RewriteBlocks::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
Mike Stump1eb44332009-09-09 15:08:12 +0000307 for (ObjCInterfaceDecl::instmeth_iterator
308 I = ClassDecl->instmeth_begin(), E = ClassDecl->instmeth_end();
Douglas Gregor6ab35242009-04-09 21:40:53 +0000309 I != E; ++I)
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000310 RewriteMethodDecl(*I);
Mike Stump1eb44332009-09-09 15:08:12 +0000311 for (ObjCInterfaceDecl::classmeth_iterator
Argyrios Kyrtzidis17945a02009-06-30 02:36:12 +0000312 I = ClassDecl->classmeth_begin(), E = ClassDecl->classmeth_end();
Douglas Gregor6ab35242009-04-09 21:40:53 +0000313 I != E; ++I)
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000314 RewriteMethodDecl(*I);
315}
316
317void RewriteBlocks::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
Mike Stump1eb44332009-09-09 15:08:12 +0000318 for (ObjCCategoryDecl::instmeth_iterator
319 I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end();
Douglas Gregor6ab35242009-04-09 21:40:53 +0000320 I != E; ++I)
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000321 RewriteMethodDecl(*I);
Mike Stump1eb44332009-09-09 15:08:12 +0000322 for (ObjCCategoryDecl::classmeth_iterator
Argyrios Kyrtzidis17945a02009-06-30 02:36:12 +0000323 I = CatDecl->classmeth_begin(), E = CatDecl->classmeth_end();
Douglas Gregor6ab35242009-04-09 21:40:53 +0000324 I != E; ++I)
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000325 RewriteMethodDecl(*I);
326}
327
328void RewriteBlocks::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
Mike Stump1eb44332009-09-09 15:08:12 +0000329 for (ObjCProtocolDecl::instmeth_iterator
330 I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
Douglas Gregor6ab35242009-04-09 21:40:53 +0000331 I != E; ++I)
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000332 RewriteMethodDecl(*I);
Mike Stump1eb44332009-09-09 15:08:12 +0000333 for (ObjCProtocolDecl::classmeth_iterator
334 I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();
Douglas Gregor6ab35242009-04-09 21:40:53 +0000335 I != E; ++I)
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000336 RewriteMethodDecl(*I);
337}
338
339//===----------------------------------------------------------------------===//
340// Top Level Driver Code
341//===----------------------------------------------------------------------===//
342
Chris Lattner682bf922009-03-29 16:50:03 +0000343void RewriteBlocks::HandleTopLevelSingleDecl(Decl *D) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000344 // Two cases: either the decl could be in the main file, or it could be in a
345 // #included file. If the former, rewrite it now. If the later, check to see
346 // if we rewrote the #include/#import.
347 SourceLocation Loc = D->getLocation();
Chris Lattnerf7cf85b2009-01-16 07:36:28 +0000348 Loc = SM->getInstantiationLoc(Loc);
Mike Stump1eb44332009-09-09 15:08:12 +0000349
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000350 // If this is for a builtin, ignore it.
351 if (Loc.isInvalid()) return;
Mike Stump1eb44332009-09-09 15:08:12 +0000352
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000353 if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D))
354 RewriteInterfaceDecl(MD);
355 else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D))
356 RewriteCategoryDecl(CD);
357 else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
358 RewriteProtocolDecl(PD);
359
360 // If we have a decl in the main file, see if we should rewrite it.
Chris Lattner23f2c582009-01-25 22:02:19 +0000361 if (SM->isFromMainFile(Loc))
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000362 HandleDeclInMainFile(D);
363 return;
364}
365
366std::string RewriteBlocks::SynthesizeBlockFunc(BlockExpr *CE, int i,
367 const char *funcName,
368 std::string Tag) {
369 const FunctionType *AFT = CE->getFunctionType();
370 QualType RT = AFT->getResultType();
Steve Naroff48a8c612008-10-03 12:09:49 +0000371 std::string StructRef = "struct " + Tag;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000372 std::string S = "static " + RT.getAsString() + " __" +
Steve Naroffa0b75cf2008-10-02 23:30:43 +0000373 funcName + "_" + "block_func_" + utostr(i);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000374
Steve Naroff56ee6892008-10-08 17:01:13 +0000375 BlockDecl *BD = CE->getBlockDecl();
Mike Stump1eb44332009-09-09 15:08:12 +0000376
Douglas Gregor72564e72009-02-26 23:50:07 +0000377 if (isa<FunctionNoProtoType>(AFT)) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000378 S += "()";
Steve Naroff56ee6892008-10-08 17:01:13 +0000379 } else if (BD->param_empty()) {
Steve Naroff48a8c612008-10-03 12:09:49 +0000380 S += "(" + StructRef + " *__cself)";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000381 } else {
Douglas Gregor72564e72009-02-26 23:50:07 +0000382 const FunctionProtoType *FT = cast<FunctionProtoType>(AFT);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000383 assert(FT && "SynthesizeBlockFunc: No function proto");
384 S += '(';
385 // first add the implicit argument.
Steve Naroff48a8c612008-10-03 12:09:49 +0000386 S += StructRef + " *__cself, ";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000387 std::string ParamStr;
Steve Naroff56ee6892008-10-08 17:01:13 +0000388 for (BlockDecl::param_iterator AI = BD->param_begin(),
389 E = BD->param_end(); AI != E; ++AI) {
390 if (AI != BD->param_begin()) S += ", ";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000391 ParamStr = (*AI)->getNameAsString();
Douglas Gregord249e1d1f2009-05-29 20:38:28 +0000392 (*AI)->getType().getAsStringInternal(ParamStr, Context->PrintingPolicy);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000393 S += ParamStr;
394 }
395 if (FT->isVariadic()) {
Steve Naroff56ee6892008-10-08 17:01:13 +0000396 if (!BD->param_empty()) S += ", ";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000397 S += "...";
398 }
399 S += ')';
400 }
401 S += " {\n";
Mike Stump1eb44332009-09-09 15:08:12 +0000402
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000403 // Create local declarations to avoid rewriting all closure decl ref exprs.
404 // First, emit a declaration for all "by ref" decls.
Mike Stump1eb44332009-09-09 15:08:12 +0000405 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000406 E = BlockByRefDecls.end(); I != E; ++I) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000407 S += " ";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000408 std::string Name = (*I)->getNameAsString();
Douglas Gregord249e1d1f2009-05-29 20:38:28 +0000409 Context->getPointerType((*I)->getType()).getAsStringInternal(Name,
410 Context->PrintingPolicy);
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000411 S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
Mike Stump1eb44332009-09-09 15:08:12 +0000412 }
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000413 // Next, emit a declaration for all "by copy" declarations.
Mike Stump1eb44332009-09-09 15:08:12 +0000414 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000415 E = BlockByCopyDecls.end(); I != E; ++I) {
416 S += " ";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000417 std::string Name = (*I)->getNameAsString();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000418 // Handle nested closure invocation. For example:
419 //
420 // void (^myImportedClosure)(void);
421 // myImportedClosure = ^(void) { setGlobalInt(x + y); };
Mike Stump1eb44332009-09-09 15:08:12 +0000422 //
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000423 // void (^anotherClosure)(void);
424 // anotherClosure = ^(void) {
425 // myImportedClosure(); // import and invoke the closure
426 // };
427 //
428 if (isBlockPointerType((*I)->getType()))
Steve Naroff8af6a452008-10-02 17:12:56 +0000429 S += "struct __block_impl *";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000430 else
Douglas Gregord249e1d1f2009-05-29 20:38:28 +0000431 (*I)->getType().getAsStringInternal(Name, Context->PrintingPolicy);
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000432 S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by copy\n";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000433 }
Steve Naroff70f95502008-10-04 17:06:23 +0000434 std::string RewrittenStr = RewrittenBlockExprs[CE];
435 const char *cstr = RewrittenStr.c_str();
436 while (*cstr++ != '{') ;
437 S += cstr;
438 S += "\n";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000439 return S;
440}
441
Steve Naroff4e13b762008-10-03 20:28:15 +0000442std::string RewriteBlocks::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
443 const char *funcName,
444 std::string Tag) {
445 std::string StructRef = "struct " + Tag;
446 std::string S = "static void __";
Mike Stump1eb44332009-09-09 15:08:12 +0000447
Steve Naroff4e13b762008-10-03 20:28:15 +0000448 S += funcName;
449 S += "_block_copy_" + utostr(i);
450 S += "(" + StructRef;
451 S += "*dst, " + StructRef;
452 S += "*src) {";
Mike Stump1eb44332009-09-09 15:08:12 +0000453 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
Steve Naroff4e13b762008-10-03 20:28:15 +0000454 E = ImportedBlockDecls.end(); I != E; ++I) {
455 S += "_Block_copy_assign(&dst->";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000456 S += (*I)->getNameAsString();
Steve Naroff4e13b762008-10-03 20:28:15 +0000457 S += ", src->";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000458 S += (*I)->getNameAsString();
Steve Naroff4e13b762008-10-03 20:28:15 +0000459 S += ");}";
460 }
461 S += "\nstatic void __";
462 S += funcName;
463 S += "_block_dispose_" + utostr(i);
464 S += "(" + StructRef;
465 S += "*src) {";
Mike Stump1eb44332009-09-09 15:08:12 +0000466 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
Steve Naroff4e13b762008-10-03 20:28:15 +0000467 E = ImportedBlockDecls.end(); I != E; ++I) {
468 S += "_Block_destroy(src->";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000469 S += (*I)->getNameAsString();
Steve Naroff4e13b762008-10-03 20:28:15 +0000470 S += ");";
471 }
Mike Stump1eb44332009-09-09 15:08:12 +0000472 S += "}\n";
Steve Naroff4e13b762008-10-03 20:28:15 +0000473 return S;
474}
475
Steve Naroffacba0f22008-10-04 23:47:37 +0000476std::string RewriteBlocks::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
477 bool hasCopyDisposeHelpers) {
Steve Naroff48a8c612008-10-03 12:09:49 +0000478 std::string S = "struct " + Tag;
479 std::string Constructor = " " + Tag;
Mike Stump1eb44332009-09-09 15:08:12 +0000480
Steve Naroff48a8c612008-10-03 12:09:49 +0000481 S += " {\n struct __block_impl impl;\n";
Mike Stump1eb44332009-09-09 15:08:12 +0000482
Steve Naroffacba0f22008-10-04 23:47:37 +0000483 if (hasCopyDisposeHelpers)
484 S += " void *copy;\n void *dispose;\n";
Mike Stump1eb44332009-09-09 15:08:12 +0000485
Steve Naroff48a8c612008-10-03 12:09:49 +0000486 Constructor += "(void *fp";
Mike Stump1eb44332009-09-09 15:08:12 +0000487
Steve Naroffacba0f22008-10-04 23:47:37 +0000488 if (hasCopyDisposeHelpers)
489 Constructor += ", void *copyHelp, void *disposeHelp";
Mike Stump1eb44332009-09-09 15:08:12 +0000490
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000491 if (BlockDeclRefs.size()) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000492 // Output all "by copy" declarations.
Mike Stump1eb44332009-09-09 15:08:12 +0000493 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000494 E = BlockByCopyDecls.end(); I != E; ++I) {
495 S += " ";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000496 std::string FieldName = (*I)->getNameAsString();
Steve Naroff4e13b762008-10-03 20:28:15 +0000497 std::string ArgName = "_" + FieldName;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000498 // Handle nested closure invocation. For example:
499 //
500 // void (^myImportedBlock)(void);
501 // myImportedBlock = ^(void) { setGlobalInt(x + y); };
Mike Stump1eb44332009-09-09 15:08:12 +0000502 //
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000503 // void (^anotherBlock)(void);
504 // anotherBlock = ^(void) {
505 // myImportedBlock(); // import and invoke the closure
506 // };
507 //
Steve Naroff4e13b762008-10-03 20:28:15 +0000508 if (isBlockPointerType((*I)->getType())) {
Steve Naroff8af6a452008-10-02 17:12:56 +0000509 S += "struct __block_impl *";
Steve Naroff4e13b762008-10-03 20:28:15 +0000510 Constructor += ", void *" + ArgName;
511 } else {
Douglas Gregord249e1d1f2009-05-29 20:38:28 +0000512 (*I)->getType().getAsStringInternal(FieldName, Context->PrintingPolicy);
513 (*I)->getType().getAsStringInternal(ArgName, Context->PrintingPolicy);
Steve Naroff4e13b762008-10-03 20:28:15 +0000514 Constructor += ", " + ArgName;
Steve Naroff48a8c612008-10-03 12:09:49 +0000515 }
Steve Naroff4e13b762008-10-03 20:28:15 +0000516 S += FieldName + ";\n";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000517 }
518 // Output all "by ref" declarations.
Mike Stump1eb44332009-09-09 15:08:12 +0000519 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000520 E = BlockByRefDecls.end(); I != E; ++I) {
521 S += " ";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000522 std::string FieldName = (*I)->getNameAsString();
Steve Naroff4e13b762008-10-03 20:28:15 +0000523 std::string ArgName = "_" + FieldName;
524 // Handle nested closure invocation. For example:
525 //
526 // void (^myImportedBlock)(void);
527 // myImportedBlock = ^(void) { setGlobalInt(x + y); };
Mike Stump1eb44332009-09-09 15:08:12 +0000528 //
Steve Naroff4e13b762008-10-03 20:28:15 +0000529 // void (^anotherBlock)(void);
530 // anotherBlock = ^(void) {
531 // myImportedBlock(); // import and invoke the closure
532 // };
533 //
534 if (isBlockPointerType((*I)->getType())) {
Steve Naroff8af6a452008-10-02 17:12:56 +0000535 S += "struct __block_impl *";
Steve Naroff4e13b762008-10-03 20:28:15 +0000536 Constructor += ", void *" + ArgName;
537 } else {
Douglas Gregord249e1d1f2009-05-29 20:38:28 +0000538 Context->getPointerType((*I)->getType()).getAsStringInternal(FieldName,
539 Context->PrintingPolicy);
540 Context->getPointerType((*I)->getType()).getAsStringInternal(ArgName,
541 Context->PrintingPolicy);
Steve Naroff4e13b762008-10-03 20:28:15 +0000542 Constructor += ", " + ArgName;
Steve Naroff48a8c612008-10-03 12:09:49 +0000543 }
Steve Naroff4e13b762008-10-03 20:28:15 +0000544 S += FieldName + "; // by ref\n";
Steve Naroff48a8c612008-10-03 12:09:49 +0000545 }
546 // Finish writing the constructor.
547 // FIXME: handle NSConcreteGlobalBlock.
548 Constructor += ", int flags=0) {\n";
Steve Naroff83ba14e2008-10-03 15:04:50 +0000549 Constructor += " impl.isa = 0/*&_NSConcreteStackBlock*/;\n impl.Size = sizeof(";
Steve Naroff48a8c612008-10-03 12:09:49 +0000550 Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
Mike Stump1eb44332009-09-09 15:08:12 +0000551
Steve Naroffacba0f22008-10-04 23:47:37 +0000552 if (hasCopyDisposeHelpers)
553 Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n";
Mike Stump1eb44332009-09-09 15:08:12 +0000554
Steve Naroff48a8c612008-10-03 12:09:49 +0000555 // Initialize all "by copy" arguments.
Mike Stump1eb44332009-09-09 15:08:12 +0000556 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
Steve Naroff48a8c612008-10-03 12:09:49 +0000557 E = BlockByCopyDecls.end(); I != E; ++I) {
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000558 std::string Name = (*I)->getNameAsString();
Steve Naroff48a8c612008-10-03 12:09:49 +0000559 Constructor += " ";
Steve Naroff4e13b762008-10-03 20:28:15 +0000560 if (isBlockPointerType((*I)->getType()))
561 Constructor += Name + " = (struct __block_impl *)_";
562 else
563 Constructor += Name + " = _";
Steve Naroff48a8c612008-10-03 12:09:49 +0000564 Constructor += Name + ";\n";
565 }
566 // Initialize all "by ref" arguments.
Mike Stump1eb44332009-09-09 15:08:12 +0000567 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
Steve Naroff48a8c612008-10-03 12:09:49 +0000568 E = BlockByRefDecls.end(); I != E; ++I) {
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000569 std::string Name = (*I)->getNameAsString();
Steve Naroff48a8c612008-10-03 12:09:49 +0000570 Constructor += " ";
Steve Naroff4e13b762008-10-03 20:28:15 +0000571 if (isBlockPointerType((*I)->getType()))
572 Constructor += Name + " = (struct __block_impl *)_";
573 else
574 Constructor += Name + " = _";
Steve Naroff48a8c612008-10-03 12:09:49 +0000575 Constructor += Name + ";\n";
576 }
Steve Naroff83ba14e2008-10-03 15:04:50 +0000577 } else {
578 // Finish writing the constructor.
579 // FIXME: handle NSConcreteGlobalBlock.
580 Constructor += ", int flags=0) {\n";
581 Constructor += " impl.isa = 0/*&_NSConcreteStackBlock*/;\n impl.Size = sizeof(";
582 Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
Steve Naroffacba0f22008-10-04 23:47:37 +0000583 if (hasCopyDisposeHelpers)
584 Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000585 }
Steve Naroff83ba14e2008-10-03 15:04:50 +0000586 Constructor += " ";
587 Constructor += "}\n";
588 S += Constructor;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000589 S += "};\n";
590 return S;
591}
592
593void RewriteBlocks::SynthesizeBlockLiterals(SourceLocation FunLocStart,
594 const char *FunName) {
595 // Insert closures that were part of the function.
596 for (unsigned i = 0; i < Blocks.size(); i++) {
Steve Naroffacba0f22008-10-04 23:47:37 +0000597
Steve Naroffd3f77902008-10-05 00:06:12 +0000598 CollectBlockDeclRefInfo(Blocks[i]);
599
Steve Naroff48a8c612008-10-03 12:09:49 +0000600 std::string Tag = "__" + std::string(FunName) + "_block_impl_" + utostr(i);
Mike Stump1eb44332009-09-09 15:08:12 +0000601
602 std::string CI = SynthesizeBlockImpl(Blocks[i], Tag,
Steve Naroffacba0f22008-10-04 23:47:37 +0000603 ImportedBlockDecls.size() > 0);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000604
605 InsertText(FunLocStart, CI.c_str(), CI.size());
Steve Naroff4e13b762008-10-03 20:28:15 +0000606
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000607 std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, Tag);
Mike Stump1eb44332009-09-09 15:08:12 +0000608
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000609 InsertText(FunLocStart, CF.c_str(), CF.size());
610
Steve Naroff4e13b762008-10-03 20:28:15 +0000611 if (ImportedBlockDecls.size()) {
612 std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, Tag);
613 InsertText(FunLocStart, HF.c_str(), HF.size());
614 }
Mike Stump1eb44332009-09-09 15:08:12 +0000615
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000616 BlockDeclRefs.clear();
617 BlockByRefDecls.clear();
618 BlockByCopyDecls.clear();
619 BlockCallExprs.clear();
Steve Naroff4e13b762008-10-03 20:28:15 +0000620 ImportedBlockDecls.clear();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000621 }
622 Blocks.clear();
Steve Naroff8e9216d2008-10-04 17:10:02 +0000623 RewrittenBlockExprs.clear();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000624}
625
626void RewriteBlocks::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {
Steve Naroff3ad29e22008-10-03 00:12:09 +0000627 SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
Chris Lattner8ec03f52008-11-24 03:54:41 +0000628 const char *FuncName = FD->getNameAsCString();
Mike Stump1eb44332009-09-09 15:08:12 +0000629
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000630 SynthesizeBlockLiterals(FunLocStart, FuncName);
631}
632
633void RewriteBlocks::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
634 SourceLocation FunLocStart = MD->getLocStart();
Chris Lattner077bf5e2008-11-24 03:33:13 +0000635 std::string FuncName = MD->getSelector().getAsString();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000636 // Convert colons to underscores.
637 std::string::size_type loc = 0;
638 while ((loc = FuncName.find(":", loc)) != std::string::npos)
639 FuncName.replace(loc, 1, "_");
Mike Stump1eb44332009-09-09 15:08:12 +0000640
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000641 SynthesizeBlockLiterals(FunLocStart, FuncName.c_str());
642}
643
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000644void RewriteBlocks::GetBlockDeclRefExprs(Stmt *S) {
645 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
646 CI != E; ++CI)
Steve Naroff84a969f2008-10-08 17:31:13 +0000647 if (*CI) {
648 if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI))
649 GetBlockDeclRefExprs(CBE->getBody());
650 else
651 GetBlockDeclRefExprs(*CI);
652 }
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000653 // Handle specific things.
654 if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S))
655 // FIXME: Handle enums.
656 if (!isa<FunctionDecl>(CDRE->getDecl()))
657 BlockDeclRefs.push_back(CDRE);
658 return;
659}
660
661void RewriteBlocks::GetBlockCallExprs(Stmt *S) {
662 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
663 CI != E; ++CI)
Steve Naroff84a969f2008-10-08 17:31:13 +0000664 if (*CI) {
665 if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI))
666 GetBlockCallExprs(CBE->getBody());
667 else
668 GetBlockCallExprs(*CI);
669 }
Mike Stump1eb44332009-09-09 15:08:12 +0000670
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000671 if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
Steve Naroff4e13b762008-10-03 20:28:15 +0000672 if (CE->getCallee()->getType()->isBlockPointerType()) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000673 BlockCallExprs[dyn_cast<BlockDeclRefExpr>(CE->getCallee())] = CE;
Steve Naroff4e13b762008-10-03 20:28:15 +0000674 }
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000675 }
676 return;
677}
678
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000679std::string RewriteBlocks::SynthesizeBlockCall(CallExpr *Exp) {
680 // Navigate to relevant type information.
Steve Naroffcc2ece22008-09-24 22:46:45 +0000681 const char *closureName = 0;
682 const BlockPointerType *CPT = 0;
Mike Stump1eb44332009-09-09 15:08:12 +0000683
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000684 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp->getCallee())) {
Chris Lattner8ec03f52008-11-24 03:54:41 +0000685 closureName = DRE->getDecl()->getNameAsCString();
Ted Kremenek6217b802009-07-29 21:53:49 +0000686 CPT = DRE->getType()->getAs<BlockPointerType>();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000687 } else if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(Exp->getCallee())) {
Chris Lattner8ec03f52008-11-24 03:54:41 +0000688 closureName = CDRE->getDecl()->getNameAsCString();
Ted Kremenek6217b802009-07-29 21:53:49 +0000689 CPT = CDRE->getType()->getAs<BlockPointerType>();
Steve Naroff83ba14e2008-10-03 15:04:50 +0000690 } else if (MemberExpr *MExpr = dyn_cast<MemberExpr>(Exp->getCallee())) {
Chris Lattner8ec03f52008-11-24 03:54:41 +0000691 closureName = MExpr->getMemberDecl()->getNameAsCString();
Ted Kremenek6217b802009-07-29 21:53:49 +0000692 CPT = MExpr->getType()->getAs<BlockPointerType>();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000693 } else {
694 assert(1 && "RewriteBlockClass: Bad type");
695 }
696 assert(CPT && "RewriteBlockClass: Bad type");
John McCall183700f2009-09-21 23:43:11 +0000697 const FunctionType *FT = CPT->getPointeeType()->getAs<FunctionType>();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000698 assert(FT && "RewriteBlockClass: Bad type");
Douglas Gregor72564e72009-02-26 23:50:07 +0000699 const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000700 // FTP will be null for closures that don't take arguments.
Mike Stump1eb44332009-09-09 15:08:12 +0000701
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000702 // Build a closure call - start with a paren expr to enforce precedence.
703 std::string BlockCall = "(";
704
Mike Stump1eb44332009-09-09 15:08:12 +0000705 // Synthesize the cast.
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000706 BlockCall += "(" + Exp->getType().getAsString() + "(*)";
Steve Naroff8af6a452008-10-02 17:12:56 +0000707 BlockCall += "(struct __block_impl *";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000708 if (FTP) {
Mike Stump1eb44332009-09-09 15:08:12 +0000709 for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000710 E = FTP->arg_type_end(); I && (I != E); ++I)
711 BlockCall += ", " + (*I).getAsString();
712 }
713 BlockCall += "))"; // close the argument list and paren expression.
Mike Stump1eb44332009-09-09 15:08:12 +0000714
Steve Naroff83ba14e2008-10-03 15:04:50 +0000715 // Invoke the closure. We need to cast it since the declaration type is
716 // bogus (it's a function pointer type)
717 BlockCall += "((struct __block_impl *)";
718 std::string closureExprBufStr;
719 llvm::raw_string_ostream closureExprBuf(closureExprBufStr);
Chris Lattnere4f21422009-06-30 01:26:17 +0000720 Exp->getCallee()->printPretty(closureExprBuf, *Context, 0,
721 PrintingPolicy(LangOpts));
Steve Naroff83ba14e2008-10-03 15:04:50 +0000722 BlockCall += closureExprBuf.str();
723 BlockCall += ")->FuncPtr)";
Mike Stump1eb44332009-09-09 15:08:12 +0000724
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000725 // Add the arguments.
Steve Naroff83ba14e2008-10-03 15:04:50 +0000726 BlockCall += "((struct __block_impl *)";
Steve Naroffb65a4f12008-10-04 17:45:51 +0000727 BlockCall += closureExprBuf.str();
Mike Stump1eb44332009-09-09 15:08:12 +0000728 for (CallExpr::arg_iterator I = Exp->arg_begin(),
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000729 E = Exp->arg_end(); I != E; ++I) {
730 std::string syncExprBufS;
731 llvm::raw_string_ostream Buf(syncExprBufS);
Chris Lattnere4f21422009-06-30 01:26:17 +0000732 (*I)->printPretty(Buf, *Context, 0, PrintingPolicy(LangOpts));
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000733 BlockCall += ", " + Buf.str();
734 }
735 return BlockCall;
736}
737
738void RewriteBlocks::RewriteBlockCall(CallExpr *Exp) {
739 std::string BlockCall = SynthesizeBlockCall(Exp);
Mike Stump1eb44332009-09-09 15:08:12 +0000740
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000741 const char *startBuf = SM->getCharacterData(Exp->getLocStart());
742 const char *endBuf = SM->getCharacterData(Exp->getLocEnd());
743
Mike Stump1eb44332009-09-09 15:08:12 +0000744 ReplaceText(Exp->getLocStart(), endBuf-startBuf,
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000745 BlockCall.c_str(), BlockCall.size());
746}
747
Steve Naroff5e52b172008-10-04 18:52:47 +0000748void RewriteBlocks::RewriteBlockDeclRefExpr(BlockDeclRefExpr *BDRE) {
749 // FIXME: Add more elaborate code generation required by the ABI.
750 InsertText(BDRE->getLocStart(), "*", 1);
751}
752
Steve Naroffca743602008-10-15 18:38:58 +0000753void RewriteBlocks::RewriteCastExpr(CastExpr *CE) {
754 SourceLocation LocStart = CE->getLocStart();
755 SourceLocation LocEnd = CE->getLocEnd();
Mike Stump1eb44332009-09-09 15:08:12 +0000756
Steve Naroff8f6ce572008-11-03 11:20:24 +0000757 if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd))
758 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000759
Steve Naroffca743602008-10-15 18:38:58 +0000760 const char *startBuf = SM->getCharacterData(LocStart);
761 const char *endBuf = SM->getCharacterData(LocEnd);
Mike Stump1eb44332009-09-09 15:08:12 +0000762
Steve Naroffca743602008-10-15 18:38:58 +0000763 // advance the location to startArgList.
764 const char *argPtr = startBuf;
Mike Stump1eb44332009-09-09 15:08:12 +0000765
Steve Naroffca743602008-10-15 18:38:58 +0000766 while (*argPtr++ && (argPtr < endBuf)) {
767 switch (*argPtr) {
Mike Stump1eb44332009-09-09 15:08:12 +0000768 case '^':
Steve Naroffca743602008-10-15 18:38:58 +0000769 // Replace the '^' with '*'.
770 LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf);
771 ReplaceText(LocStart, 1, "*", 1);
772 break;
773 }
774 }
775 return;
776}
777
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000778void RewriteBlocks::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {
779 SourceLocation DeclLoc = FD->getLocation();
Steve Naroffe0109a52008-10-10 15:33:34 +0000780 unsigned parenCount = 0;
Mike Stump1eb44332009-09-09 15:08:12 +0000781
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000782 // We have 1 or more arguments that have closure pointers.
783 const char *startBuf = SM->getCharacterData(DeclLoc);
784 const char *startArgList = strchr(startBuf, '(');
Mike Stump1eb44332009-09-09 15:08:12 +0000785
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000786 assert((*startArgList == '(') && "Rewriter fuzzy parser confused");
Mike Stump1eb44332009-09-09 15:08:12 +0000787
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000788 parenCount++;
789 // advance the location to startArgList.
Steve Naroffe0109a52008-10-10 15:33:34 +0000790 DeclLoc = DeclLoc.getFileLocWithOffset(startArgList-startBuf);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000791 assert((DeclLoc.isValid()) && "Invalid DeclLoc");
Mike Stump1eb44332009-09-09 15:08:12 +0000792
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000793 const char *argPtr = startArgList;
Mike Stump1eb44332009-09-09 15:08:12 +0000794
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000795 while (*argPtr++ && parenCount) {
796 switch (*argPtr) {
Mike Stump1eb44332009-09-09 15:08:12 +0000797 case '^':
Steve Naroffe0109a52008-10-10 15:33:34 +0000798 // Replace the '^' with '*'.
799 DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList);
800 ReplaceText(DeclLoc, 1, "*", 1);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000801 break;
Mike Stump1eb44332009-09-09 15:08:12 +0000802 case '(':
803 parenCount++;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000804 break;
Mike Stump1eb44332009-09-09 15:08:12 +0000805 case ')':
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000806 parenCount--;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000807 break;
808 }
809 }
810 return;
811}
812
Steve Naroffca743602008-10-15 18:38:58 +0000813bool RewriteBlocks::PointerTypeTakesAnyBlockArguments(QualType QT) {
Douglas Gregor72564e72009-02-26 23:50:07 +0000814 const FunctionProtoType *FTP;
Ted Kremenek6217b802009-07-29 21:53:49 +0000815 const PointerType *PT = QT->getAs<PointerType>();
Steve Naroffca743602008-10-15 18:38:58 +0000816 if (PT) {
John McCall183700f2009-09-21 23:43:11 +0000817 FTP = PT->getPointeeType()->getAs<FunctionProtoType>();
Steve Naroffca743602008-10-15 18:38:58 +0000818 } else {
Ted Kremenek6217b802009-07-29 21:53:49 +0000819 const BlockPointerType *BPT = QT->getAs<BlockPointerType>();
Steve Naroffca743602008-10-15 18:38:58 +0000820 assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");
John McCall183700f2009-09-21 23:43:11 +0000821 FTP = BPT->getPointeeType()->getAs<FunctionProtoType>();
Steve Naroffca743602008-10-15 18:38:58 +0000822 }
Steve Naroffeab5f632008-09-23 19:24:41 +0000823 if (FTP) {
Mike Stump1eb44332009-09-09 15:08:12 +0000824 for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
Steve Naroffeab5f632008-09-23 19:24:41 +0000825 E = FTP->arg_type_end(); I != E; ++I)
826 if (isBlockPointerType(*I))
827 return true;
828 }
829 return false;
830}
831
Mike Stump1eb44332009-09-09 15:08:12 +0000832void RewriteBlocks::GetExtentOfArgList(const char *Name,
Steve Naroff1f6c3ae2008-09-24 17:22:34 +0000833 const char *&LParen, const char *&RParen) {
834 const char *argPtr = strchr(Name, '(');
Steve Naroffeab5f632008-09-23 19:24:41 +0000835 assert((*argPtr == '(') && "Rewriter fuzzy parser confused");
Mike Stump1eb44332009-09-09 15:08:12 +0000836
Steve Naroffeab5f632008-09-23 19:24:41 +0000837 LParen = argPtr; // output the start.
838 argPtr++; // skip past the left paren.
839 unsigned parenCount = 1;
Mike Stump1eb44332009-09-09 15:08:12 +0000840
Steve Naroffeab5f632008-09-23 19:24:41 +0000841 while (*argPtr && parenCount) {
842 switch (*argPtr) {
843 case '(': parenCount++; break;
844 case ')': parenCount--; break;
845 default: break;
846 }
847 if (parenCount) argPtr++;
848 }
849 assert((*argPtr == ')') && "Rewriter fuzzy parser confused");
850 RParen = argPtr; // output the end
851}
852
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000853void RewriteBlocks::RewriteBlockPointerDecl(NamedDecl *ND) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000854 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
855 RewriteBlockPointerFunctionArgs(FD);
856 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000857 }
Steve Naroffca3bb4f2008-09-23 21:15:53 +0000858 // Handle Variables and Typedefs.
859 SourceLocation DeclLoc = ND->getLocation();
860 QualType DeclT;
861 if (VarDecl *VD = dyn_cast<VarDecl>(ND))
862 DeclT = VD->getType();
863 else if (TypedefDecl *TDD = dyn_cast<TypedefDecl>(ND))
864 DeclT = TDD->getUnderlyingType();
Steve Naroff83ba14e2008-10-03 15:04:50 +0000865 else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND))
866 DeclT = FD->getType();
Mike Stump1eb44332009-09-09 15:08:12 +0000867 else
Steve Naroffca3bb4f2008-09-23 21:15:53 +0000868 assert(0 && "RewriteBlockPointerDecl(): Decl type not yet handled");
Mike Stump1eb44332009-09-09 15:08:12 +0000869
Steve Naroffca3bb4f2008-09-23 21:15:53 +0000870 const char *startBuf = SM->getCharacterData(DeclLoc);
871 const char *endBuf = startBuf;
872 // scan backward (from the decl location) for the end of the previous decl.
873 while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart)
874 startBuf--;
Mike Stump1eb44332009-09-09 15:08:12 +0000875
Steve Naroffca743602008-10-15 18:38:58 +0000876 // *startBuf != '^' if we are dealing with a pointer to function that
877 // may take block argument types (which will be handled below).
878 if (*startBuf == '^') {
879 // Replace the '^' with '*', computing a negative offset.
880 DeclLoc = DeclLoc.getFileLocWithOffset(startBuf-endBuf);
881 ReplaceText(DeclLoc, 1, "*", 1);
882 }
883 if (PointerTypeTakesAnyBlockArguments(DeclT)) {
Steve Naroffca3bb4f2008-09-23 21:15:53 +0000884 // Replace the '^' with '*' for arguments.
885 DeclLoc = ND->getLocation();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000886 startBuf = SM->getCharacterData(DeclLoc);
Steve Naroff1f6c3ae2008-09-24 17:22:34 +0000887 const char *argListBegin, *argListEnd;
Steve Naroffca3bb4f2008-09-23 21:15:53 +0000888 GetExtentOfArgList(startBuf, argListBegin, argListEnd);
889 while (argListBegin < argListEnd) {
890 if (*argListBegin == '^') {
891 SourceLocation CaretLoc = DeclLoc.getFileLocWithOffset(argListBegin-startBuf);
892 ReplaceText(CaretLoc, 1, "*", 1);
893 }
894 argListBegin++;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000895 }
Steve Naroffeab5f632008-09-23 19:24:41 +0000896 }
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000897 return;
898}
899
Mike Stump1eb44332009-09-09 15:08:12 +0000900void RewriteBlocks::CollectBlockDeclRefInfo(BlockExpr *Exp) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000901 // Add initializers for any closure decl refs.
Steve Naroff84a969f2008-10-08 17:31:13 +0000902 GetBlockDeclRefExprs(Exp->getBody());
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000903 if (BlockDeclRefs.size()) {
904 // Unique all "by copy" declarations.
905 for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
906 if (!BlockDeclRefs[i]->isByRef())
907 BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl());
908 // Unique all "by ref" declarations.
909 for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
910 if (BlockDeclRefs[i]->isByRef()) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000911 BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl());
912 }
Steve Naroffacba0f22008-10-04 23:47:37 +0000913 // Find any imported blocks...they will need special attention.
914 for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
915 if (isBlockPointerType(BlockDeclRefs[i]->getType())) {
916 GetBlockCallExprs(Blocks[i]);
917 ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl());
918 }
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000919 }
Steve Naroffd3f77902008-10-05 00:06:12 +0000920}
921
922std::string RewriteBlocks::SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD) {
923 Blocks.push_back(Exp);
924
925 CollectBlockDeclRefInfo(Exp);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000926 std::string FuncName;
Mike Stump1eb44332009-09-09 15:08:12 +0000927
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000928 if (CurFunctionDef)
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000929 FuncName = std::string(CurFunctionDef->getNameAsString());
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000930 else if (CurMethodDef) {
Chris Lattner077bf5e2008-11-24 03:33:13 +0000931 FuncName = CurMethodDef->getSelector().getAsString();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000932 // Convert colons to underscores.
933 std::string::size_type loc = 0;
934 while ((loc = FuncName.find(":", loc)) != std::string::npos)
935 FuncName.replace(loc, 1, "_");
Steve Naroff39622b92008-10-03 15:38:09 +0000936 } else if (VD)
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000937 FuncName = std::string(VD->getNameAsString());
Mike Stump1eb44332009-09-09 15:08:12 +0000938
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000939 std::string BlockNumber = utostr(Blocks.size()-1);
Mike Stump1eb44332009-09-09 15:08:12 +0000940
Steve Naroff83ba14e2008-10-03 15:04:50 +0000941 std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber;
Steve Naroffa0b75cf2008-10-02 23:30:43 +0000942 std::string Func = "__" + FuncName + "_block_func_" + BlockNumber;
Mike Stump1eb44332009-09-09 15:08:12 +0000943
Steve Naroff83ba14e2008-10-03 15:04:50 +0000944 std::string FunkTypeStr;
Mike Stump1eb44332009-09-09 15:08:12 +0000945
Steve Naroff83ba14e2008-10-03 15:04:50 +0000946 // Get a pointer to the function type so we can cast appropriately.
Douglas Gregord249e1d1f2009-05-29 20:38:28 +0000947 Context->getPointerType(QualType(Exp->getFunctionType(),0))
948 .getAsStringInternal(FunkTypeStr, Context->PrintingPolicy);
Mike Stump1eb44332009-09-09 15:08:12 +0000949
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000950 // Rewrite the closure block with a compound literal. The first cast is
951 // to prevent warnings from the C compiler.
Steve Naroff83ba14e2008-10-03 15:04:50 +0000952 std::string Init = "(" + FunkTypeStr;
Mike Stump1eb44332009-09-09 15:08:12 +0000953
Steve Naroff83ba14e2008-10-03 15:04:50 +0000954 Init += ")&" + Tag;
Mike Stump1eb44332009-09-09 15:08:12 +0000955
Steve Naroff83ba14e2008-10-03 15:04:50 +0000956 // Initialize the block function.
957 Init += "((void*)" + Func;
Mike Stump1eb44332009-09-09 15:08:12 +0000958
Steve Naroffacba0f22008-10-04 23:47:37 +0000959 if (ImportedBlockDecls.size()) {
960 std::string Buf = "__" + FuncName + "_block_copy_" + BlockNumber;
961 Init += ",(void*)" + Buf;
962 Buf = "__" + FuncName + "_block_dispose_" + BlockNumber;
963 Init += ",(void*)" + Buf;
964 }
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000965 // Add initializers for any closure decl refs.
966 if (BlockDeclRefs.size()) {
967 // Output all "by copy" declarations.
Mike Stump1eb44332009-09-09 15:08:12 +0000968 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000969 E = BlockByCopyDecls.end(); I != E; ++I) {
970 Init += ",";
971 if (isObjCType((*I)->getType())) {
972 Init += "[[";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000973 Init += (*I)->getNameAsString();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000974 Init += " retain] autorelease]";
Steve Naroff4e13b762008-10-03 20:28:15 +0000975 } else if (isBlockPointerType((*I)->getType())) {
976 Init += "(void *)";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000977 Init += (*I)->getNameAsString();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000978 } else {
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000979 Init += (*I)->getNameAsString();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000980 }
981 }
982 // Output all "by ref" declarations.
Mike Stump1eb44332009-09-09 15:08:12 +0000983 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000984 E = BlockByRefDecls.end(); I != E; ++I) {
985 Init += ",&";
Chris Lattnerd9d22dd2008-11-24 05:29:24 +0000986 Init += (*I)->getNameAsString();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000987 }
988 }
Steve Naroff83ba14e2008-10-03 15:04:50 +0000989 Init += ")";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000990 BlockDeclRefs.clear();
991 BlockByRefDecls.clear();
992 BlockByCopyDecls.clear();
Steve Naroff4e13b762008-10-03 20:28:15 +0000993 ImportedBlockDecls.clear();
994
Steve Naroff70f95502008-10-04 17:06:23 +0000995 return Init;
996}
997
998//===----------------------------------------------------------------------===//
999// Function Body / Expression rewriting
1000//===----------------------------------------------------------------------===//
1001
1002Stmt *RewriteBlocks::RewriteFunctionBody(Stmt *S) {
1003 // Start by rewriting all children.
1004 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
1005 CI != E; ++CI)
1006 if (*CI) {
1007 if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) {
Eli Friedman687abff2009-06-08 04:24:21 +00001008 RewriteFunctionBody(CBE->getBody());
Mike Stump1eb44332009-09-09 15:08:12 +00001009
Steve Naroff70f95502008-10-04 17:06:23 +00001010 // We've just rewritten the block body in place.
1011 // Now we snarf the rewritten text and stash it away for later use.
1012 std::string S = Rewrite.getRewritenText(CBE->getSourceRange());
1013 RewrittenBlockExprs[CBE] = S;
1014 std::string Init = SynthesizeBlockInitExpr(CBE);
1015 // Do the rewrite, using S.size() which contains the rewritten size.
1016 ReplaceText(CBE->getLocStart(), S.size(), Init.c_str(), Init.size());
1017 } else {
Eli Friedman687abff2009-06-08 04:24:21 +00001018 RewriteFunctionBody(*CI);
Steve Naroff70f95502008-10-04 17:06:23 +00001019 }
1020 }
1021 // Handle specific things.
1022 if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
1023 if (CE->getCallee()->getType()->isBlockPointerType())
1024 RewriteBlockCall(CE);
1025 }
Steve Naroffca743602008-10-15 18:38:58 +00001026 if (CastExpr *CE = dyn_cast<CastExpr>(S)) {
1027 RewriteCastExpr(CE);
1028 }
Steve Naroff70f95502008-10-04 17:06:23 +00001029 if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
Ted Kremenekfda4fed2008-10-06 18:47:09 +00001030 for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
1031 DI != DE; ++DI) {
Mike Stump1eb44332009-09-09 15:08:12 +00001032
Douglas Gregor4afa39d2009-01-20 01:17:11 +00001033 Decl *SD = *DI;
Ted Kremenekfda4fed2008-10-06 18:47:09 +00001034 if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) {
1035 if (isBlockPointerType(ND->getType()))
1036 RewriteBlockPointerDecl(ND);
Mike Stump1eb44332009-09-09 15:08:12 +00001037 else if (ND->getType()->isFunctionPointerType())
Steve Naroffca743602008-10-15 18:38:58 +00001038 CheckFunctionPointerDecl(ND->getType(), ND);
Ted Kremenekfda4fed2008-10-06 18:47:09 +00001039 }
1040 if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
1041 if (isBlockPointerType(TD->getUnderlyingType()))
1042 RewriteBlockPointerDecl(TD);
Mike Stump1eb44332009-09-09 15:08:12 +00001043 else if (TD->getUnderlyingType()->isFunctionPointerType())
Steve Naroffca743602008-10-15 18:38:58 +00001044 CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
Ted Kremenekfda4fed2008-10-06 18:47:09 +00001045 }
Steve Naroff70f95502008-10-04 17:06:23 +00001046 }
1047 }
Steve Naroff5e52b172008-10-04 18:52:47 +00001048 // Handle specific things.
1049 if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
1050 if (BDRE->isByRef())
1051 RewriteBlockDeclRefExpr(BDRE);
1052 }
Steve Naroff70f95502008-10-04 17:06:23 +00001053 // Return this stmt unmodified.
1054 return S;
1055}
1056
Mike Stump1eb44332009-09-09 15:08:12 +00001057void RewriteBlocks::RewriteFunctionProtoType(QualType funcType, NamedDecl *D) {
Douglas Gregor72564e72009-02-26 23:50:07 +00001058 if (FunctionProtoType *fproto = dyn_cast<FunctionProtoType>(funcType)) {
Mike Stump1eb44332009-09-09 15:08:12 +00001059 for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(),
Steve Naroffca743602008-10-15 18:38:58 +00001060 E = fproto->arg_type_end(); I && (I != E); ++I)
1061 if (isBlockPointerType(*I)) {
1062 // All the args are checked/rewritten. Don't call twice!
1063 RewriteBlockPointerDecl(D);
1064 break;
1065 }
1066 }
1067}
1068
1069void RewriteBlocks::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) {
Ted Kremenek6217b802009-07-29 21:53:49 +00001070 const PointerType *PT = funcType->getAs<PointerType>();
Steve Naroffca743602008-10-15 18:38:58 +00001071 if (PT && PointerTypeTakesAnyBlockArguments(funcType))
Douglas Gregor72564e72009-02-26 23:50:07 +00001072 RewriteFunctionProtoType(PT->getPointeeType(), ND);
Steve Naroffca743602008-10-15 18:38:58 +00001073}
1074
Steve Naroff70f95502008-10-04 17:06:23 +00001075/// HandleDeclInMainFile - This is called for each top-level decl defined in the
1076/// main file of the input.
1077void RewriteBlocks::HandleDeclInMainFile(Decl *D) {
1078 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Steve Naroff70f95502008-10-04 17:06:23 +00001079 // Since function prototypes don't have ParmDecl's, we check the function
1080 // prototype. This enables us to rewrite function declarations and
1081 // definitions using the same code.
Douglas Gregor72564e72009-02-26 23:50:07 +00001082 RewriteFunctionProtoType(FD->getType(), FD);
Sebastian Redld3a413d2009-04-26 20:35:05 +00001083
1084 // FIXME: Handle CXXTryStmt
Argyrios Kyrtzidis6fb0aee2009-06-30 02:35:26 +00001085 if (CompoundStmt *Body = FD->getCompoundBody()) {
Steve Naroff70f95502008-10-04 17:06:23 +00001086 CurFunctionDef = FD;
Ted Kremenekeaab2062009-03-12 18:33:24 +00001087 FD->setBody(cast_or_null<CompoundStmt>(RewriteFunctionBody(Body)));
Steve Naroff70f95502008-10-04 17:06:23 +00001088 // This synthesizes and inserts the block "impl" struct, invoke function,
1089 // and any copy/dispose helper functions.
1090 InsertBlockLiteralsWithinFunction(FD);
1091 CurFunctionDef = 0;
Mike Stump1eb44332009-09-09 15:08:12 +00001092 }
Steve Naroff70f95502008-10-04 17:06:23 +00001093 return;
1094 }
1095 if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
1096 RewriteMethodDecl(MD);
Argyrios Kyrtzidis6fb0aee2009-06-30 02:35:26 +00001097 if (Stmt *Body = MD->getBody()) {
Steve Naroff70f95502008-10-04 17:06:23 +00001098 CurMethodDef = MD;
1099 RewriteFunctionBody(Body);
1100 InsertBlockLiteralsWithinMethod(MD);
1101 CurMethodDef = 0;
1102 }
1103 }
1104 if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
1105 if (isBlockPointerType(VD->getType())) {
1106 RewriteBlockPointerDecl(VD);
1107 if (VD->getInit()) {
1108 if (BlockExpr *CBE = dyn_cast<BlockExpr>(VD->getInit())) {
Argyrios Kyrtzidis6fb0aee2009-06-30 02:35:26 +00001109 RewriteFunctionBody(CBE->getBody());
Steve Naroff70f95502008-10-04 17:06:23 +00001110
1111 // We've just rewritten the block body in place.
1112 // Now we snarf the rewritten text and stash it away for later use.
1113 std::string S = Rewrite.getRewritenText(CBE->getSourceRange());
1114 RewrittenBlockExprs[CBE] = S;
1115 std::string Init = SynthesizeBlockInitExpr(CBE, VD);
1116 // Do the rewrite, using S.size() which contains the rewritten size.
1117 ReplaceText(CBE->getLocStart(), S.size(), Init.c_str(), Init.size());
Mike Stump1eb44332009-09-09 15:08:12 +00001118 SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(),
Chris Lattner8ec03f52008-11-24 03:54:41 +00001119 VD->getNameAsCString());
Steve Naroffca743602008-10-15 18:38:58 +00001120 } else if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) {
1121 RewriteCastExpr(CE);
1122 }
1123 }
1124 } else if (VD->getType()->isFunctionPointerType()) {
1125 CheckFunctionPointerDecl(VD->getType(), VD);
1126 if (VD->getInit()) {
1127 if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) {
1128 RewriteCastExpr(CE);
Steve Naroff70f95502008-10-04 17:06:23 +00001129 }
1130 }
1131 }
1132 return;
1133 }
1134 if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
1135 if (isBlockPointerType(TD->getUnderlyingType()))
1136 RewriteBlockPointerDecl(TD);
Mike Stump1eb44332009-09-09 15:08:12 +00001137 else if (TD->getUnderlyingType()->isFunctionPointerType())
Steve Naroffca743602008-10-15 18:38:58 +00001138 CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
Steve Naroff70f95502008-10-04 17:06:23 +00001139 return;
1140 }
1141 if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
1142 if (RD->isDefinition()) {
Mike Stump1eb44332009-09-09 15:08:12 +00001143 for (RecordDecl::field_iterator i = RD->field_begin(),
Argyrios Kyrtzidis17945a02009-06-30 02:36:12 +00001144 e = RD->field_end(); i != e; ++i) {
Steve Naroff70f95502008-10-04 17:06:23 +00001145 FieldDecl *FD = *i;
1146 if (isBlockPointerType(FD->getType()))
1147 RewriteBlockPointerDecl(FD);
1148 }
1149 }
1150 return;
1151 }
Steve Naroff1c9f81b2008-09-17 00:13:27 +00001152}