blob: e50f2b2f79000e382be27c53f55da73d879df4bf [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
14#include "ASTConsumers.h"
15#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"
25#include <sstream>
26
27using namespace clang;
28using llvm::utostr;
29
30namespace {
31
32class RewriteBlocks : public ASTConsumer {
33 Rewriter Rewrite;
34 Diagnostic &Diags;
35 const LangOptions &LangOpts;
36 unsigned RewriteFailedDiag;
37 unsigned NoNestedBlockCalls;
38
39 ASTContext *Context;
40 SourceManager *SM;
41 unsigned MainFileID;
42 const char *MainFileStart, *MainFileEnd;
43
44 // Block expressions.
45 llvm::SmallVector<BlockExpr *, 32> Blocks;
46 llvm::SmallVector<BlockDeclRefExpr *, 32> BlockDeclRefs;
47 llvm::DenseMap<BlockDeclRefExpr *, CallExpr *> BlockCallExprs;
48
49 // Block related declarations.
50 llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDecls;
51 llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDecls;
52
53 // The function/method we are rewriting.
54 FunctionDecl *CurFunctionDef;
55 ObjCMethodDecl *CurMethodDef;
56
57 bool IsHeader;
Steve Naroff13188952008-09-18 14:10:13 +000058 std::string InFileName;
59 std::string OutFileName;
Steve Naroffa0b75cf2008-10-02 23:30:43 +000060
61 std::string Preamble;
Steve Naroff1c9f81b2008-09-17 00:13:27 +000062public:
Steve Naroff13188952008-09-18 14:10:13 +000063 RewriteBlocks(std::string inFile, std::string outFile, Diagnostic &D,
64 const LangOptions &LOpts);
Steve Naroff1c9f81b2008-09-17 00:13:27 +000065 ~RewriteBlocks() {
66 // Get the buffer corresponding to MainFileID.
67 // If we haven't changed it, then we are done.
68 if (const RewriteBuffer *RewriteBuf =
69 Rewrite.getRewriteBufferFor(MainFileID)) {
70 std::string S(RewriteBuf->begin(), RewriteBuf->end());
71 printf("%s\n", S.c_str());
72 } else {
73 printf("No changes\n");
74 }
75 }
76
77 void Initialize(ASTContext &context);
78
79 void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen);
80 void ReplaceText(SourceLocation Start, unsigned OrigLength,
81 const char *NewStr, unsigned NewLength);
82
83 // Top Level Driver code.
84 virtual void HandleTopLevelDecl(Decl *D);
85 void HandleDeclInMainFile(Decl *D);
86
87 // Top level
88 Stmt *RewriteFunctionBody(Stmt *S);
89 void InsertBlockLiteralsWithinFunction(FunctionDecl *FD);
90 void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD);
91
92 // Block specific rewrite rules.
Steve Naroff39622b92008-10-03 15:38:09 +000093 void RewriteBlockExpr(BlockExpr *Exp, VarDecl *VD=0);
Steve Naroff1c9f81b2008-09-17 00:13:27 +000094
95 void RewriteBlockCall(CallExpr *Exp);
96 void RewriteBlockPointerDecl(NamedDecl *VD);
97 void RewriteBlockPointerFunctionArgs(FunctionDecl *FD);
98
99 std::string SynthesizeBlockFunc(BlockExpr *CE, int i,
100 const char *funcName, std::string Tag);
101 std::string SynthesizeBlockImpl(BlockExpr *CE, std::string Tag);
102 std::string SynthesizeBlockCall(CallExpr *Exp);
103 void SynthesizeBlockLiterals(SourceLocation FunLocStart,
104 const char *FunName);
105
106 void GetBlockDeclRefExprs(Stmt *S);
107 void GetBlockCallExprs(Stmt *S);
108
109 // We avoid calling Type::isBlockPointerType(), since it operates on the
110 // canonical type. We only care if the top-level type is a closure pointer.
111 bool isBlockPointerType(QualType T) { return isa<BlockPointerType>(T); }
112
113 // FIXME: This predicate seems like it would be useful to add to ASTContext.
114 bool isObjCType(QualType T) {
115 if (!LangOpts.ObjC1 && !LangOpts.ObjC2)
116 return false;
117
118 QualType OCT = Context->getCanonicalType(T).getUnqualifiedType();
119
120 if (OCT == Context->getCanonicalType(Context->getObjCIdType()) ||
121 OCT == Context->getCanonicalType(Context->getObjCClassType()))
122 return true;
123
124 if (const PointerType *PT = OCT->getAsPointerType()) {
125 if (isa<ObjCInterfaceType>(PT->getPointeeType()) ||
126 isa<ObjCQualifiedIdType>(PT->getPointeeType()))
127 return true;
128 }
129 return false;
130 }
131 // ObjC rewrite methods.
132 void RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl);
133 void RewriteCategoryDecl(ObjCCategoryDecl *CatDecl);
134 void RewriteProtocolDecl(ObjCProtocolDecl *PDecl);
135 void RewriteMethodDecl(ObjCMethodDecl *MDecl);
Steve Naroffeab5f632008-09-23 19:24:41 +0000136
137 bool BlockPointerTypeTakesAnyBlockArguments(QualType QT);
Steve Naroff1f6c3ae2008-09-24 17:22:34 +0000138 void GetExtentOfArgList(const char *Name, const char *&LParen, const char *&RParen);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000139};
140
141}
142
143static bool IsHeaderFile(const std::string &Filename) {
144 std::string::size_type DotPos = Filename.rfind('.');
145
146 if (DotPos == std::string::npos) {
147 // no file extension
148 return false;
149 }
150
151 std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end());
152 // C header: .h
153 // C++ header: .hh or .H;
154 return Ext == "h" || Ext == "hh" || Ext == "H";
155}
156
Steve Naroff13188952008-09-18 14:10:13 +0000157RewriteBlocks::RewriteBlocks(std::string inFile, std::string outFile,
158 Diagnostic &D, const LangOptions &LOpts) :
159 Diags(D), LangOpts(LOpts) {
160 IsHeader = IsHeaderFile(inFile);
161 InFileName = inFile;
162 OutFileName = outFile;
163 CurFunctionDef = 0;
164 CurMethodDef = 0;
165 RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
166 "rewriting failed");
167 NoNestedBlockCalls = Diags.getCustomDiagID(Diagnostic::Warning,
168 "Rewrite support for closure calls nested within closure blocks is incomplete");
169}
170
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000171ASTConsumer *clang::CreateBlockRewriter(const std::string& InFile,
Steve Naroff13188952008-09-18 14:10:13 +0000172 const std::string& OutFile,
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000173 Diagnostic &Diags,
174 const LangOptions &LangOpts) {
Steve Naroff13188952008-09-18 14:10:13 +0000175 return new RewriteBlocks(InFile, OutFile, Diags, LangOpts);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000176}
177
178void RewriteBlocks::Initialize(ASTContext &context) {
179 Context = &context;
180 SM = &Context->getSourceManager();
181
182 // Get the ID and start/end of the main file.
183 MainFileID = SM->getMainFileID();
184 const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID);
185 MainFileStart = MainBuf->getBufferStart();
186 MainFileEnd = MainBuf->getBufferEnd();
187
188 Rewrite.setSourceMgr(Context->getSourceManager());
189
Steve Naroffa0b75cf2008-10-02 23:30:43 +0000190 if (IsHeader)
191 Preamble = "#pragma once\n";
192 Preamble += "#ifndef BLOCK_IMPL\n";
193 Preamble += "#define BLOCK_IMPL\n";
194 Preamble += "struct __block_impl {\n";
195 Preamble += " void *isa;\n";
196 Preamble += " int Flags;\n";
197 Preamble += " int Size;\n";
198 Preamble += " void *FuncPtr;\n";
199 Preamble += "};\n";
200 Preamble += "enum {\n";
201 Preamble += " BLOCK_HAS_COPY_DISPOSE = (1<<25),\n";
202 Preamble += " BLOCK_IS_GLOBAL = (1<<28)\n";
203 Preamble += "};\n";
204 if (LangOpts.Microsoft)
205 Preamble += "#define __OBJC_RW_EXTERN extern \"C\" __declspec(dllimport)\n";
206 else
207 Preamble += "#define __OBJC_RW_EXTERN extern\n";
208 Preamble += "// Runtime copy/destroy helper functions\n";
209 Preamble += "__OBJC_RW_EXTERN void _Block_copy_assign(void *, void *);\n";
210 Preamble += "__OBJC_RW_EXTERN void _Block_byref_assign_copy(void *, void *);\n";
211 Preamble += "__OBJC_RW_EXTERN void _Block_destroy(void *);\n";
212 Preamble += "__OBJC_RW_EXTERN void _Block_byref_release(void *);\n";
Steve Naroff48a8c612008-10-03 12:09:49 +0000213 Preamble += "__OBJC_RW_EXTERN void *_NSConcreteGlobalBlock;\n";
214 Preamble += "__OBJC_RW_EXTERN void *_NSConcreteStackBlock;\n";
Steve Naroffa0b75cf2008-10-02 23:30:43 +0000215 Preamble += "#endif\n";
216
217 InsertText(SourceLocation::getFileLoc(MainFileID, 0),
218 Preamble.c_str(), Preamble.size());
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000219}
220
221void RewriteBlocks::InsertText(SourceLocation Loc, const char *StrData,
222 unsigned StrLen)
223{
224 if (!Rewrite.InsertText(Loc, StrData, StrLen))
225 return;
226 Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag);
227}
228
229void RewriteBlocks::ReplaceText(SourceLocation Start, unsigned OrigLength,
230 const char *NewStr, unsigned NewLength) {
231 if (!Rewrite.ReplaceText(Start, OrigLength, NewStr, NewLength))
232 return;
233 Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag);
234}
235
236void RewriteBlocks::RewriteMethodDecl(ObjCMethodDecl *Method) {
237 bool haveBlockPtrs = false;
238 for (ObjCMethodDecl::param_iterator I = Method->param_begin(),
239 E = Method->param_end(); I != E; ++I)
240 if (isBlockPointerType((*I)->getType()))
241 haveBlockPtrs = true;
242
243 if (!haveBlockPtrs)
244 return;
245
246 // Do a fuzzy rewrite.
247 // We have 1 or more arguments that have closure pointers.
248 SourceLocation Loc = Method->getLocStart();
249 SourceLocation LocEnd = Method->getLocEnd();
250 const char *startBuf = SM->getCharacterData(Loc);
251 const char *endBuf = SM->getCharacterData(LocEnd);
252
253 const char *methodPtr = startBuf;
Steve Naroff8af6a452008-10-02 17:12:56 +0000254 std::string Tag = "struct __block_impl *";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000255
256 while (*methodPtr++ && (methodPtr != endBuf)) {
257 switch (*methodPtr) {
258 case ':':
259 methodPtr++;
260 if (*methodPtr == '(') {
261 const char *scanType = ++methodPtr;
262 bool foundBlockPointer = false;
263 unsigned parenCount = 1;
264
265 while (parenCount) {
266 switch (*scanType) {
267 case '(':
268 parenCount++;
269 break;
270 case ')':
271 parenCount--;
272 break;
273 case '^':
274 foundBlockPointer = true;
275 break;
276 }
277 scanType++;
278 }
279 if (foundBlockPointer) {
280 // advance the location to startArgList.
281 Loc = Loc.getFileLocWithOffset(methodPtr-startBuf);
282 assert((Loc.isValid()) && "Invalid Loc");
283 ReplaceText(Loc, scanType-methodPtr-1, Tag.c_str(), Tag.size());
284
285 // Advance startBuf. Since the underlying buffer has changed,
286 // it's very important to advance startBuf (so we can correctly
287 // compute a relative Loc the next time around).
288 startBuf = methodPtr;
289 }
290 // Advance the method ptr to the end of the type.
291 methodPtr = scanType;
292 }
293 break;
294 }
295 }
296 return;
297}
298
299void RewriteBlocks::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
300 for (ObjCInterfaceDecl::instmeth_iterator I = ClassDecl->instmeth_begin(),
301 E = ClassDecl->instmeth_end(); I != E; ++I)
302 RewriteMethodDecl(*I);
303 for (ObjCInterfaceDecl::classmeth_iterator I = ClassDecl->classmeth_begin(),
304 E = ClassDecl->classmeth_end(); I != E; ++I)
305 RewriteMethodDecl(*I);
306}
307
308void RewriteBlocks::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
309 for (ObjCCategoryDecl::instmeth_iterator I = CatDecl->instmeth_begin(),
310 E = CatDecl->instmeth_end(); I != E; ++I)
311 RewriteMethodDecl(*I);
312 for (ObjCCategoryDecl::classmeth_iterator I = CatDecl->classmeth_begin(),
313 E = CatDecl->classmeth_end(); I != E; ++I)
314 RewriteMethodDecl(*I);
315}
316
317void RewriteBlocks::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
318 for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(),
319 E = PDecl->instmeth_end(); I != E; ++I)
320 RewriteMethodDecl(*I);
321 for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(),
322 E = PDecl->classmeth_end(); I != E; ++I)
323 RewriteMethodDecl(*I);
324}
325
326//===----------------------------------------------------------------------===//
327// Top Level Driver Code
328//===----------------------------------------------------------------------===//
329
330void RewriteBlocks::HandleTopLevelDecl(Decl *D) {
331 // Two cases: either the decl could be in the main file, or it could be in a
332 // #included file. If the former, rewrite it now. If the later, check to see
333 // if we rewrote the #include/#import.
334 SourceLocation Loc = D->getLocation();
335 Loc = SM->getLogicalLoc(Loc);
336
337 // If this is for a builtin, ignore it.
338 if (Loc.isInvalid()) return;
339
340 if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D))
341 RewriteInterfaceDecl(MD);
342 else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D))
343 RewriteCategoryDecl(CD);
344 else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
345 RewriteProtocolDecl(PD);
346
347 // If we have a decl in the main file, see if we should rewrite it.
348 if (SM->getDecomposedFileLoc(Loc).first == MainFileID)
349 HandleDeclInMainFile(D);
350 return;
351}
352
353std::string RewriteBlocks::SynthesizeBlockFunc(BlockExpr *CE, int i,
354 const char *funcName,
355 std::string Tag) {
356 const FunctionType *AFT = CE->getFunctionType();
357 QualType RT = AFT->getResultType();
Steve Naroff48a8c612008-10-03 12:09:49 +0000358 std::string StructRef = "struct " + Tag;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000359 std::string S = "static " + RT.getAsString() + " __" +
Steve Naroffa0b75cf2008-10-02 23:30:43 +0000360 funcName + "_" + "block_func_" + utostr(i);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000361
362 if (isa<FunctionTypeNoProto>(AFT)) {
363 S += "()";
364 } else if (CE->arg_empty()) {
Steve Naroff48a8c612008-10-03 12:09:49 +0000365 S += "(" + StructRef + " *__cself)";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000366 } else {
367 const FunctionTypeProto *FT = cast<FunctionTypeProto>(AFT);
368 assert(FT && "SynthesizeBlockFunc: No function proto");
369 S += '(';
370 // first add the implicit argument.
Steve Naroff48a8c612008-10-03 12:09:49 +0000371 S += StructRef + " *__cself, ";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000372 std::string ParamStr;
Steve Naroff9c3c9022008-09-17 18:37:59 +0000373 for (BlockExpr::arg_iterator AI = CE->arg_begin(),
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000374 E = CE->arg_end(); AI != E; ++AI) {
375 if (AI != CE->arg_begin()) S += ", ";
376 ParamStr = (*AI)->getName();
377 (*AI)->getType().getAsStringInternal(ParamStr);
378 S += ParamStr;
379 }
380 if (FT->isVariadic()) {
381 if (!CE->arg_empty()) S += ", ";
382 S += "...";
383 }
384 S += ')';
385 }
386 S += " {\n";
387
388 bool haveByRefDecls = false;
389
390 // Create local declarations to avoid rewriting all closure decl ref exprs.
391 // First, emit a declaration for all "by ref" decls.
392 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
393 E = BlockByRefDecls.end(); I != E; ++I) {
394 // Note: It is not possible to have "by ref" closure pointer decls.
395 haveByRefDecls = true;
396 S += " ";
397 std::string Name = (*I)->getName();
398 Context->getPointerType((*I)->getType()).getAsStringInternal(Name);
399 S += Name + " = __cself->" + (*I)->getName() + "; // bound by ref\n";
400 }
401 // Next, emit a declaration for all "by copy" declarations.
402 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
403 E = BlockByCopyDecls.end(); I != E; ++I) {
404 S += " ";
405 std::string Name = (*I)->getName();
406 // Handle nested closure invocation. For example:
407 //
408 // void (^myImportedClosure)(void);
409 // myImportedClosure = ^(void) { setGlobalInt(x + y); };
410 //
411 // void (^anotherClosure)(void);
412 // anotherClosure = ^(void) {
413 // myImportedClosure(); // import and invoke the closure
414 // };
415 //
416 if (isBlockPointerType((*I)->getType()))
Steve Naroff8af6a452008-10-02 17:12:56 +0000417 S += "struct __block_impl *";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000418 else
419 (*I)->getType().getAsStringInternal(Name);
420 S += Name + " = __cself->" + (*I)->getName() + "; // bound by copy\n";
421 }
Steve Naroff9c3c9022008-09-17 18:37:59 +0000422 if (BlockExpr *CBE = dyn_cast<BlockExpr>(CE)) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000423 std::string BodyBuf;
424
425 SourceLocation BodyLocStart = CBE->getBody()->getLocStart();
426 SourceLocation BodyLocEnd = CBE->getBody()->getLocEnd();
427 const char *BodyStartBuf = SM->getCharacterData(BodyLocStart);
428 const char *BodyEndBuf = SM->getCharacterData(BodyLocEnd);
429
430 BodyBuf.append(BodyStartBuf, BodyEndBuf-BodyStartBuf+1);
431
432 if (BlockDeclRefs.size()) {
433 unsigned int nCharsAdded = 0;
434 for (unsigned i = 0; i < BlockDeclRefs.size(); i++) {
435 if (BlockDeclRefs[i]->isByRef()) {
436 // Add a level of indirection! The code below assumes
437 // the closure decl refs/locations are in strictly ascending
438 // order. The traversal performed by GetBlockDeclRefExprs()
439 // currently does this. FIXME: Wrap the *x with parens,
440 // just in case x is a more complex expression, like x->member,
441 // which needs to be rewritten to (*x)->member.
442 SourceLocation StarLoc = BlockDeclRefs[i]->getLocStart();
443 const char *StarBuf = SM->getCharacterData(StarLoc);
444 BodyBuf.insert(StarBuf-BodyStartBuf+nCharsAdded, 1, '*');
445 // Get a fresh buffer, the insert might have caused it to grow.
446 BodyStartBuf = SM->getCharacterData(BodyLocStart);
447 nCharsAdded++;
448 } else if (isBlockPointerType(BlockDeclRefs[i]->getType())) {
449 Diags.Report(NoNestedBlockCalls);
450
451 GetBlockCallExprs(CE);
452
453 // Rewrite the closure in place.
454 // The character based equivalent of RewriteBlockCall().
455 // Need to get the CallExpr associated with this BlockDeclRef.
456 std::string BlockCall = SynthesizeBlockCall(BlockCallExprs[BlockDeclRefs[i]]);
457
458 SourceLocation CallLocStart = BlockCallExprs[BlockDeclRefs[i]]->getLocStart();
459 SourceLocation CallLocEnd = BlockCallExprs[BlockDeclRefs[i]]->getLocEnd();
460 const char *CallStart = SM->getCharacterData(CallLocStart);
461 const char *CallEnd = SM->getCharacterData(CallLocEnd);
462 unsigned CallBytes = CallEnd-CallStart;
463 BodyBuf.replace(CallStart-BodyStartBuf, CallBytes, BlockCall.c_str());
464 nCharsAdded += CallBytes;
465 }
466 }
467 }
468 if (haveByRefDecls) {
469 // Remove |...|.
Steve Naroffeab5f632008-09-23 19:24:41 +0000470 //const char *firstBarPtr = strchr(BodyStartBuf, '|');
471 //const char *secondBarPtr = strchr(firstBarPtr+1, '|');
472 //BodyBuf.replace(firstBarPtr-BodyStartBuf, secondBarPtr-firstBarPtr+1, "");
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000473 }
474 S += " ";
475 S += BodyBuf;
476 }
477 S += "\n}\n";
478 return S;
479}
480
Steve Naroff48a8c612008-10-03 12:09:49 +0000481std::string RewriteBlocks::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag) {
482 std::string S = "struct " + Tag;
483 std::string Constructor = " " + Tag;
484
485 S += " {\n struct __block_impl impl;\n";
486 Constructor += "(void *fp";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000487
488 GetBlockDeclRefExprs(CE);
489 if (BlockDeclRefs.size()) {
490 // Unique all "by copy" declarations.
491 for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
492 if (!BlockDeclRefs[i]->isByRef())
493 BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl());
494 // Unique all "by ref" declarations.
495 for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
496 if (BlockDeclRefs[i]->isByRef())
497 BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl());
498
499 // Output all "by copy" declarations.
500 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
501 E = BlockByCopyDecls.end(); I != E; ++I) {
502 S += " ";
503 std::string Name = (*I)->getName();
Steve Naroff48a8c612008-10-03 12:09:49 +0000504 std::string ArgName = "_" + Name;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000505 // Handle nested closure invocation. For example:
506 //
507 // void (^myImportedBlock)(void);
508 // myImportedBlock = ^(void) { setGlobalInt(x + y); };
509 //
510 // void (^anotherBlock)(void);
511 // anotherBlock = ^(void) {
512 // myImportedBlock(); // import and invoke the closure
513 // };
514 //
515 if (isBlockPointerType((*I)->getType()))
Steve Naroff8af6a452008-10-02 17:12:56 +0000516 S += "struct __block_impl *";
Steve Naroff48a8c612008-10-03 12:09:49 +0000517 else {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000518 (*I)->getType().getAsStringInternal(Name);
Steve Naroff48a8c612008-10-03 12:09:49 +0000519 (*I)->getType().getAsStringInternal(ArgName);
520 }
521 Constructor += ", " + ArgName;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000522 S += Name + ";\n";
523 }
524 // Output all "by ref" declarations.
525 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
526 E = BlockByRefDecls.end(); I != E; ++I) {
527 S += " ";
528 std::string Name = (*I)->getName();
Steve Naroff48a8c612008-10-03 12:09:49 +0000529 std::string ArgName = "_" + Name;
530
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000531 if (isBlockPointerType((*I)->getType()))
Steve Naroff8af6a452008-10-02 17:12:56 +0000532 S += "struct __block_impl *";
Steve Naroff48a8c612008-10-03 12:09:49 +0000533 else {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000534 Context->getPointerType((*I)->getType()).getAsStringInternal(Name);
Steve Naroff48a8c612008-10-03 12:09:49 +0000535 Context->getPointerType((*I)->getType()).getAsStringInternal(ArgName);
536 }
537 Constructor += ", " + ArgName;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000538 S += Name + "; // by ref\n";
Steve Naroff48a8c612008-10-03 12:09:49 +0000539 }
540 // Finish writing the constructor.
541 // FIXME: handle NSConcreteGlobalBlock.
542 Constructor += ", int flags=0) {\n";
Steve Naroff83ba14e2008-10-03 15:04:50 +0000543 Constructor += " impl.isa = 0/*&_NSConcreteStackBlock*/;\n impl.Size = sizeof(";
Steve Naroff48a8c612008-10-03 12:09:49 +0000544 Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
545
546 // Initialize all "by copy" arguments.
547 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
548 E = BlockByCopyDecls.end(); I != E; ++I) {
549 std::string Name = (*I)->getName();
550 Constructor += " ";
551 Constructor += Name + " = _";
552 Constructor += Name + ";\n";
553 }
554 // Initialize all "by ref" arguments.
555 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
556 E = BlockByRefDecls.end(); I != E; ++I) {
557 std::string Name = (*I)->getName();
558 Constructor += " ";
559 Constructor += Name + " = _";
560 Constructor += Name + ";\n";
561 }
Steve Naroff83ba14e2008-10-03 15:04:50 +0000562 } else {
563 // Finish writing the constructor.
564 // FIXME: handle NSConcreteGlobalBlock.
565 Constructor += ", int flags=0) {\n";
566 Constructor += " impl.isa = 0/*&_NSConcreteStackBlock*/;\n impl.Size = sizeof(";
567 Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000568 }
Steve Naroff83ba14e2008-10-03 15:04:50 +0000569 Constructor += " ";
570 Constructor += "}\n";
571 S += Constructor;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000572 S += "};\n";
573 return S;
574}
575
576void RewriteBlocks::SynthesizeBlockLiterals(SourceLocation FunLocStart,
577 const char *FunName) {
578 // Insert closures that were part of the function.
579 for (unsigned i = 0; i < Blocks.size(); i++) {
580
Steve Naroff48a8c612008-10-03 12:09:49 +0000581 std::string Tag = "__" + std::string(FunName) + "_block_impl_" + utostr(i);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000582
583 std::string CI = SynthesizeBlockImpl(Blocks[i], Tag);
584
585 InsertText(FunLocStart, CI.c_str(), CI.size());
586
587 std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, Tag);
588
589 InsertText(FunLocStart, CF.c_str(), CF.size());
590
591 BlockDeclRefs.clear();
592 BlockByRefDecls.clear();
593 BlockByCopyDecls.clear();
594 BlockCallExprs.clear();
595 }
596 Blocks.clear();
597}
598
599void RewriteBlocks::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {
Steve Naroff3ad29e22008-10-03 00:12:09 +0000600 SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000601 const char *FuncName = FD->getName();
602
603 SynthesizeBlockLiterals(FunLocStart, FuncName);
604}
605
606void RewriteBlocks::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
607 SourceLocation FunLocStart = MD->getLocStart();
608 std::string FuncName = std::string(MD->getSelector().getName());
609 // Convert colons to underscores.
610 std::string::size_type loc = 0;
611 while ((loc = FuncName.find(":", loc)) != std::string::npos)
612 FuncName.replace(loc, 1, "_");
613
614 SynthesizeBlockLiterals(FunLocStart, FuncName.c_str());
615}
616
617/// HandleDeclInMainFile - This is called for each top-level decl defined in the
618/// main file of the input.
619void RewriteBlocks::HandleDeclInMainFile(Decl *D) {
620 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
621
622 // Since function prototypes don't have ParmDecl's, we check the function
623 // prototype. This enables us to rewrite function declarations and
624 // definitions using the same code.
625 QualType funcType = FD->getType();
626
627 if (FunctionTypeProto *fproto = dyn_cast<FunctionTypeProto>(funcType)) {
628 for (FunctionTypeProto::arg_type_iterator I = fproto->arg_type_begin(),
629 E = fproto->arg_type_end(); I && (I != E); ++I)
630 if (isBlockPointerType(*I)) {
631 // All the args are checked/rewritten. Don't call twice!
632 RewriteBlockPointerDecl(FD);
633 break;
634 }
635 }
636 if (Stmt *Body = FD->getBody()) {
637 CurFunctionDef = FD;
638 FD->setBody(RewriteFunctionBody(Body));
639 InsertBlockLiteralsWithinFunction(FD);
640 CurFunctionDef = 0;
641 }
642 return;
643 }
644 if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
645 RewriteMethodDecl(MD);
646 if (Stmt *Body = MD->getBody()) {
647 CurMethodDef = MD;
648 RewriteFunctionBody(Body);
649 InsertBlockLiteralsWithinMethod(MD);
650 CurMethodDef = 0;
651 }
652 }
Steve Naroff39622b92008-10-03 15:38:09 +0000653 if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
654 if (isBlockPointerType(VD->getType())) {
655 RewriteBlockPointerDecl(VD);
656 if (VD->getInit()) {
657 if (BlockExpr *BExp = dyn_cast<BlockExpr>(VD->getInit())) {
658 RewriteBlockExpr(BExp, VD);
659 SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName());
660 }
661 }
662 }
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000663 return;
664 }
665 if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
666 if (isBlockPointerType(TD->getUnderlyingType()))
667 RewriteBlockPointerDecl(TD);
668 return;
669 }
Steve Naroff83ba14e2008-10-03 15:04:50 +0000670 if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
671 if (RD->isDefinition()) {
672 for (RecordDecl::field_const_iterator i = RD->field_begin(),
673 e = RD->field_end(); i != e; ++i) {
674 FieldDecl *FD = *i;
675 if (isBlockPointerType(FD->getType()))
676 RewriteBlockPointerDecl(FD);
677 }
678 }
679 return;
680 }
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000681}
682
683void RewriteBlocks::GetBlockDeclRefExprs(Stmt *S) {
684 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
685 CI != E; ++CI)
686 if (*CI)
687 GetBlockDeclRefExprs(*CI);
688
689 // Handle specific things.
690 if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S))
691 // FIXME: Handle enums.
692 if (!isa<FunctionDecl>(CDRE->getDecl()))
693 BlockDeclRefs.push_back(CDRE);
694 return;
695}
696
697void RewriteBlocks::GetBlockCallExprs(Stmt *S) {
698 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
699 CI != E; ++CI)
700 if (*CI)
701 GetBlockCallExprs(*CI);
702
703 if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
704 if (CE->getCallee()->getType()->isBlockPointerType())
705 BlockCallExprs[dyn_cast<BlockDeclRefExpr>(CE->getCallee())] = CE;
706 }
707 return;
708}
709
710//===----------------------------------------------------------------------===//
711// Function Body / Expression rewriting
712//===----------------------------------------------------------------------===//
713
714Stmt *RewriteBlocks::RewriteFunctionBody(Stmt *S) {
715 // Start by rewriting all children.
716 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
717 CI != E; ++CI)
718 if (*CI) {
Steve Naroff9c3c9022008-09-17 18:37:59 +0000719 if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000720 // We intentionally avoid rewritting the contents of a closure block
721 // expr. InsertBlockLiteralsWithinFunction() will rewrite the body.
Steve Naroff9c3c9022008-09-17 18:37:59 +0000722 RewriteBlockExpr(CBE);
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000723 } else {
724 Stmt *newStmt = RewriteFunctionBody(*CI);
725 if (newStmt)
726 *CI = newStmt;
727 }
728 }
729 // Handle specific things.
730 if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
731 if (CE->getCallee()->getType()->isBlockPointerType())
732 RewriteBlockCall(CE);
733 }
734 if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
735 ScopedDecl *SD = DS->getDecl();
736 if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) {
737 if (isBlockPointerType(ND->getType()))
738 RewriteBlockPointerDecl(ND);
739 }
740 if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
741 if (isBlockPointerType(TD->getUnderlyingType()))
742 RewriteBlockPointerDecl(TD);
743 }
744 }
745 // Return this stmt unmodified.
746 return S;
747}
748
749std::string RewriteBlocks::SynthesizeBlockCall(CallExpr *Exp) {
750 // Navigate to relevant type information.
Steve Naroffcc2ece22008-09-24 22:46:45 +0000751 const char *closureName = 0;
752 const BlockPointerType *CPT = 0;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000753
754 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp->getCallee())) {
755 closureName = DRE->getDecl()->getName();
756 CPT = DRE->getType()->getAsBlockPointerType();
757 } else if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(Exp->getCallee())) {
758 closureName = CDRE->getDecl()->getName();
759 CPT = CDRE->getType()->getAsBlockPointerType();
Steve Naroff83ba14e2008-10-03 15:04:50 +0000760 } else if (MemberExpr *MExpr = dyn_cast<MemberExpr>(Exp->getCallee())) {
761 closureName = MExpr->getMemberDecl()->getName();
762 CPT = MExpr->getType()->getAsBlockPointerType();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000763 } else {
764 assert(1 && "RewriteBlockClass: Bad type");
765 }
766 assert(CPT && "RewriteBlockClass: Bad type");
767 const FunctionType *FT = CPT->getPointeeType()->getAsFunctionType();
768 assert(FT && "RewriteBlockClass: Bad type");
769 const FunctionTypeProto *FTP = dyn_cast<FunctionTypeProto>(FT);
770 // FTP will be null for closures that don't take arguments.
771
772 // Build a closure call - start with a paren expr to enforce precedence.
773 std::string BlockCall = "(";
774
775 // Synthesize the cast.
776 BlockCall += "(" + Exp->getType().getAsString() + "(*)";
Steve Naroff8af6a452008-10-02 17:12:56 +0000777 BlockCall += "(struct __block_impl *";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000778 if (FTP) {
779 for (FunctionTypeProto::arg_type_iterator I = FTP->arg_type_begin(),
780 E = FTP->arg_type_end(); I && (I != E); ++I)
781 BlockCall += ", " + (*I).getAsString();
782 }
783 BlockCall += "))"; // close the argument list and paren expression.
784
Steve Naroff83ba14e2008-10-03 15:04:50 +0000785 // Invoke the closure. We need to cast it since the declaration type is
786 // bogus (it's a function pointer type)
787 BlockCall += "((struct __block_impl *)";
788 std::string closureExprBufStr;
789 llvm::raw_string_ostream closureExprBuf(closureExprBufStr);
790 Exp->getCallee()->printPretty(closureExprBuf);
791 BlockCall += closureExprBuf.str();
792 BlockCall += ")->FuncPtr)";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000793
794 // Add the arguments.
Steve Naroff83ba14e2008-10-03 15:04:50 +0000795 BlockCall += "((struct __block_impl *)";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000796 BlockCall += closureName;
797 for (CallExpr::arg_iterator I = Exp->arg_begin(),
798 E = Exp->arg_end(); I != E; ++I) {
799 std::string syncExprBufS;
800 llvm::raw_string_ostream Buf(syncExprBufS);
801 (*I)->printPretty(Buf);
802 BlockCall += ", " + Buf.str();
803 }
804 return BlockCall;
805}
806
807void RewriteBlocks::RewriteBlockCall(CallExpr *Exp) {
808 std::string BlockCall = SynthesizeBlockCall(Exp);
809
810 const char *startBuf = SM->getCharacterData(Exp->getLocStart());
811 const char *endBuf = SM->getCharacterData(Exp->getLocEnd());
812
813 ReplaceText(Exp->getLocStart(), endBuf-startBuf,
814 BlockCall.c_str(), BlockCall.size());
815}
816
817void RewriteBlocks::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {
818 SourceLocation DeclLoc = FD->getLocation();
819 unsigned parenCount = 0, nArgs = 0;
820
821 // We have 1 or more arguments that have closure pointers.
822 const char *startBuf = SM->getCharacterData(DeclLoc);
823 const char *startArgList = strchr(startBuf, '(');
824
825 assert((*startArgList == '(') && "Rewriter fuzzy parser confused");
826
827 parenCount++;
828 // advance the location to startArgList.
829 DeclLoc = DeclLoc.getFileLocWithOffset(startArgList-startBuf+1);
830 assert((DeclLoc.isValid()) && "Invalid DeclLoc");
831
832 const char *topLevelCommaCursor = 0;
833 const char *argPtr = startArgList;
834 bool scannedBlockDecl = false;
Steve Naroff8af6a452008-10-02 17:12:56 +0000835 std::string Tag = "struct __block_impl *";
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000836
837 while (*argPtr++ && parenCount) {
838 switch (*argPtr) {
839 case '^':
840 scannedBlockDecl = true;
841 break;
842 case '(':
843 parenCount++;
844 break;
845 case ')':
846 parenCount--;
847 if (parenCount == 0) {
848 if (scannedBlockDecl) {
849 // If we are rewriting a definition, don't forget the arg name.
850 if (FD->getBody())
851 Tag += FD->getParamDecl(nArgs)->getName();
852 // The last argument is a closure pointer decl, rewrite it!
853 if (topLevelCommaCursor)
854 ReplaceText(DeclLoc, argPtr-topLevelCommaCursor-2, Tag.c_str(), Tag.size());
855 else
856 ReplaceText(DeclLoc, argPtr-startArgList-1, Tag.c_str(), Tag.size());
857 scannedBlockDecl = false; // reset.
858 }
859 nArgs++;
860 }
861 break;
862 case ',':
863 if (parenCount == 1) {
864 // Make sure the function takes more than one argument.
865 assert((FD->getNumParams() > 1) && "Rewriter fuzzy parser confused");
866 if (scannedBlockDecl) {
867 // If we are rewriting a definition, don't forget the arg name.
868 if (FD->getBody())
869 Tag += FD->getParamDecl(nArgs)->getName();
870 // The current argument is a closure pointer decl, rewrite it!
871 if (topLevelCommaCursor)
872 ReplaceText(DeclLoc, argPtr-topLevelCommaCursor-1, Tag.c_str(), Tag.size());
873 else
874 ReplaceText(DeclLoc, argPtr-startArgList-1, Tag.c_str(), Tag.size());
875 scannedBlockDecl = false;
876 }
877 nArgs++;
878 // advance the location to topLevelCommaCursor.
879 if (topLevelCommaCursor)
880 DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-topLevelCommaCursor);
881 else
882 DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList+1);
883 topLevelCommaCursor = argPtr;
884 assert((DeclLoc.isValid()) && "Invalid DeclLoc");
885 }
886 break;
887 }
888 }
889 return;
890}
891
Steve Naroffeab5f632008-09-23 19:24:41 +0000892bool RewriteBlocks::BlockPointerTypeTakesAnyBlockArguments(QualType QT) {
893 const BlockPointerType *BPT = QT->getAsBlockPointerType();
894 assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");
895 const FunctionTypeProto *FTP = BPT->getPointeeType()->getAsFunctionTypeProto();
896 if (FTP) {
897 for (FunctionTypeProto::arg_type_iterator I = FTP->arg_type_begin(),
898 E = FTP->arg_type_end(); I != E; ++I)
899 if (isBlockPointerType(*I))
900 return true;
901 }
902 return false;
903}
904
905void RewriteBlocks::GetExtentOfArgList(const char *Name,
Steve Naroff1f6c3ae2008-09-24 17:22:34 +0000906 const char *&LParen, const char *&RParen) {
907 const char *argPtr = strchr(Name, '(');
Steve Naroffeab5f632008-09-23 19:24:41 +0000908 assert((*argPtr == '(') && "Rewriter fuzzy parser confused");
909
910 LParen = argPtr; // output the start.
911 argPtr++; // skip past the left paren.
912 unsigned parenCount = 1;
913
914 while (*argPtr && parenCount) {
915 switch (*argPtr) {
916 case '(': parenCount++; break;
917 case ')': parenCount--; break;
918 default: break;
919 }
920 if (parenCount) argPtr++;
921 }
922 assert((*argPtr == ')') && "Rewriter fuzzy parser confused");
923 RParen = argPtr; // output the end
924}
925
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000926void RewriteBlocks::RewriteBlockPointerDecl(NamedDecl *ND) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000927 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
928 RewriteBlockPointerFunctionArgs(FD);
929 return;
Steve Naroffca3bb4f2008-09-23 21:15:53 +0000930 }
931 // Handle Variables and Typedefs.
932 SourceLocation DeclLoc = ND->getLocation();
933 QualType DeclT;
934 if (VarDecl *VD = dyn_cast<VarDecl>(ND))
935 DeclT = VD->getType();
936 else if (TypedefDecl *TDD = dyn_cast<TypedefDecl>(ND))
937 DeclT = TDD->getUnderlyingType();
Steve Naroff83ba14e2008-10-03 15:04:50 +0000938 else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND))
939 DeclT = FD->getType();
Steve Naroffca3bb4f2008-09-23 21:15:53 +0000940 else
941 assert(0 && "RewriteBlockPointerDecl(): Decl type not yet handled");
Steve Naroffeab5f632008-09-23 19:24:41 +0000942
Steve Naroffca3bb4f2008-09-23 21:15:53 +0000943 const char *startBuf = SM->getCharacterData(DeclLoc);
944 const char *endBuf = startBuf;
945 // scan backward (from the decl location) for the end of the previous decl.
946 while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart)
947 startBuf--;
948 assert((*startBuf == '^') &&
949 "RewriteBlockPointerDecl() scan error: no caret");
950 // Replace the '^' with '*', computing a negative offset.
951 DeclLoc = DeclLoc.getFileLocWithOffset(startBuf-endBuf);
952 ReplaceText(DeclLoc, 1, "*", 1);
953
954 if (BlockPointerTypeTakesAnyBlockArguments(DeclT)) {
955 // Replace the '^' with '*' for arguments.
956 DeclLoc = ND->getLocation();
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000957 startBuf = SM->getCharacterData(DeclLoc);
Steve Naroff1f6c3ae2008-09-24 17:22:34 +0000958 const char *argListBegin, *argListEnd;
Steve Naroffca3bb4f2008-09-23 21:15:53 +0000959 GetExtentOfArgList(startBuf, argListBegin, argListEnd);
960 while (argListBegin < argListEnd) {
961 if (*argListBegin == '^') {
962 SourceLocation CaretLoc = DeclLoc.getFileLocWithOffset(argListBegin-startBuf);
963 ReplaceText(CaretLoc, 1, "*", 1);
964 }
965 argListBegin++;
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000966 }
Steve Naroffeab5f632008-09-23 19:24:41 +0000967 }
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000968 return;
969}
970
Steve Naroff39622b92008-10-03 15:38:09 +0000971void RewriteBlocks::RewriteBlockExpr(BlockExpr *Exp, VarDecl *VD) {
Steve Naroff1c9f81b2008-09-17 00:13:27 +0000972 Blocks.push_back(Exp);
973 bool haveByRefDecls = false;
974
975 // Add initializers for any closure decl refs.
976 GetBlockDeclRefExprs(Exp);
977 if (BlockDeclRefs.size()) {
978 // Unique all "by copy" declarations.
979 for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
980 if (!BlockDeclRefs[i]->isByRef())
981 BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl());
982 // Unique all "by ref" declarations.
983 for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
984 if (BlockDeclRefs[i]->isByRef()) {
985 haveByRefDecls = true;
986 BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl());
987 }
988 }
989 std::string FuncName;
990
991 if (CurFunctionDef)
992 FuncName = std::string(CurFunctionDef->getName());
993 else if (CurMethodDef) {
994 FuncName = std::string(CurMethodDef->getSelector().getName());
995 // Convert colons to underscores.
996 std::string::size_type loc = 0;
997 while ((loc = FuncName.find(":", loc)) != std::string::npos)
998 FuncName.replace(loc, 1, "_");
Steve Naroff39622b92008-10-03 15:38:09 +0000999 } else if (VD)
1000 FuncName = std::string(VD->getName());
1001
Steve Naroff1c9f81b2008-09-17 00:13:27 +00001002 std::string BlockNumber = utostr(Blocks.size()-1);
1003
Steve Naroff83ba14e2008-10-03 15:04:50 +00001004 std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber;
Steve Naroffa0b75cf2008-10-02 23:30:43 +00001005 std::string Func = "__" + FuncName + "_block_func_" + BlockNumber;
Steve Naroff1c9f81b2008-09-17 00:13:27 +00001006
Steve Naroff83ba14e2008-10-03 15:04:50 +00001007 std::string FunkTypeStr;
1008
1009 // Get a pointer to the function type so we can cast appropriately.
1010 Context->getPointerType(QualType(Exp->getFunctionType(),0)).getAsStringInternal(FunkTypeStr);
1011
Steve Naroff1c9f81b2008-09-17 00:13:27 +00001012 // Rewrite the closure block with a compound literal. The first cast is
1013 // to prevent warnings from the C compiler.
Steve Naroff83ba14e2008-10-03 15:04:50 +00001014 std::string Init = "(" + FunkTypeStr;
Steve Naroff1c9f81b2008-09-17 00:13:27 +00001015
Steve Naroff83ba14e2008-10-03 15:04:50 +00001016 Init += ")&" + Tag;
1017
1018 // Initialize the block function.
1019 Init += "((void*)" + Func;
Steve Naroff1c9f81b2008-09-17 00:13:27 +00001020
1021 // Add initializers for any closure decl refs.
1022 if (BlockDeclRefs.size()) {
1023 // Output all "by copy" declarations.
1024 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
1025 E = BlockByCopyDecls.end(); I != E; ++I) {
1026 Init += ",";
1027 if (isObjCType((*I)->getType())) {
1028 Init += "[[";
1029 Init += (*I)->getName();
1030 Init += " retain] autorelease]";
1031 } else {
1032 Init += (*I)->getName();
1033 }
1034 }
1035 // Output all "by ref" declarations.
1036 for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
1037 E = BlockByRefDecls.end(); I != E; ++I) {
1038 Init += ",&";
1039 Init += (*I)->getName();
1040 }
1041 }
Steve Naroff83ba14e2008-10-03 15:04:50 +00001042 Init += ")";
Steve Naroff1c9f81b2008-09-17 00:13:27 +00001043 BlockDeclRefs.clear();
1044 BlockByRefDecls.clear();
1045 BlockByCopyDecls.clear();
1046
1047 // Do the rewrite.
1048 const char *startBuf = SM->getCharacterData(Exp->getLocStart());
1049 const char *endBuf = SM->getCharacterData(Exp->getLocEnd());
1050 ReplaceText(Exp->getLocStart(), endBuf-startBuf+1, Init.c_str(), Init.size());
1051 return;
1052}