]> granicus.if.org Git - clang/blob - Driver/RewriteTest.cpp
add some helper methods for removing and replacing text, this makes the
[clang] / Driver / RewriteTest.cpp
1 //===--- RewriteTest.cpp - Playground for the code rewriter ---------------===//
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 code 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/Lex/Lexer.h"
22 #include "llvm/ADT/StringExtras.h"
23 #include "llvm/ADT/SmallPtrSet.h"
24 #include "llvm/Support/MemoryBuffer.h"
25 #include "llvm/Support/CommandLine.h"
26 #include <sstream>
27 using namespace clang;
28 using llvm::utostr;
29
30 static llvm::cl::opt<bool>
31 SilenceRewriteMacroWarning("Wno-rewrite-macros", llvm::cl::init(false),
32                            llvm::cl::desc("Silence ObjC rewriting warnings"));
33
34 namespace {
35   class RewriteTest : public ASTConsumer {
36     Rewriter Rewrite;
37     Diagnostic &Diags;
38     unsigned RewriteFailedDiag;
39     
40     ASTContext *Context;
41     SourceManager *SM;
42     unsigned MainFileID;
43     const char *MainFileStart, *MainFileEnd;
44     SourceLocation LastIncLoc;
45     llvm::SmallVector<ObjCImplementationDecl *, 8> ClassImplementation;
46     llvm::SmallVector<ObjCCategoryImplDecl *, 8> CategoryImplementation;
47     llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCSynthesizedStructs;
48     llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCForwardDecls;
49     llvm::DenseMap<ObjCMethodDecl*, std::string> MethodInternalNames;
50     llvm::SmallVector<Stmt *, 32> Stmts;
51     llvm::SmallVector<int, 8> ObjCBcLabelNo;
52     llvm::SmallVector<const RecordType *, 8> EncodingRecordTypes;
53     
54     FunctionDecl *MsgSendFunctionDecl;
55     FunctionDecl *MsgSendSuperFunctionDecl;
56     FunctionDecl *MsgSendStretFunctionDecl;
57     FunctionDecl *MsgSendSuperStretFunctionDecl;
58     FunctionDecl *MsgSendFpretFunctionDecl;
59     FunctionDecl *GetClassFunctionDecl;
60     FunctionDecl *GetMetaClassFunctionDecl;
61     FunctionDecl *SelGetUidFunctionDecl;
62     FunctionDecl *CFStringFunctionDecl;
63     FunctionDecl *GetProtocolFunctionDecl;
64       
65     // ObjC string constant support.
66     FileVarDecl *ConstantStringClassReference;
67     RecordDecl *NSStringRecord;
68     
69     // ObjC foreach break/continue generation support.
70     int BcLabelCount;
71     
72     // Needed for super.
73     ObjCMethodDecl *CurMethodDecl;
74     RecordDecl *SuperStructDecl;
75     
76     // Needed for header files being rewritten
77     bool IsHeader;
78     
79     static const int OBJC_ABI_VERSION =7 ;
80   public:
81     void Initialize(ASTContext &context);
82     
83
84     // Top Level Driver code.
85     virtual void HandleTopLevelDecl(Decl *D);
86     void HandleDeclInMainFile(Decl *D);
87     RewriteTest(bool isHeader, Diagnostic &D) : Diags(D) {
88       IsHeader = isHeader;
89       RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning, 
90                "rewriting sub-expression within a macro (may not be correct)");
91     }
92     ~RewriteTest();
93     
94     void ReplaceStmt(Stmt *Old, Stmt *New) {
95       // If replacement succeeded or warning disabled return with no warning.
96       if (!Rewrite.ReplaceStmt(Old, New) || SilenceRewriteMacroWarning)
97         return;
98
99       SourceRange Range = Old->getSourceRange();
100       Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag,
101                    0, 0, &Range, 1);
102     }
103     
104     void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen) {
105       // If insertion succeeded or warning disabled return with no warning.
106       if (!Rewrite.InsertText(Loc, StrData, StrLen) ||
107           SilenceRewriteMacroWarning)
108         return;
109       
110       Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag);
111     }
112     
113     void RemoveText(SourceLocation Loc, unsigned StrLen) {
114       // If removal succeeded or warning disabled return with no warning.
115       if (!Rewrite.RemoveText(Loc, StrLen) || SilenceRewriteMacroWarning)
116         return;
117       
118       Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag);
119     }
120
121     void ReplaceText(SourceLocation Start, unsigned OrigLength,
122                      const char *NewStr, unsigned NewLength) {
123       // If removal succeeded or warning disabled return with no warning.
124       if (!Rewrite.ReplaceText(Start, OrigLength, NewStr, NewLength) ||
125           SilenceRewriteMacroWarning)
126         return;
127       
128       Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag);
129     }
130     
131     // Syntactic Rewriting.
132     void RewritePrologue(SourceLocation Loc);
133     void RewriteInclude();
134     void RewriteTabs();
135     void RewriteForwardClassDecl(ObjCClassDecl *Dcl);
136     void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl);
137     void RewriteImplementationDecl(NamedDecl *Dcl);
138     void RewriteObjCMethodDecl(ObjCMethodDecl *MDecl, std::string &ResultStr);
139     void RewriteCategoryDecl(ObjCCategoryDecl *Dcl);
140     void RewriteProtocolDecl(ObjCProtocolDecl *Dcl);
141     void RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *Dcl);
142     void RewriteMethodDeclaration(ObjCMethodDecl *Method);
143     void RewriteProperties(int nProperties, ObjCPropertyDecl **Properties);
144     void RewriteFunctionDecl(FunctionDecl *FD);
145     void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl);
146     bool needToScanForQualifiers(QualType T);
147     ObjCInterfaceDecl *isSuperReceiver(Expr *recExpr);
148     QualType getSuperStructType();
149     
150     // Expression Rewriting.
151     Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S);
152     Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
153     Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV);
154     Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp);
155     Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
156     Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp);
157     Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp);
158     Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S);
159     Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S);
160     Stmt *RewriteObjCCatchStmt(ObjCAtCatchStmt *S);
161     Stmt *RewriteObjCFinallyStmt(ObjCAtFinallyStmt *S);
162     Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S);
163     Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
164                                        SourceLocation OrigEnd);
165     CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD, 
166                                            Expr **args, unsigned nargs);
167     Stmt *SynthMessageExpr(ObjCMessageExpr *Exp);
168     Stmt *RewriteBreakStmt(BreakStmt *S);
169     Stmt *RewriteContinueStmt(ContinueStmt *S);
170     void SynthCountByEnumWithState(std::string &buf);
171     
172     void SynthMsgSendFunctionDecl();
173     void SynthMsgSendSuperFunctionDecl();
174     void SynthMsgSendStretFunctionDecl();
175     void SynthMsgSendFpretFunctionDecl();
176     void SynthMsgSendSuperStretFunctionDecl();
177     void SynthGetClassFunctionDecl();
178     void SynthGetMetaClassFunctionDecl();
179     void SynthCFStringFunctionDecl();
180     void SynthSelGetUidFunctionDecl();
181     void SynthGetProtocolFunctionDecl();
182       
183     // Metadata emission.
184     void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
185                                   std::string &Result);
186     
187     void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl,
188                                      std::string &Result);
189     
190     typedef ObjCCategoryImplDecl::instmeth_iterator instmeth_iterator;
191     void RewriteObjCMethodsMetaData(instmeth_iterator MethodBegin,
192                                     instmeth_iterator MethodEnd,
193                                     bool IsInstanceMethod,
194                                     const char *prefix,
195                                     const char *ClassName,
196                                     std::string &Result);
197     
198     void RewriteObjCProtocolsMetaData(ObjCProtocolDecl **Protocols,
199                                       int NumProtocols,
200                                       const char *prefix,
201                                       const char *ClassName,
202                                       std::string &Result);
203     void SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
204                                       std::string &Result);
205     void SynthesizeIvarOffsetComputation(ObjCImplementationDecl *IDecl, 
206                                          ObjCIvarDecl *ivar, 
207                                          std::string &Result);
208     void RewriteImplementations(std::string &Result);
209   };
210 }
211
212 static bool IsHeaderFile(const std::string &Filename) {
213   std::string::size_type DotPos = Filename.rfind('.');
214   
215   if (DotPos == std::string::npos) {
216     // no file extension
217     return false; 
218   }
219   
220   std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end());
221   // C header: .h
222   // C++ header: .hh or .H;
223   return Ext == "h" || Ext == "hh" || Ext == "H";
224 }    
225
226 ASTConsumer *clang::CreateCodeRewriterTest(const std::string& InFile,
227                                            Diagnostic &Diags) {
228   return new RewriteTest(IsHeaderFile(InFile), Diags);
229 }
230
231 void RewriteTest::Initialize(ASTContext &context) {
232   Context = &context;
233   SM = &Context->getSourceManager();
234   MsgSendFunctionDecl = 0;
235   MsgSendSuperFunctionDecl = 0;
236   MsgSendStretFunctionDecl = 0;
237   MsgSendSuperStretFunctionDecl = 0;
238   MsgSendFpretFunctionDecl = 0;
239   GetClassFunctionDecl = 0;
240   GetMetaClassFunctionDecl = 0;
241   SelGetUidFunctionDecl = 0;
242   CFStringFunctionDecl = 0;
243   GetProtocolFunctionDecl = 0;
244   ConstantStringClassReference = 0;
245   NSStringRecord = 0;
246   CurMethodDecl = 0;
247   SuperStructDecl = 0;
248   BcLabelCount = 0;
249   
250   // Get the ID and start/end of the main file.
251   MainFileID = SM->getMainFileID();
252   const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID);
253   MainFileStart = MainBuf->getBufferStart();
254   MainFileEnd = MainBuf->getBufferEnd();
255   
256   
257   Rewrite.setSourceMgr(Context->getSourceManager());
258   // declaring objc_selector outside the parameter list removes a silly
259   // scope related warning...
260   const char *s = "#pragma once\n"
261   "struct objc_selector; struct objc_class;\n"
262   "#ifndef OBJC_SUPER\n"
263   "struct objc_super { struct objc_object *o; "
264   "struct objc_object *superClass; };\n"
265   "#define OBJC_SUPER\n"
266   "#endif\n"
267   "#ifndef _REWRITER_typedef_Protocol\n"
268   "typedef struct objc_object Protocol;\n"
269   "#define _REWRITER_typedef_Protocol\n"
270   "#endif\n"
271   "extern struct objc_object *objc_msgSend"
272   "(struct objc_object *, struct objc_selector *, ...);\n"
273   "extern struct objc_object *objc_msgSendSuper"
274   "(struct objc_super *, struct objc_selector *, ...);\n"
275   "extern struct objc_object *objc_msgSend_stret"
276   "(struct objc_object *, struct objc_selector *, ...);\n"
277   "extern struct objc_object *objc_msgSendSuper_stret"
278   "(struct objc_super *, struct objc_selector *, ...);\n"
279   "extern struct objc_object *objc_msgSend_fpret"
280   "(struct objc_object *, struct objc_selector *, ...);\n"
281   "extern struct objc_object *objc_getClass"
282   "(const char *);\n"
283   "extern struct objc_object *objc_getMetaClass"
284   "(const char *);\n"
285   "extern void objc_exception_throw(struct objc_object *);\n"
286   "extern void objc_exception_try_enter(void *);\n"
287   "extern void objc_exception_try_exit(void *);\n"
288   "extern struct objc_object *objc_exception_extract(void *);\n"
289   "extern int objc_exception_match"
290   "(struct objc_class *, struct objc_object *, ...);\n"
291   "extern Protocol *objc_getProtocol(const char *);\n"
292   "#include <objc/objc.h>\n"
293   "#ifndef __FASTENUMERATIONSTATE\n"
294   "struct __objcFastEnumerationState {\n\t"
295   "unsigned long state;\n\t"
296   "id *itemsPtr;\n\t"
297   "unsigned long *mutationsPtr;\n\t"
298   "unsigned long extra[5];\n};\n"
299   "#define __FASTENUMERATIONSTATE\n"
300   "#endif\n";
301   if (IsHeader) {
302     // insert the whole string when rewriting a header file
303     InsertText(SourceLocation::getFileLoc(MainFileID, 0), s, strlen(s));
304   }
305   else {
306     // Not rewriting header, exclude the #pragma once pragma
307     const char *p = s + strlen("#pragma once\n");
308     InsertText(SourceLocation::getFileLoc(MainFileID, 0), p, strlen(p));
309   }
310 }
311
312
313 //===----------------------------------------------------------------------===//
314 // Top Level Driver Code
315 //===----------------------------------------------------------------------===//
316
317 void RewriteTest::HandleTopLevelDecl(Decl *D) {
318   // Two cases: either the decl could be in the main file, or it could be in a
319   // #included file.  If the former, rewrite it now.  If the later, check to see
320   // if we rewrote the #include/#import.
321   SourceLocation Loc = D->getLocation();
322   Loc = SM->getLogicalLoc(Loc);
323   
324   // If this is for a builtin, ignore it.
325   if (Loc.isInvalid()) return;
326
327   // Look for built-in declarations that we need to refer during the rewrite.
328   if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
329     RewriteFunctionDecl(FD);
330   } else if (FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
331     // declared in <Foundation/NSString.h>
332     if (strcmp(FVD->getName(), "_NSConstantStringClassReference") == 0) {
333       ConstantStringClassReference = FVD;
334       return;
335     }
336   } else if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D)) {
337     RewriteInterfaceDecl(MD);
338   } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) {
339     RewriteCategoryDecl(CD);
340   } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
341     RewriteProtocolDecl(PD);
342   } else if (ObjCForwardProtocolDecl *FP = 
343              dyn_cast<ObjCForwardProtocolDecl>(D)){
344     RewriteForwardProtocolDecl(FP);
345   }
346   // If we have a decl in the main file, see if we should rewrite it.
347   if (SM->getDecomposedFileLoc(Loc).first == MainFileID)
348     return HandleDeclInMainFile(D);
349 }
350
351 /// HandleDeclInMainFile - This is called for each top-level decl defined in the
352 /// main file of the input.
353 void RewriteTest::HandleDeclInMainFile(Decl *D) {
354   if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
355     if (Stmt *Body = FD->getBody())
356       FD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
357       
358   if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
359     if (Stmt *Body = MD->getBody()) {
360       //Body->dump();
361       CurMethodDecl = MD;
362       MD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
363       CurMethodDecl = 0;
364     }
365   }
366   if (ObjCImplementationDecl *CI = dyn_cast<ObjCImplementationDecl>(D))
367     ClassImplementation.push_back(CI);
368   else if (ObjCCategoryImplDecl *CI = dyn_cast<ObjCCategoryImplDecl>(D))
369     CategoryImplementation.push_back(CI);
370   else if (ObjCClassDecl *CD = dyn_cast<ObjCClassDecl>(D))
371     RewriteForwardClassDecl(CD);
372   else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
373     RewriteObjCQualifiedInterfaceTypes(VD);
374     if (VD->getInit())
375       RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
376   }
377   // Nothing yet.
378 }
379
380 RewriteTest::~RewriteTest() {
381   // Get the top-level buffer that this corresponds to.
382   
383   // Rewrite tabs if we care.
384   //RewriteTabs();
385   
386   RewriteInclude();
387   
388   // Rewrite Objective-c meta data*
389   std::string ResultStr;
390   RewriteImplementations(ResultStr);
391   
392   // Get the buffer corresponding to MainFileID.  If we haven't changed it, then
393   // we are done.
394   if (const RewriteBuffer *RewriteBuf = 
395       Rewrite.getRewriteBufferFor(MainFileID)) {
396     //printf("Changed:\n");
397     std::string S(RewriteBuf->begin(), RewriteBuf->end());
398     printf("%s\n", S.c_str());
399   } else {
400     printf("No changes\n");
401   }
402   // Emit metadata.
403   printf("%s", ResultStr.c_str());
404 }
405
406 //===----------------------------------------------------------------------===//
407 // Syntactic (non-AST) Rewriting Code
408 //===----------------------------------------------------------------------===//
409
410 void RewriteTest::RewriteInclude() {
411   SourceLocation LocStart = SourceLocation::getFileLoc(MainFileID, 0);
412   std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
413   const char *MainBufStart = MainBuf.first;
414   const char *MainBufEnd = MainBuf.second;
415   size_t ImportLen = strlen("import");
416   size_t IncludeLen = strlen("include");
417                              
418   // Loop over the whole file, looking for includes.
419   for (const char *BufPtr = MainBufStart; BufPtr < MainBufEnd; ++BufPtr) {
420     if (*BufPtr == '#') {
421       if (++BufPtr == MainBufEnd)
422         return;
423       while (*BufPtr == ' ' || *BufPtr == '\t')
424         if (++BufPtr == MainBufEnd)
425           return;
426       if (!strncmp(BufPtr, "import", ImportLen)) {
427         // replace import with include
428         SourceLocation ImportLoc = 
429           LocStart.getFileLocWithOffset(BufPtr-MainBufStart);
430         ReplaceText(ImportLoc, ImportLen, "include", IncludeLen);
431         BufPtr += ImportLen;
432       }
433     }
434   }
435 }
436
437 void RewriteTest::RewriteTabs() {
438   std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
439   const char *MainBufStart = MainBuf.first;
440   const char *MainBufEnd = MainBuf.second;
441   
442   // Loop over the whole file, looking for tabs.
443   for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) {
444     if (*BufPtr != '\t')
445       continue;
446     
447     // Okay, we found a tab.  This tab will turn into at least one character,
448     // but it depends on which 'virtual column' it is in.  Compute that now.
449     unsigned VCol = 0;
450     while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' &&
451            BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r')
452       ++VCol;
453     
454     // Okay, now that we know the virtual column, we know how many spaces to
455     // insert.  We assume 8-character tab-stops.
456     unsigned Spaces = 8-(VCol & 7);
457     
458     // Get the location of the tab.
459     SourceLocation TabLoc =
460       SourceLocation::getFileLoc(MainFileID, BufPtr-MainBufStart);
461     
462     // Rewrite the single tab character into a sequence of spaces.
463     ReplaceText(TabLoc, 1, "        ", Spaces);
464   }
465 }
466
467
468 void RewriteTest::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) {
469   int numDecls = ClassDecl->getNumForwardDecls();
470   ObjCInterfaceDecl **ForwardDecls = ClassDecl->getForwardDecls();
471   
472   // Get the start location and compute the semi location.
473   SourceLocation startLoc = ClassDecl->getLocation();
474   const char *startBuf = SM->getCharacterData(startLoc);
475   const char *semiPtr = strchr(startBuf, ';');
476   
477   // Translate to typedef's that forward reference structs with the same name
478   // as the class. As a convenience, we include the original declaration
479   // as a comment.
480   std::string typedefString;
481   typedefString += "// ";
482   typedefString.append(startBuf, semiPtr-startBuf+1);
483   typedefString += "\n";
484   for (int i = 0; i < numDecls; i++) {
485     ObjCInterfaceDecl *ForwardDecl = ForwardDecls[i];
486     typedefString += "#ifndef _REWRITER_typedef_";
487     typedefString += ForwardDecl->getName();
488     typedefString += "\n";
489     typedefString += "#define _REWRITER_typedef_";
490     typedefString += ForwardDecl->getName();
491     typedefString += "\n";
492     typedefString += "typedef struct objc_object ";
493     typedefString += ForwardDecl->getName();
494     typedefString += ";\n#endif\n";
495   }
496   
497   // Replace the @class with typedefs corresponding to the classes.
498   ReplaceText(startLoc, semiPtr-startBuf+1, 
499               typedefString.c_str(), typedefString.size());
500 }
501
502 void RewriteTest::RewriteMethodDeclaration(ObjCMethodDecl *Method) {
503   SourceLocation LocStart = Method->getLocStart();
504   SourceLocation LocEnd = Method->getLocEnd();
505     
506   if (SM->getLineNumber(LocEnd) > SM->getLineNumber(LocStart)) {
507     InsertText(LocStart, "/* ", 3);
508     ReplaceText(LocEnd, 1, ";*/ ", 4);
509   } else {
510     InsertText(LocStart, "// ", 3);
511   }
512 }
513
514 void RewriteTest::RewriteProperties(int nProperties, ObjCPropertyDecl **Properties) 
515 {
516   for (int i = 0; i < nProperties; i++) {
517     ObjCPropertyDecl *Property = Properties[i];
518     SourceLocation Loc = Property->getLocation();
519     
520     ReplaceText(Loc, 0, "// ", 3);
521     
522     // FIXME: handle properties that are declared across multiple lines.
523   }
524 }
525
526 void RewriteTest::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
527   SourceLocation LocStart = CatDecl->getLocStart();
528   
529   // FIXME: handle category headers that are declared across multiple lines.
530   ReplaceText(LocStart, 0, "// ", 3);
531   
532   for (ObjCCategoryDecl::instmeth_iterator I = CatDecl->instmeth_begin(), 
533        E = CatDecl->instmeth_end(); I != E; ++I)
534     RewriteMethodDeclaration(*I);
535   for (ObjCCategoryDecl::classmeth_iterator I = CatDecl->classmeth_begin(), 
536        E = CatDecl->classmeth_end(); I != E; ++I)
537     RewriteMethodDeclaration(*I);
538
539   // Lastly, comment out the @end.
540   ReplaceText(CatDecl->getAtEndLoc(), 0, "// ", 3);
541 }
542
543 void RewriteTest::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
544   std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
545   
546   SourceLocation LocStart = PDecl->getLocStart();
547   
548   // FIXME: handle protocol headers that are declared across multiple lines.
549   ReplaceText(LocStart, 0, "// ", 3);
550   
551   for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(), 
552        E = PDecl->instmeth_end(); I != E; ++I)
553     RewriteMethodDeclaration(*I);
554   for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(), 
555        E = PDecl->classmeth_end(); I != E; ++I)
556     RewriteMethodDeclaration(*I);
557
558   // Lastly, comment out the @end.
559   SourceLocation LocEnd = PDecl->getAtEndLoc();
560   ReplaceText(LocEnd, 0, "// ", 3);
561
562   // Must comment out @optional/@required
563   const char *startBuf = SM->getCharacterData(LocStart);
564   const char *endBuf = SM->getCharacterData(LocEnd);
565   for (const char *p = startBuf; p < endBuf; p++) {
566     if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) {
567       std::string CommentedOptional = "/* @optional */";
568       SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
569       ReplaceText(OptionalLoc, strlen("@optional"),
570                   CommentedOptional.c_str(), CommentedOptional.size());
571       
572     }
573     else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) {
574       std::string CommentedRequired = "/* @required */";
575       SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
576       ReplaceText(OptionalLoc, strlen("@required"),
577                   CommentedRequired.c_str(), CommentedRequired.size());
578       
579     }
580   }
581 }
582
583 void RewriteTest::RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *PDecl) {
584   SourceLocation LocStart = PDecl->getLocation();
585   if (LocStart.isInvalid())
586     assert(false && "Invalid SourceLocation");
587   // FIXME: handle forward protocol that are declared across multiple lines.
588   ReplaceText(LocStart, 0, "// ", 3);
589 }
590
591 void RewriteTest::RewriteObjCMethodDecl(ObjCMethodDecl *OMD, 
592                                         std::string &ResultStr) {
593   ResultStr += "\nstatic ";
594   if (OMD->getResultType()->isObjCQualifiedIdType())
595     ResultStr += "id";
596   else
597     ResultStr += OMD->getResultType().getAsString();
598   ResultStr += " ";
599   
600   // Unique method name
601   std::string NameStr;
602   
603   if (OMD->isInstance())
604     NameStr += "_I_";
605   else
606     NameStr += "_C_";
607   
608   NameStr += OMD->getClassInterface()->getName();
609   NameStr += "_";
610   
611   NamedDecl *MethodContext = OMD->getMethodContext();
612   if (ObjCCategoryImplDecl *CID = 
613       dyn_cast<ObjCCategoryImplDecl>(MethodContext)) {
614     NameStr += CID->getName();
615     NameStr += "_";
616   }
617   // Append selector names, replacing ':' with '_'
618   const char *selName = OMD->getSelector().getName().c_str();
619   if (!strchr(selName, ':'))
620     NameStr +=  OMD->getSelector().getName();
621   else {
622     std::string selString = OMD->getSelector().getName();
623     int len = selString.size();
624     for (int i = 0; i < len; i++)
625       if (selString[i] == ':')
626         selString[i] = '_';
627     NameStr += selString;
628   }
629   // Remember this name for metadata emission
630   MethodInternalNames[OMD] = NameStr;
631   ResultStr += NameStr;
632   
633   // Rewrite arguments
634   ResultStr += "(";
635   
636   // invisible arguments
637   if (OMD->isInstance()) {
638     QualType selfTy = Context->getObjCInterfaceType(OMD->getClassInterface());
639     selfTy = Context->getPointerType(selfTy);
640     if (ObjCSynthesizedStructs.count(OMD->getClassInterface()))
641       ResultStr += "struct ";
642     ResultStr += selfTy.getAsString();
643   }
644   else
645     ResultStr += Context->getObjCIdType().getAsString();
646   
647   ResultStr += " self, ";
648   ResultStr += Context->getObjCSelType().getAsString();
649   ResultStr += " _cmd";
650   
651   // Method arguments.
652   for (int i = 0; i < OMD->getNumParams(); i++) {
653     ParmVarDecl *PDecl = OMD->getParamDecl(i);
654     ResultStr += ", ";
655     if (PDecl->getType()->isObjCQualifiedIdType())
656       ResultStr += "id";
657     else
658       ResultStr += PDecl->getType().getAsString();
659     ResultStr += " ";
660     ResultStr += PDecl->getName();
661   }
662   if (OMD->isVariadic())
663     ResultStr += ", ...";
664   ResultStr += ") ";
665   
666 }
667 void RewriteTest::RewriteImplementationDecl(NamedDecl *OID) {
668   ObjCImplementationDecl *IMD = dyn_cast<ObjCImplementationDecl>(OID);
669   ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(OID);
670   
671   if (IMD)
672     InsertText(IMD->getLocStart(), "// ", 3);
673   else
674     InsertText(CID->getLocStart(), "// ", 3);
675   
676   for (ObjCCategoryImplDecl::instmeth_iterator
677        I = IMD ? IMD->instmeth_begin() : CID->instmeth_begin(),
678        E = IMD ? IMD->instmeth_end() : CID->instmeth_end(); I != E; ++I) {
679     std::string ResultStr;
680     ObjCMethodDecl *OMD = *I;
681     RewriteObjCMethodDecl(OMD, ResultStr);
682     SourceLocation LocStart = OMD->getLocStart();
683     SourceLocation LocEnd = OMD->getBody()->getLocStart();
684     
685     const char *startBuf = SM->getCharacterData(LocStart);
686     const char *endBuf = SM->getCharacterData(LocEnd);
687     ReplaceText(LocStart, endBuf-startBuf,
688                 ResultStr.c_str(), ResultStr.size());
689   }
690   
691   for (ObjCCategoryImplDecl::classmeth_iterator
692        I = IMD ? IMD->classmeth_begin() : CID->classmeth_begin(),
693        E = IMD ? IMD->classmeth_end() : CID->classmeth_end(); I != E; ++I) {
694     std::string ResultStr;
695     ObjCMethodDecl *OMD = *I;
696     RewriteObjCMethodDecl(OMD, ResultStr);
697     SourceLocation LocStart = OMD->getLocStart();
698     SourceLocation LocEnd = OMD->getBody()->getLocStart();
699     
700     const char *startBuf = SM->getCharacterData(LocStart);
701     const char *endBuf = SM->getCharacterData(LocEnd);
702     ReplaceText(LocStart, endBuf-startBuf,
703                 ResultStr.c_str(), ResultStr.size());    
704   }
705   if (IMD)
706     InsertText(IMD->getLocEnd(), "// ", 3);
707   else
708    InsertText(CID->getLocEnd(), "// ", 3); 
709 }
710
711 void RewriteTest::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
712   std::string ResultStr;
713   if (!ObjCForwardDecls.count(ClassDecl)) {
714     // we haven't seen a forward decl - generate a typedef.
715     ResultStr = "#ifndef _REWRITER_typedef_";
716     ResultStr += ClassDecl->getName();
717     ResultStr += "\n";
718     ResultStr += "#define _REWRITER_typedef_";
719     ResultStr += ClassDecl->getName();
720     ResultStr += "\n";
721     ResultStr += "typedef struct ";
722     ResultStr += ClassDecl->getName();
723     ResultStr += " ";
724     ResultStr += ClassDecl->getName();
725     ResultStr += ";\n#endif\n";
726     
727     // Mark this typedef as having been generated.
728     ObjCForwardDecls.insert(ClassDecl);
729   }
730   SynthesizeObjCInternalStruct(ClassDecl, ResultStr);
731     
732   RewriteProperties(ClassDecl->getNumPropertyDecl(),
733                     ClassDecl->getPropertyDecl());
734   for (ObjCInterfaceDecl::instmeth_iterator I = ClassDecl->instmeth_begin(), 
735        E = ClassDecl->instmeth_end(); I != E; ++I)
736     RewriteMethodDeclaration(*I);
737   for (ObjCInterfaceDecl::classmeth_iterator I = ClassDecl->classmeth_begin(), 
738        E = ClassDecl->classmeth_end(); I != E; ++I)
739     RewriteMethodDeclaration(*I);
740
741   // Lastly, comment out the @end.
742   ReplaceText(ClassDecl->getAtEndLoc(), 0, "// ", 3);
743 }
744
745 Stmt *RewriteTest::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
746   ObjCIvarDecl *D = IV->getDecl();
747   if (IV->isFreeIvar()) {
748     Expr *Replacement = new MemberExpr(IV->getBase(), true, D, 
749                                        IV->getLocation());
750     ReplaceStmt(IV, Replacement);
751     delete IV;
752     return Replacement;
753   } else {
754 #if 0
755     /// This code is not right. It seems unnecessary. It breaks use of 
756     /// ivar reference used as 'receiver' of an expression; as in:
757     /// [newInv->_container addObject:0];
758     if (CurMethodDecl) {
759       if (const PointerType *pType = IV->getBase()->getType()->getAsPointerType()) {
760         ObjCInterfaceType *intT = dyn_cast<ObjCInterfaceType>(pType->getPointeeType());
761         if (CurMethodDecl->getClassInterface() == intT->getDecl()) {
762           IdentifierInfo *II = intT->getDecl()->getIdentifier();
763           RecordDecl *RD = new RecordDecl(Decl::Struct, SourceLocation(),
764                                           II, 0);
765           QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
766           
767           CastExpr *castExpr = new CastExpr(castT, IV->getBase(), SourceLocation());
768           // Don't forget the parens to enforce the proper binding.
769           ParenExpr *PE = new ParenExpr(SourceLocation(), SourceLocation(), castExpr);
770           ReplaceStmt(IV->getBase(), PE);
771           delete IV->getBase();
772           return PE;
773         }
774       }
775     }
776 #endif
777     return IV;
778   }
779 }
780
781 //===----------------------------------------------------------------------===//
782 // Function Body / Expression rewriting
783 //===----------------------------------------------------------------------===//
784
785 Stmt *RewriteTest::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
786   if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) || 
787       isa<DoStmt>(S) || isa<ForStmt>(S))
788     Stmts.push_back(S);
789   else if (isa<ObjCForCollectionStmt>(S)) {
790     Stmts.push_back(S);
791     ObjCBcLabelNo.push_back(++BcLabelCount);
792   }
793   
794   SourceLocation OrigStmtEnd = S->getLocEnd();
795   
796   // Start by rewriting all children.
797   for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
798        CI != E; ++CI)
799     if (*CI) {
800       Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(*CI);
801       if (newStmt) 
802         *CI = newStmt;
803     }
804       
805   // Handle specific things.
806   if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
807     return RewriteAtEncode(AtEncode);
808   
809   if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S))
810     return RewriteObjCIvarRefExpr(IvarRefExpr);
811
812   if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S))
813     return RewriteAtSelector(AtSelector);
814     
815   if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S))
816     return RewriteObjCStringLiteral(AtString);
817     
818   if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {
819     // Before we rewrite it, put the original message expression in a comment.
820     SourceLocation startLoc = MessExpr->getLocStart();
821     SourceLocation endLoc = MessExpr->getLocEnd();
822     
823     const char *startBuf = SM->getCharacterData(startLoc);
824     const char *endBuf = SM->getCharacterData(endLoc);
825     
826     std::string messString;
827     messString += "// ";
828     messString.append(startBuf, endBuf-startBuf+1);
829     messString += "\n";
830         
831     // FIXME: Missing definition of 
832     // InsertText(clang::SourceLocation, char const*, unsigned int).
833     // InsertText(startLoc, messString.c_str(), messString.size());
834     // Tried this, but it didn't work either...
835     // ReplaceText(startLoc, 0, messString.c_str(), messString.size());
836     return RewriteMessageExpr(MessExpr);
837   }
838   
839   if (ObjCAtTryStmt *StmtTry = dyn_cast<ObjCAtTryStmt>(S))
840     return RewriteObjCTryStmt(StmtTry);
841
842   if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast<ObjCAtSynchronizedStmt>(S))
843     return RewriteObjCSynchronizedStmt(StmtTry);
844
845   if (ObjCAtThrowStmt *StmtThrow = dyn_cast<ObjCAtThrowStmt>(S))
846     return RewriteObjCThrowStmt(StmtThrow);
847   
848   if (ObjCProtocolExpr *ProtocolExp = dyn_cast<ObjCProtocolExpr>(S))
849     return RewriteObjCProtocolExpr(ProtocolExp);
850   
851   if (ObjCForCollectionStmt *StmtForCollection = 
852         dyn_cast<ObjCForCollectionStmt>(S))
853     return RewriteObjCForCollectionStmt(StmtForCollection, OrigStmtEnd);
854   if (BreakStmt *StmtBreakStmt =
855       dyn_cast<BreakStmt>(S))
856     return RewriteBreakStmt(StmtBreakStmt);
857   if (ContinueStmt *StmtContinueStmt =
858       dyn_cast<ContinueStmt>(S))
859     return RewriteContinueStmt(StmtContinueStmt);
860   
861   if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) || 
862       isa<DoStmt>(S) || isa<ForStmt>(S)) {
863     assert(!Stmts.empty() && "Statement stack is empty");
864     assert ((isa<SwitchStmt>(Stmts.back()) || isa<WhileStmt>(Stmts.back()) || 
865              isa<DoStmt>(Stmts.back()) || isa<ForStmt>(Stmts.back())) 
866             && "Statement stack mismatch");
867     Stmts.pop_back();
868   }
869 #if 0
870   if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) {
871     CastExpr *Replacement = new CastExpr(ICE->getType(), ICE->getSubExpr(), SourceLocation());
872     // Get the new text.
873     std::ostringstream Buf;
874     Replacement->printPretty(Buf);
875     const std::string &Str = Buf.str();
876
877     printf("CAST = %s\n", &Str[0]);
878     InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size());
879     delete S;
880     return Replacement;
881   }
882 #endif
883   // Return this stmt unmodified.
884   return S;
885 }
886
887 /// SynthCountByEnumWithState - To print:
888 /// ((unsigned int (*)
889 ///  (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
890 ///  (void *)objc_msgSend)((id)l_collection, 
891 ///                        sel_registerName(
892 ///                          "countByEnumeratingWithState:objects:count:"), 
893 ///                        &enumState, 
894 ///                        (id *)items, (unsigned int)16)
895 ///
896 void RewriteTest::SynthCountByEnumWithState(std::string &buf) {
897   buf += "((unsigned int (*) (id, SEL, struct __objcFastEnumerationState *, "
898   "id *, unsigned int))(void *)objc_msgSend)";
899   buf += "\n\t\t";
900   buf += "((id)l_collection,\n\t\t";
901   buf += "sel_registerName(\"countByEnumeratingWithState:objects:count:\"),";
902   buf += "\n\t\t";
903   buf += "&enumState, "
904          "(id *)items, (unsigned int)16)";
905 }
906
907 /// RewriteBreakStmt - Rewrite for a break-stmt inside an ObjC2's foreach
908 /// statement to exit to its outer synthesized loop.
909 ///
910 Stmt *RewriteTest::RewriteBreakStmt(BreakStmt *S) {
911   if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back()))
912     return S;
913   // replace break with goto __break_label
914   std::string buf;
915   
916   SourceLocation startLoc = S->getLocStart();
917   buf = "goto __break_label_";
918   buf += utostr(ObjCBcLabelNo.back());
919   ReplaceText(startLoc, strlen("break"), buf.c_str(), buf.size());
920
921   return 0;
922 }
923
924 /// RewriteContinueStmt - Rewrite for a continue-stmt inside an ObjC2's foreach
925 /// statement to continue with its inner synthesized loop.
926 ///
927 Stmt *RewriteTest::RewriteContinueStmt(ContinueStmt *S) {
928   if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back()))
929     return S;
930   // replace continue with goto __continue_label
931   std::string buf;
932   
933   SourceLocation startLoc = S->getLocStart();
934   buf = "goto __continue_label_";
935   buf += utostr(ObjCBcLabelNo.back());
936   ReplaceText(startLoc, strlen("continue"), buf.c_str(), buf.size());
937   
938   return 0;
939 }
940
941 /// RewriteObjCForCollectionStmt - Rewriter for ObjC2's foreach statement.
942 ///  It rewrites:
943 /// for ( type elem in collection) { stmts; }
944  
945 /// Into:
946 /// {
947 ///   type elem; 
948 ///   struct __objcFastEnumerationState enumState = { 0 };
949 ///   id items[16];
950 ///   id l_collection = (id)collection;
951 ///   unsigned long limit = [l_collection countByEnumeratingWithState:&enumState 
952 ///                                       objects:items count:16];
953 /// if (limit) {
954 ///   unsigned long startMutations = *enumState.mutationsPtr;
955 ///   do {
956 ///        unsigned long counter = 0;
957 ///        do {
958 ///             if (startMutations != *enumState.mutationsPtr) 
959 ///               objc_enumerationMutation(l_collection);
960 ///             elem = (type)enumState.itemsPtr[counter++];
961 ///             stmts;
962 ///             __continue_label: ;
963 ///        } while (counter < limit);
964 ///   } while (limit = [l_collection countByEnumeratingWithState:&enumState 
965 ///                                  objects:items count:16]);
966 ///   elem = nil;
967 ///   __break_label: ;
968 ///  }
969 ///  else
970 ///       elem = nil;
971 ///  }
972 ///
973 Stmt *RewriteTest::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
974                                                 SourceLocation OrigEnd) {
975   assert(!Stmts.empty() && "ObjCForCollectionStmt - Statement stack empty");
976   assert(isa<ObjCForCollectionStmt>(Stmts.back()) && 
977          "ObjCForCollectionStmt Statement stack mismatch");
978   assert(!ObjCBcLabelNo.empty() && 
979          "ObjCForCollectionStmt - Label No stack empty");
980   
981   SourceLocation startLoc = S->getLocStart();
982   const char *startBuf = SM->getCharacterData(startLoc);
983   const char *elementName;
984   std::string elementTypeAsString;
985   std::string buf;
986   buf = "\n{\n\t";
987   if (DeclStmt *DS = dyn_cast<DeclStmt>(S->getElement())) {
988     // type elem;
989     QualType ElementType = cast<ValueDecl>(DS->getDecl())->getType();
990     elementTypeAsString = ElementType.getAsString();
991     buf += elementTypeAsString;
992     buf += " ";
993     elementName = DS->getDecl()->getName();
994     buf += elementName;
995     buf += ";\n\t";
996   }
997   else if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S->getElement())) {
998     elementName = DR->getDecl()->getName();
999     elementTypeAsString = DR->getDecl()->getType().getAsString();
1000   }
1001   else
1002     assert(false && "RewriteObjCForCollectionStmt - bad element kind");
1003   
1004   // struct __objcFastEnumerationState enumState = { 0 };
1005   buf += "struct __objcFastEnumerationState enumState = { 0 };\n\t";
1006   // id items[16];
1007   buf += "id items[16];\n\t";
1008   // id l_collection = (id)
1009   buf += "id l_collection = (id)";
1010   // Find start location of 'collection' the hard way!
1011   const char *startCollectionBuf = startBuf;
1012   startCollectionBuf += 3;  // skip 'for'
1013   startCollectionBuf = strchr(startCollectionBuf, '(');
1014   startCollectionBuf++; // skip '('
1015   // find 'in' and skip it.
1016   while (*startCollectionBuf != ' ' ||
1017          *(startCollectionBuf+1) != 'i' || *(startCollectionBuf+2) != 'n' ||
1018          (*(startCollectionBuf+3) != ' ' &&
1019           *(startCollectionBuf+3) != '[' && *(startCollectionBuf+3) != '('))
1020     startCollectionBuf++;
1021   startCollectionBuf += 3;
1022   
1023   // Replace: "for (type element in" with string constructed thus far. 
1024   ReplaceText(startLoc, startCollectionBuf - startBuf,
1025               buf.c_str(), buf.size());
1026   // Replace ')' in for '(' type elem in collection ')' with ';'
1027   SourceLocation rightParenLoc = S->getRParenLoc();
1028   const char *rparenBuf = SM->getCharacterData(rightParenLoc);
1029   SourceLocation lparenLoc = startLoc.getFileLocWithOffset(rparenBuf-startBuf);
1030   buf = ";\n\t";
1031   
1032   // unsigned long limit = [l_collection countByEnumeratingWithState:&enumState
1033   //                                   objects:items count:16];
1034   // which is synthesized into:
1035   // unsigned int limit = 
1036   // ((unsigned int (*)
1037   //  (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
1038   //  (void *)objc_msgSend)((id)l_collection, 
1039   //                        sel_registerName(
1040   //                          "countByEnumeratingWithState:objects:count:"), 
1041   //                        (struct __objcFastEnumerationState *)&state, 
1042   //                        (id *)items, (unsigned int)16);
1043   buf += "unsigned long limit =\n\t\t";
1044   SynthCountByEnumWithState(buf);
1045   buf += ";\n\t";
1046   /// if (limit) {
1047   ///   unsigned long startMutations = *enumState.mutationsPtr;
1048   ///   do {
1049   ///        unsigned long counter = 0;
1050   ///        do {
1051   ///             if (startMutations != *enumState.mutationsPtr) 
1052   ///               objc_enumerationMutation(l_collection);
1053   ///             elem = (type)enumState.itemsPtr[counter++];
1054   buf += "if (limit) {\n\t";
1055   buf += "unsigned long startMutations = *enumState.mutationsPtr;\n\t";
1056   buf += "do {\n\t\t";
1057   buf += "unsigned long counter = 0;\n\t\t";
1058   buf += "do {\n\t\t\t";
1059   buf += "if (startMutations != *enumState.mutationsPtr)\n\t\t\t\t";
1060   buf += "objc_enumerationMutation(l_collection);\n\t\t\t";
1061   buf += elementName;
1062   buf += " = (";
1063   buf += elementTypeAsString;
1064   buf += ")enumState.itemsPtr[counter++];";
1065   // Replace ')' in for '(' type elem in collection ')' with all of these.
1066   ReplaceText(lparenLoc, 1, buf.c_str(), buf.size());
1067   
1068   ///            __continue_label: ;
1069   ///        } while (counter < limit);
1070   ///   } while (limit = [l_collection countByEnumeratingWithState:&enumState 
1071   ///                                  objects:items count:16]);
1072   ///   elem = nil;
1073   ///   __break_label: ;
1074   ///  }
1075   ///  else
1076   ///       elem = nil;
1077   ///  }
1078   /// 
1079   buf = ";\n\t";
1080   buf += "__continue_label_";
1081   buf += utostr(ObjCBcLabelNo.back());
1082   buf += ": ;";
1083   buf += "\n\t\t";
1084   buf += "} while (counter < limit);\n\t";
1085   buf += "} while (limit = ";
1086   SynthCountByEnumWithState(buf);
1087   buf += ");\n\t";
1088   buf += elementName;
1089   buf += " = nil;\n\t";
1090   buf += "__break_label_";
1091   buf += utostr(ObjCBcLabelNo.back());
1092   buf += ": ;\n\t";
1093   buf += "}\n\t";
1094   buf += "else\n\t\t";
1095   buf += elementName;
1096   buf += " = nil;\n";
1097   buf += "}\n";
1098   // Insert all these *after* the statement body.
1099   SourceLocation endBodyLoc = OrigEnd.getFileLocWithOffset(1);
1100   InsertText(endBodyLoc, buf.c_str(), buf.size());
1101   Stmts.pop_back();
1102   ObjCBcLabelNo.pop_back();
1103   return 0;
1104 }
1105
1106 /// RewriteObjCSynchronizedStmt - 
1107 /// This routine rewrites @synchronized(expr) stmt;
1108 /// into:
1109 /// objc_sync_enter(expr);
1110 /// @try stmt @finally { objc_sync_exit(expr); }
1111 ///
1112 Stmt *RewriteTest::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
1113   // Get the start location and compute the semi location.
1114   SourceLocation startLoc = S->getLocStart();
1115   const char *startBuf = SM->getCharacterData(startLoc);
1116   
1117   assert((*startBuf == '@') && "bogus @synchronized location");
1118   
1119   std::string buf; 
1120   buf = "objc_sync_enter";
1121   ReplaceText(startLoc, 13, buf.c_str(), buf.size());
1122   SourceLocation endLoc = S->getSynchExpr()->getLocEnd();
1123   const char *endBuf = SM->getCharacterData(endLoc);
1124   endBuf++;
1125   const char *rparenBuf = strchr(endBuf, ')');
1126   SourceLocation rparenLoc = startLoc.getFileLocWithOffset(rparenBuf-startBuf);
1127   buf = ");\n";
1128   // declare a new scope with two variables, _stack and _rethrow.
1129   buf += "/* @try scope begin */ \n{ struct _objc_exception_data {\n";
1130   buf += "int buf[18/*32-bit i386*/];\n";
1131   buf += "char *pointers[4];} _stack;\n";
1132   buf += "id volatile _rethrow = 0;\n";
1133   buf += "objc_exception_try_enter(&_stack);\n";
1134   buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";
1135   ReplaceText(rparenLoc, 1, buf.c_str(), buf.size());
1136   startLoc = S->getSynchBody()->getLocEnd();
1137   startBuf = SM->getCharacterData(startLoc);
1138   
1139   assert((*startBuf == '}') && "bogus @try block");
1140   SourceLocation lastCurlyLoc = startLoc;
1141   buf = "}\nelse {\n";
1142   buf += "  _rethrow = objc_exception_extract(&_stack);\n";
1143   buf += "  if (!_rethrow) objc_exception_try_exit(&_stack);\n";
1144   // FIXME: This must be objc_sync_exit(syncExpr);
1145   buf += "  objc_sync_exit();\n";
1146   buf += "  if (_rethrow) objc_exception_throw(_rethrow);\n";
1147   buf += "}\n";
1148   buf += "}";
1149   
1150   ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size());
1151   return 0;
1152 }
1153
1154 Stmt *RewriteTest::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
1155   // Get the start location and compute the semi location.
1156   SourceLocation startLoc = S->getLocStart();
1157   const char *startBuf = SM->getCharacterData(startLoc);
1158   
1159   assert((*startBuf == '@') && "bogus @try location");
1160
1161   std::string buf;
1162   // declare a new scope with two variables, _stack and _rethrow.
1163   buf = "/* @try scope begin */ { struct _objc_exception_data {\n";
1164   buf += "int buf[18/*32-bit i386*/];\n";
1165   buf += "char *pointers[4];} _stack;\n";
1166   buf += "id volatile _rethrow = 0;\n";
1167   buf += "objc_exception_try_enter(&_stack);\n";
1168   buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";
1169
1170   ReplaceText(startLoc, 4, buf.c_str(), buf.size());
1171   
1172   startLoc = S->getTryBody()->getLocEnd();
1173   startBuf = SM->getCharacterData(startLoc);
1174
1175   assert((*startBuf == '}') && "bogus @try block");
1176
1177   SourceLocation lastCurlyLoc = startLoc;
1178   
1179   startLoc = startLoc.getFileLocWithOffset(1);
1180   buf = " /* @catch begin */ else {\n";
1181   buf += " id _caught = objc_exception_extract(&_stack);\n";
1182   buf += " objc_exception_try_enter (&_stack);\n";
1183   buf += " if (_setjmp(_stack.buf))\n";
1184   buf += "   _rethrow = objc_exception_extract(&_stack);\n";
1185   buf += " else { /* @catch continue */";
1186   
1187   InsertText(startLoc, buf.c_str(), buf.size());
1188   
1189   bool sawIdTypedCatch = false;
1190   Stmt *lastCatchBody = 0;
1191   ObjCAtCatchStmt *catchList = S->getCatchStmts();
1192   while (catchList) {
1193     Stmt *catchStmt = catchList->getCatchParamStmt();
1194
1195     if (catchList == S->getCatchStmts()) 
1196       buf = "if ("; // we are generating code for the first catch clause
1197     else
1198       buf = "else if (";
1199     startLoc = catchList->getLocStart();
1200     startBuf = SM->getCharacterData(startLoc);
1201     
1202     assert((*startBuf == '@') && "bogus @catch location");
1203     
1204     const char *lParenLoc = strchr(startBuf, '(');
1205
1206     if (DeclStmt *declStmt = dyn_cast<DeclStmt>(catchStmt)) {
1207       QualType t = dyn_cast<ValueDecl>(declStmt->getDecl())->getType();
1208       if (t == Context->getObjCIdType()) {
1209         buf += "1) { ";
1210         ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size());
1211         sawIdTypedCatch = true;
1212       } else if (const PointerType *pType = t->getAsPointerType()) { 
1213         ObjCInterfaceType *cls; // Should be a pointer to a class.
1214         
1215         cls = dyn_cast<ObjCInterfaceType>(pType->getPointeeType().getTypePtr());
1216         if (cls) {
1217           buf += "objc_exception_match((struct objc_class *)objc_getClass(\"";
1218           buf += cls->getDecl()->getName();
1219           buf += "\"), (struct objc_object *)_caught)) { ";
1220           ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size());
1221         }
1222       }
1223       // Now rewrite the body...
1224       lastCatchBody = catchList->getCatchBody();
1225       SourceLocation rParenLoc = catchList->getRParenLoc();
1226       SourceLocation bodyLoc = lastCatchBody->getLocStart();
1227       const char *bodyBuf = SM->getCharacterData(bodyLoc);
1228       const char *rParenBuf = SM->getCharacterData(rParenLoc);
1229       assert((*rParenBuf == ')') && "bogus @catch paren location");
1230       assert((*bodyBuf == '{') && "bogus @catch body location");
1231         
1232       buf = " = _caught;";
1233       // Here we replace ") {" with "= _caught;" (which initializes and 
1234       // declares the @catch parameter).
1235       ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, buf.c_str(), buf.size());
1236     } else if (!isa<NullStmt>(catchStmt)) {
1237       assert(false && "@catch rewrite bug");
1238     }
1239     catchList = catchList->getNextCatchStmt();
1240   }
1241   // Complete the catch list...
1242   if (lastCatchBody) {
1243     SourceLocation bodyLoc = lastCatchBody->getLocEnd();
1244     const char *bodyBuf = SM->getCharacterData(bodyLoc);
1245     assert((*bodyBuf == '}') && "bogus @catch body location");
1246     bodyLoc = bodyLoc.getFileLocWithOffset(1);
1247     buf = " } } /* @catch end */\n";
1248   
1249     InsertText(bodyLoc, buf.c_str(), buf.size());
1250     
1251     // Set lastCurlyLoc
1252     lastCurlyLoc = lastCatchBody->getLocEnd();
1253   }
1254   if (ObjCAtFinallyStmt *finalStmt = S->getFinallyStmt()) {
1255     startLoc = finalStmt->getLocStart();
1256     startBuf = SM->getCharacterData(startLoc);
1257     assert((*startBuf == '@') && "bogus @finally start");
1258     
1259     buf = "/* @finally */";
1260     ReplaceText(startLoc, 8, buf.c_str(), buf.size());
1261     
1262     Stmt *body = finalStmt->getFinallyBody();
1263     SourceLocation startLoc = body->getLocStart();
1264     SourceLocation endLoc = body->getLocEnd();
1265     const char *startBuf = SM->getCharacterData(startLoc);
1266     const char *endBuf = SM->getCharacterData(endLoc);
1267     assert((*startBuf == '{') && "bogus @finally body location");
1268     assert((*endBuf == '}') && "bogus @finally body location");
1269   
1270     startLoc = startLoc.getFileLocWithOffset(1);
1271     buf = " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
1272     InsertText(startLoc, buf.c_str(), buf.size());
1273     endLoc = endLoc.getFileLocWithOffset(-1);
1274     buf = " if (_rethrow) objc_exception_throw(_rethrow);\n";
1275     InsertText(endLoc, buf.c_str(), buf.size());
1276     
1277     // Set lastCurlyLoc
1278     lastCurlyLoc = body->getLocEnd();
1279   }
1280   // Now emit the final closing curly brace...
1281   lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1);
1282   buf = " } /* @try scope end */\n";
1283   InsertText(lastCurlyLoc, buf.c_str(), buf.size());
1284   return 0;
1285 }
1286
1287 Stmt *RewriteTest::RewriteObjCCatchStmt(ObjCAtCatchStmt *S) {
1288   return 0;
1289 }
1290
1291 Stmt *RewriteTest::RewriteObjCFinallyStmt(ObjCAtFinallyStmt *S) {
1292   return 0;
1293 }
1294
1295 // This can't be done with ReplaceStmt(S, ThrowExpr), since 
1296 // the throw expression is typically a message expression that's already 
1297 // been rewritten! (which implies the SourceLocation's are invalid).
1298 Stmt *RewriteTest::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) {
1299   // Get the start location and compute the semi location.
1300   SourceLocation startLoc = S->getLocStart();
1301   const char *startBuf = SM->getCharacterData(startLoc);
1302   
1303   assert((*startBuf == '@') && "bogus @throw location");
1304
1305   std::string buf;
1306   /* void objc_exception_throw(id) __attribute__((noreturn)); */
1307   if (S->getThrowExpr())
1308     buf = "objc_exception_throw(";
1309   else // add an implicit argument
1310     buf = "objc_exception_throw(_caught";
1311   ReplaceText(startLoc, 6, buf.c_str(), buf.size());
1312   const char *semiBuf = strchr(startBuf, ';');
1313   assert((*semiBuf == ';') && "@throw: can't find ';'");
1314   SourceLocation semiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf);
1315   buf = ");";
1316   ReplaceText(semiLoc, 1, buf.c_str(), buf.size());
1317   return 0;
1318 }
1319
1320 Stmt *RewriteTest::RewriteAtEncode(ObjCEncodeExpr *Exp) {
1321   // Create a new string expression.
1322   QualType StrType = Context->getPointerType(Context->CharTy);
1323   std::string StrEncoding;
1324   Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding, 
1325                                   EncodingRecordTypes);
1326   Expr *Replacement = new StringLiteral(StrEncoding.c_str(),
1327                                         StrEncoding.length(), false, StrType, 
1328                                         SourceLocation(), SourceLocation());
1329   ReplaceStmt(Exp, Replacement);
1330   
1331   // Replace this subexpr in the parent.
1332   delete Exp;
1333   return Replacement;
1334 }
1335
1336 Stmt *RewriteTest::RewriteAtSelector(ObjCSelectorExpr *Exp) {
1337   assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");
1338   // Create a call to sel_registerName("selName").
1339   llvm::SmallVector<Expr*, 8> SelExprs;
1340   QualType argType = Context->getPointerType(Context->CharTy);
1341   SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
1342                                        Exp->getSelector().getName().size(),
1343                                        false, argType, SourceLocation(),
1344                                        SourceLocation()));
1345   CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
1346                                                  &SelExprs[0], SelExprs.size());
1347   ReplaceStmt(Exp, SelExp);
1348   delete Exp;
1349   return SelExp;
1350 }
1351
1352 CallExpr *RewriteTest::SynthesizeCallToFunctionDecl(
1353   FunctionDecl *FD, Expr **args, unsigned nargs) {
1354   // Get the type, we will need to reference it in a couple spots.
1355   QualType msgSendType = FD->getType();
1356   
1357   // Create a reference to the objc_msgSend() declaration.
1358   DeclRefExpr *DRE = new DeclRefExpr(FD, msgSendType, SourceLocation());
1359                                      
1360   // Now, we cast the reference to a pointer to the objc_msgSend type.
1361   QualType pToFunc = Context->getPointerType(msgSendType);
1362   ImplicitCastExpr *ICE = new ImplicitCastExpr(pToFunc, DRE);
1363   
1364   const FunctionType *FT = msgSendType->getAsFunctionType();
1365   
1366   return new CallExpr(ICE, args, nargs, FT->getResultType(), SourceLocation());
1367 }
1368
1369 static bool scanForProtocolRefs(const char *startBuf, const char *endBuf,
1370                                 const char *&startRef, const char *&endRef) {
1371   while (startBuf < endBuf) {
1372     if (*startBuf == '<')
1373       startRef = startBuf; // mark the start.
1374     if (*startBuf == '>') {
1375       if (startRef && *startRef == '<') {
1376         endRef = startBuf; // mark the end.
1377         return true;
1378       }
1379       return false;
1380     }
1381     startBuf++;
1382   }
1383   return false;
1384 }
1385
1386 static void scanToNextArgument(const char *&argRef) {
1387   int angle = 0;
1388   while (*argRef != ')' && (*argRef != ',' || angle > 0)) {
1389     if (*argRef == '<')
1390       angle++;
1391     else if (*argRef == '>')
1392       angle--;
1393     argRef++;
1394   }
1395   assert(angle == 0 && "scanToNextArgument - bad protocol type syntax");
1396 }
1397
1398 bool RewriteTest::needToScanForQualifiers(QualType T) {
1399   
1400   if (T == Context->getObjCIdType())
1401     return true;
1402     
1403   if (T->isObjCQualifiedIdType())
1404     return true;
1405   
1406   if (const PointerType *pType = T->getAsPointerType()) {
1407     Type *pointeeType = pType->getPointeeType().getTypePtr();
1408     if (isa<ObjCQualifiedInterfaceType>(pointeeType))
1409       return true; // we have "Class <Protocol> *".
1410   }
1411   return false;
1412 }
1413
1414 void RewriteTest::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
1415   SourceLocation Loc;
1416   QualType Type;
1417   const FunctionTypeProto *proto = 0;
1418   if (VarDecl *VD = dyn_cast<VarDecl>(Dcl)) {
1419     Loc = VD->getLocation();
1420     Type = VD->getType();
1421   }
1422   else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Dcl)) {
1423     Loc = FD->getLocation();
1424     // Check for ObjC 'id' and class types that have been adorned with protocol
1425     // information (id<p>, C<p>*). The protocol references need to be rewritten!
1426     const FunctionType *funcType = FD->getType()->getAsFunctionType();
1427     assert(funcType && "missing function type");
1428     proto = dyn_cast<FunctionTypeProto>(funcType);
1429     if (!proto)
1430       return;
1431     Type = proto->getResultType();
1432   }
1433   else
1434     return;
1435   
1436   if (needToScanForQualifiers(Type)) {
1437     // Since types are unique, we need to scan the buffer.
1438     
1439     const char *endBuf = SM->getCharacterData(Loc);
1440     const char *startBuf = endBuf;
1441     while (*startBuf != ';' && startBuf != MainFileStart)
1442       startBuf--; // scan backward (from the decl location) for return type.
1443     const char *startRef = 0, *endRef = 0;
1444     if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
1445       // Get the locations of the startRef, endRef.
1446       SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-endBuf);
1447       SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-endBuf+1);
1448       // Comment out the protocol references.
1449       InsertText(LessLoc, "/*", 2);
1450       InsertText(GreaterLoc, "*/", 2);
1451     }
1452   }
1453   if (!proto)
1454       return; // most likely, was a variable
1455   // Now check arguments.
1456   const char *startBuf = SM->getCharacterData(Loc);
1457   const char *startFuncBuf = startBuf;
1458   for (unsigned i = 0; i < proto->getNumArgs(); i++) {
1459     if (needToScanForQualifiers(proto->getArgType(i))) {
1460       // Since types are unique, we need to scan the buffer.
1461       
1462       const char *endBuf = startBuf;
1463       // scan forward (from the decl location) for argument types.
1464       scanToNextArgument(endBuf);
1465       const char *startRef = 0, *endRef = 0;
1466       if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
1467         // Get the locations of the startRef, endRef.
1468         SourceLocation LessLoc = 
1469           Loc.getFileLocWithOffset(startRef-startFuncBuf);
1470         SourceLocation GreaterLoc = 
1471           Loc.getFileLocWithOffset(endRef-startFuncBuf+1);
1472         // Comment out the protocol references.
1473         InsertText(LessLoc, "/*", 2);
1474         InsertText(GreaterLoc, "*/", 2);
1475       }
1476       startBuf = ++endBuf;
1477     }
1478     else {
1479       while (*startBuf != ')' && *startBuf != ',')
1480         startBuf++; // scan forward (from the decl location) for argument types.
1481       startBuf++;
1482     }
1483   }
1484 }
1485
1486 // SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str);
1487 void RewriteTest::SynthSelGetUidFunctionDecl() {
1488   IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName");
1489   llvm::SmallVector<QualType, 16> ArgTys;
1490   ArgTys.push_back(Context->getPointerType(
1491     Context->CharTy.getQualifiedType(QualType::Const)));
1492   QualType getFuncType = Context->getFunctionType(Context->getObjCSelType(),
1493                                                    &ArgTys[0], ArgTys.size(),
1494                                                    false /*isVariadic*/);
1495   SelGetUidFunctionDecl = new FunctionDecl(SourceLocation(), 
1496                                            SelGetUidIdent, getFuncType,
1497                                            FunctionDecl::Extern, false, 0);
1498 }
1499
1500 // SynthGetProtocolFunctionDecl - Protocol objc_getProtocol(const char *proto);
1501 void RewriteTest::SynthGetProtocolFunctionDecl() {
1502   IdentifierInfo *SelGetProtoIdent = &Context->Idents.get("objc_getProtocol");
1503   llvm::SmallVector<QualType, 16> ArgTys;
1504   ArgTys.push_back(Context->getPointerType(
1505     Context->CharTy.getQualifiedType(QualType::Const)));
1506   QualType getFuncType = Context->getFunctionType(Context->getObjCProtoType(),
1507                                                   &ArgTys[0], ArgTys.size(),
1508                                                   false /*isVariadic*/);
1509   GetProtocolFunctionDecl = new FunctionDecl(SourceLocation(), 
1510                                              SelGetProtoIdent, getFuncType,
1511                                              FunctionDecl::Extern, false, 0);
1512 }
1513
1514 void RewriteTest::RewriteFunctionDecl(FunctionDecl *FD) {
1515   // declared in <objc/objc.h>
1516   if (strcmp(FD->getName(), "sel_registerName") == 0) {
1517     SelGetUidFunctionDecl = FD;
1518     return;
1519   }
1520   RewriteObjCQualifiedInterfaceTypes(FD);
1521 }
1522
1523 // SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
1524 void RewriteTest::SynthMsgSendFunctionDecl() {
1525   IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend");
1526   llvm::SmallVector<QualType, 16> ArgTys;
1527   QualType argT = Context->getObjCIdType();
1528   assert(!argT.isNull() && "Can't find 'id' type");
1529   ArgTys.push_back(argT);
1530   argT = Context->getObjCSelType();
1531   assert(!argT.isNull() && "Can't find 'SEL' type");
1532   ArgTys.push_back(argT);
1533   QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
1534                                                   &ArgTys[0], ArgTys.size(),
1535                                                   true /*isVariadic*/);
1536   MsgSendFunctionDecl = new FunctionDecl(SourceLocation(), 
1537                                          msgSendIdent, msgSendType,
1538                                          FunctionDecl::Extern, false, 0);
1539 }
1540
1541 // SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...);
1542 void RewriteTest::SynthMsgSendSuperFunctionDecl() {
1543   IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper");
1544   llvm::SmallVector<QualType, 16> ArgTys;
1545   RecordDecl *RD = new RecordDecl(Decl::Struct, SourceLocation(),
1546                                   &Context->Idents.get("objc_super"), 0);
1547   QualType argT = Context->getPointerType(Context->getTagDeclType(RD));
1548   assert(!argT.isNull() && "Can't build 'struct objc_super *' type");
1549   ArgTys.push_back(argT);
1550   argT = Context->getObjCSelType();
1551   assert(!argT.isNull() && "Can't find 'SEL' type");
1552   ArgTys.push_back(argT);
1553   QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
1554                                                   &ArgTys[0], ArgTys.size(),
1555                                                   true /*isVariadic*/);
1556   MsgSendSuperFunctionDecl = new FunctionDecl(SourceLocation(), 
1557                                               msgSendIdent, msgSendType,
1558                                               FunctionDecl::Extern, false, 0);
1559 }
1560
1561 // SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...);
1562 void RewriteTest::SynthMsgSendStretFunctionDecl() {
1563   IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_stret");
1564   llvm::SmallVector<QualType, 16> ArgTys;
1565   QualType argT = Context->getObjCIdType();
1566   assert(!argT.isNull() && "Can't find 'id' type");
1567   ArgTys.push_back(argT);
1568   argT = Context->getObjCSelType();
1569   assert(!argT.isNull() && "Can't find 'SEL' type");
1570   ArgTys.push_back(argT);
1571   QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
1572                                                   &ArgTys[0], ArgTys.size(),
1573                                                   true /*isVariadic*/);
1574   MsgSendStretFunctionDecl = new FunctionDecl(SourceLocation(), 
1575                                          msgSendIdent, msgSendType,
1576                                          FunctionDecl::Extern, false, 0);
1577 }
1578
1579 // SynthMsgSendSuperStretFunctionDecl - 
1580 // id objc_msgSendSuper_stret(struct objc_super *, SEL op, ...);
1581 void RewriteTest::SynthMsgSendSuperStretFunctionDecl() {
1582   IdentifierInfo *msgSendIdent = 
1583     &Context->Idents.get("objc_msgSendSuper_stret");
1584   llvm::SmallVector<QualType, 16> ArgTys;
1585   RecordDecl *RD = new RecordDecl(Decl::Struct, SourceLocation(),
1586                                   &Context->Idents.get("objc_super"), 0);
1587   QualType argT = Context->getPointerType(Context->getTagDeclType(RD));
1588   assert(!argT.isNull() && "Can't build 'struct objc_super *' type");
1589   ArgTys.push_back(argT);
1590   argT = Context->getObjCSelType();
1591   assert(!argT.isNull() && "Can't find 'SEL' type");
1592   ArgTys.push_back(argT);
1593   QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
1594                                                   &ArgTys[0], ArgTys.size(),
1595                                                   true /*isVariadic*/);
1596   MsgSendSuperStretFunctionDecl = new FunctionDecl(SourceLocation(), 
1597                                               msgSendIdent, msgSendType,
1598                                               FunctionDecl::Extern, false, 0);
1599 }
1600
1601 // SynthMsgSendFpretFunctionDecl - id objc_msgSend_fpret(id self, SEL op, ...);
1602 void RewriteTest::SynthMsgSendFpretFunctionDecl() {
1603   IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_fpret");
1604   llvm::SmallVector<QualType, 16> ArgTys;
1605   QualType argT = Context->getObjCIdType();
1606   assert(!argT.isNull() && "Can't find 'id' type");
1607   ArgTys.push_back(argT);
1608   argT = Context->getObjCSelType();
1609   assert(!argT.isNull() && "Can't find 'SEL' type");
1610   ArgTys.push_back(argT);
1611   QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
1612                                                   &ArgTys[0], ArgTys.size(),
1613                                                   true /*isVariadic*/);
1614   MsgSendFpretFunctionDecl = new FunctionDecl(SourceLocation(), 
1615                                               msgSendIdent, msgSendType,
1616                                               FunctionDecl::Extern, false, 0);
1617 }
1618
1619 // SynthGetClassFunctionDecl - id objc_getClass(const char *name);
1620 void RewriteTest::SynthGetClassFunctionDecl() {
1621   IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass");
1622   llvm::SmallVector<QualType, 16> ArgTys;
1623   ArgTys.push_back(Context->getPointerType(
1624                      Context->CharTy.getQualifiedType(QualType::Const)));
1625   QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
1626                                                    &ArgTys[0], ArgTys.size(),
1627                                                    false /*isVariadic*/);
1628   GetClassFunctionDecl = new FunctionDecl(SourceLocation(), 
1629                                           getClassIdent, getClassType,
1630                                           FunctionDecl::Extern, false, 0);
1631 }
1632
1633 // SynthGetMetaClassFunctionDecl - id objc_getClass(const char *name);
1634 void RewriteTest::SynthGetMetaClassFunctionDecl() {
1635   IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass");
1636   llvm::SmallVector<QualType, 16> ArgTys;
1637   ArgTys.push_back(Context->getPointerType(
1638                      Context->CharTy.getQualifiedType(QualType::Const)));
1639   QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
1640                                                    &ArgTys[0], ArgTys.size(),
1641                                                    false /*isVariadic*/);
1642   GetMetaClassFunctionDecl = new FunctionDecl(SourceLocation(), 
1643                                               getClassIdent, getClassType,
1644                                               FunctionDecl::Extern, false, 0);
1645 }
1646
1647 // SynthCFStringFunctionDecl - id __builtin___CFStringMakeConstantString(const char *name);
1648 void RewriteTest::SynthCFStringFunctionDecl() {
1649   IdentifierInfo *getClassIdent = &Context->Idents.get("__builtin___CFStringMakeConstantString");
1650   llvm::SmallVector<QualType, 16> ArgTys;
1651   ArgTys.push_back(Context->getPointerType(
1652                      Context->CharTy.getQualifiedType(QualType::Const)));
1653   QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
1654                                                    &ArgTys[0], ArgTys.size(),
1655                                                    false /*isVariadic*/);
1656   CFStringFunctionDecl = new FunctionDecl(SourceLocation(), 
1657                                           getClassIdent, getClassType,
1658                                           FunctionDecl::Extern, false, 0);
1659 }
1660
1661 Stmt *RewriteTest::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
1662 #if 1
1663   // This rewrite is specific to GCC, which has builtin support for CFString.
1664   if (!CFStringFunctionDecl)
1665     SynthCFStringFunctionDecl();
1666   // Create a call to __builtin___CFStringMakeConstantString("cstr").
1667   llvm::SmallVector<Expr*, 8> StrExpr;
1668   StrExpr.push_back(Exp->getString());
1669   CallExpr *call = SynthesizeCallToFunctionDecl(CFStringFunctionDecl,
1670                                                 &StrExpr[0], StrExpr.size());
1671   // cast to NSConstantString *
1672   CastExpr *cast = new CastExpr(Exp->getType(), call, SourceLocation());
1673   ReplaceStmt(Exp, cast);
1674   delete Exp;
1675   return cast;
1676 #else
1677   assert(ConstantStringClassReference && "Can't find constant string reference");
1678   llvm::SmallVector<Expr*, 4> InitExprs;
1679   
1680   // Synthesize "(Class)&_NSConstantStringClassReference"
1681   DeclRefExpr *ClsRef = new DeclRefExpr(ConstantStringClassReference,
1682                                         ConstantStringClassReference->getType(),
1683                                         SourceLocation());
1684   QualType expType = Context->getPointerType(ClsRef->getType());
1685   UnaryOperator *Unop = new UnaryOperator(ClsRef, UnaryOperator::AddrOf,
1686                                           expType, SourceLocation());
1687   CastExpr *cast = new CastExpr(Context->getObjCClassType(), Unop, 
1688                                 SourceLocation());
1689   InitExprs.push_back(cast); // set the 'isa'.
1690   InitExprs.push_back(Exp->getString()); // set "char *bytes".
1691   unsigned IntSize = static_cast<unsigned>(
1692       Context->getTypeSize(Context->IntTy, Exp->getLocStart()));
1693   llvm::APInt IntVal(IntSize, Exp->getString()->getByteLength());
1694   IntegerLiteral *len = new IntegerLiteral(IntVal, Context->IntTy, 
1695                                            Exp->getLocStart());
1696   InitExprs.push_back(len); // set "int numBytes".
1697   
1698   // struct NSConstantString
1699   QualType CFConstantStrType = Context->getCFConstantStringType();
1700   // (struct NSConstantString) { <exprs from above> }
1701   InitListExpr *ILE = new InitListExpr(SourceLocation(), 
1702                                        &InitExprs[0], InitExprs.size(), 
1703                                        SourceLocation());
1704   CompoundLiteralExpr *StrRep = new CompoundLiteralExpr(CFConstantStrType, ILE, false);
1705   // struct NSConstantString *
1706   expType = Context->getPointerType(StrRep->getType());
1707   Unop = new UnaryOperator(StrRep, UnaryOperator::AddrOf, expType, 
1708                            SourceLocation());
1709   // cast to NSConstantString *
1710   cast = new CastExpr(Exp->getType(), Unop, SourceLocation());
1711   ReplaceStmt(Exp, cast);
1712   delete Exp;
1713   return cast;
1714 #endif
1715 }
1716
1717 ObjCInterfaceDecl *RewriteTest::isSuperReceiver(Expr *recExpr) {
1718   // check if we are sending a message to 'super'
1719   if (CurMethodDecl && CurMethodDecl->isInstance()) {
1720     if (CastExpr *CE = dyn_cast<CastExpr>(recExpr)) {
1721       if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) {
1722         if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
1723           if (!strcmp(PVD->getName(), "self")) {
1724             // is this id<P1..> type?
1725             if (CE->getType()->isObjCQualifiedIdType())
1726               return 0;
1727             if (const PointerType *PT = CE->getType()->getAsPointerType()) {
1728               if (ObjCInterfaceType *IT = 
1729                     dyn_cast<ObjCInterfaceType>(PT->getPointeeType())) {
1730                 if (IT->getDecl() == 
1731                     CurMethodDecl->getClassInterface()->getSuperClass())
1732                   return IT->getDecl();
1733               }
1734             }
1735           }
1736         }
1737       }
1738     }
1739   }
1740   return 0;
1741 }
1742
1743 // struct objc_super { struct objc_object *receiver; struct objc_class *super; };
1744 QualType RewriteTest::getSuperStructType() {
1745   if (!SuperStructDecl) {
1746     SuperStructDecl = new RecordDecl(Decl::Struct, SourceLocation(), 
1747                                      &Context->Idents.get("objc_super"), 0);
1748     QualType FieldTypes[2];
1749   
1750     // struct objc_object *receiver;
1751     FieldTypes[0] = Context->getObjCIdType();  
1752     // struct objc_class *super;
1753     FieldTypes[1] = Context->getObjCClassType();  
1754     // Create fields
1755     FieldDecl *FieldDecls[2];
1756   
1757     for (unsigned i = 0; i < 2; ++i)
1758       FieldDecls[i] = new FieldDecl(SourceLocation(), 0, FieldTypes[i]);
1759   
1760     SuperStructDecl->defineBody(FieldDecls, 4);
1761   }
1762   return Context->getTagDeclType(SuperStructDecl);
1763 }
1764
1765 Stmt *RewriteTest::SynthMessageExpr(ObjCMessageExpr *Exp) {
1766   if (!SelGetUidFunctionDecl)
1767     SynthSelGetUidFunctionDecl();
1768   if (!MsgSendFunctionDecl)
1769     SynthMsgSendFunctionDecl();
1770   if (!MsgSendSuperFunctionDecl)
1771     SynthMsgSendSuperFunctionDecl();
1772   if (!MsgSendStretFunctionDecl)
1773     SynthMsgSendStretFunctionDecl();
1774   if (!MsgSendSuperStretFunctionDecl)
1775     SynthMsgSendSuperStretFunctionDecl();
1776   if (!MsgSendFpretFunctionDecl)
1777     SynthMsgSendFpretFunctionDecl();
1778   if (!GetClassFunctionDecl)
1779     SynthGetClassFunctionDecl();
1780   if (!GetMetaClassFunctionDecl)
1781     SynthGetMetaClassFunctionDecl();
1782   
1783   // default to objc_msgSend().
1784   FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl;
1785   // May need to use objc_msgSend_stret() as well.
1786   FunctionDecl *MsgSendStretFlavor = 0;
1787   if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) {
1788     QualType resultType = mDecl->getResultType();
1789     if (resultType.getCanonicalType()->isStructureType() 
1790         || resultType.getCanonicalType()->isUnionType())
1791       MsgSendStretFlavor = MsgSendStretFunctionDecl;
1792     else if (resultType.getCanonicalType()->isRealFloatingType())
1793       MsgSendFlavor = MsgSendFpretFunctionDecl;
1794   }
1795   
1796   // Synthesize a call to objc_msgSend().
1797   llvm::SmallVector<Expr*, 8> MsgExprs;
1798   IdentifierInfo *clsName = Exp->getClassName();
1799   
1800   // Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend().
1801   if (clsName) { // class message.
1802     if (!strcmp(clsName->getName(), "super")) {
1803       MsgSendFlavor = MsgSendSuperFunctionDecl;
1804       if (MsgSendStretFlavor)
1805         MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
1806       assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
1807       
1808       ObjCInterfaceDecl *SuperDecl = 
1809         CurMethodDecl->getClassInterface()->getSuperClass();
1810
1811       llvm::SmallVector<Expr*, 4> InitExprs;
1812       
1813       // set the receiver to self, the first argument to all methods.
1814       InitExprs.push_back(new DeclRefExpr(CurMethodDecl->getSelfDecl(), 
1815                                           Context->getObjCIdType(),
1816                                           SourceLocation())); 
1817       llvm::SmallVector<Expr*, 8> ClsExprs;
1818       QualType argType = Context->getPointerType(Context->CharTy);
1819       ClsExprs.push_back(new StringLiteral(SuperDecl->getIdentifier()->getName(), 
1820                                            SuperDecl->getIdentifier()->getLength(),
1821                                            false, argType, SourceLocation(),
1822                                            SourceLocation()));
1823       CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
1824                                                    &ClsExprs[0], 
1825                                                    ClsExprs.size());
1826       // To turn off a warning, type-cast to 'id'
1827       InitExprs.push_back(
1828         new CastExpr(Context->getObjCIdType(), 
1829         Cls, SourceLocation())); // set 'super class', using objc_getClass().
1830       // struct objc_super
1831       QualType superType = getSuperStructType();
1832       // (struct objc_super) { <exprs from above> }
1833       InitListExpr *ILE = new InitListExpr(SourceLocation(), 
1834                                            &InitExprs[0], InitExprs.size(), 
1835                                            SourceLocation());
1836       CompoundLiteralExpr *SuperRep = new CompoundLiteralExpr(SourceLocation(),
1837                                                               superType, ILE, false);
1838       // struct objc_super *
1839       Expr *Unop = new UnaryOperator(SuperRep, UnaryOperator::AddrOf,
1840                                Context->getPointerType(SuperRep->getType()), 
1841                                SourceLocation());
1842       MsgExprs.push_back(Unop);
1843     } else {
1844       llvm::SmallVector<Expr*, 8> ClsExprs;
1845       QualType argType = Context->getPointerType(Context->CharTy);
1846       ClsExprs.push_back(new StringLiteral(clsName->getName(), 
1847                                            clsName->getLength(),
1848                                            false, argType, SourceLocation(),
1849                                            SourceLocation()));
1850       CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
1851                                                    &ClsExprs[0], 
1852                                                    ClsExprs.size());
1853       MsgExprs.push_back(Cls);
1854     }
1855   } else { // instance message.
1856     Expr *recExpr = Exp->getReceiver();
1857
1858     if (ObjCInterfaceDecl *SuperDecl = isSuperReceiver(recExpr)) {
1859       MsgSendFlavor = MsgSendSuperFunctionDecl;
1860       if (MsgSendStretFlavor)
1861         MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
1862       assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
1863       
1864       llvm::SmallVector<Expr*, 4> InitExprs;
1865       
1866       InitExprs.push_back(
1867         new CastExpr(Context->getObjCIdType(), 
1868                      recExpr, SourceLocation())); // set the 'receiver'.
1869       
1870       llvm::SmallVector<Expr*, 8> ClsExprs;
1871       QualType argType = Context->getPointerType(Context->CharTy);
1872       ClsExprs.push_back(new StringLiteral(SuperDecl->getIdentifier()->getName(), 
1873                                            SuperDecl->getIdentifier()->getLength(),
1874                                            false, argType, SourceLocation(),
1875                                            SourceLocation()));
1876       CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
1877                                                    &ClsExprs[0], 
1878                                                    ClsExprs.size());
1879       // To turn off a warning, type-cast to 'id'
1880       InitExprs.push_back(
1881         new CastExpr(Context->getObjCIdType(), 
1882         Cls, SourceLocation())); // set 'super class', using objc_getClass().
1883       // struct objc_super
1884       QualType superType = getSuperStructType();
1885       // (struct objc_super) { <exprs from above> }
1886       InitListExpr *ILE = new InitListExpr(SourceLocation(), 
1887                                            &InitExprs[0], InitExprs.size(), 
1888                                            SourceLocation());
1889       CompoundLiteralExpr *SuperRep = new CompoundLiteralExpr(SourceLocation(),
1890                                                               superType, ILE, false);
1891       // struct objc_super *
1892       Expr *Unop = new UnaryOperator(SuperRep, UnaryOperator::AddrOf,
1893                                Context->getPointerType(SuperRep->getType()), 
1894                                SourceLocation());
1895       MsgExprs.push_back(Unop);
1896     } else {
1897       // Remove all type-casts because it may contain objc-style types; e.g.
1898       // Foo<Proto> *.
1899       while (CastExpr *CE = dyn_cast<CastExpr>(recExpr))
1900         recExpr = CE->getSubExpr();
1901       recExpr = new CastExpr(Context->getObjCIdType(), recExpr, SourceLocation());
1902       MsgExprs.push_back(recExpr);
1903     }
1904   }
1905   // Create a call to sel_registerName("selName"), it will be the 2nd argument.
1906   llvm::SmallVector<Expr*, 8> SelExprs;
1907   QualType argType = Context->getPointerType(Context->CharTy);
1908   SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
1909                                        Exp->getSelector().getName().size(),
1910                                        false, argType, SourceLocation(),
1911                                        SourceLocation()));
1912   CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
1913                                                  &SelExprs[0], SelExprs.size());
1914   MsgExprs.push_back(SelExp);
1915   
1916   // Now push any user supplied arguments.
1917   for (unsigned i = 0; i < Exp->getNumArgs(); i++) {
1918     Expr *userExpr = Exp->getArg(i);
1919     // Make all implicit casts explicit...ICE comes in handy:-)
1920     if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) {
1921       // Reuse the ICE type, it is exactly what the doctor ordered.
1922       userExpr = new CastExpr(ICE->getType()->isObjCQualifiedIdType()
1923                                 ? Context->getObjCIdType()
1924                                 : ICE->getType(), userExpr, SourceLocation());
1925     }
1926     // Make id<P...> cast into an 'id' cast.
1927     else if (CastExpr *CE = dyn_cast<CastExpr>(userExpr)) {
1928       if (CE->getType()->isObjCQualifiedIdType()) {
1929         while ((CE = dyn_cast<CastExpr>(userExpr)))
1930           userExpr = CE->getSubExpr();
1931         userExpr = new CastExpr(Context->getObjCIdType(), 
1932                                 userExpr, SourceLocation());
1933       }
1934     } 
1935     MsgExprs.push_back(userExpr);
1936     // We've transferred the ownership to MsgExprs. Null out the argument in
1937     // the original expression, since we will delete it below.
1938     Exp->setArg(i, 0);
1939   }
1940   // Generate the funky cast.
1941   CastExpr *cast;
1942   llvm::SmallVector<QualType, 8> ArgTypes;
1943   QualType returnType;
1944   
1945   // Push 'id' and 'SEL', the 2 implicit arguments.
1946   if (MsgSendFlavor == MsgSendSuperFunctionDecl)
1947     ArgTypes.push_back(Context->getPointerType(getSuperStructType()));
1948   else
1949     ArgTypes.push_back(Context->getObjCIdType());
1950   ArgTypes.push_back(Context->getObjCSelType());
1951   if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) {
1952     // Push any user argument types.
1953     for (int i = 0; i < mDecl->getNumParams(); i++) {
1954       QualType t = mDecl->getParamDecl(i)->getType()->isObjCQualifiedIdType()
1955                      ? Context->getObjCIdType() 
1956                      : mDecl->getParamDecl(i)->getType();
1957       ArgTypes.push_back(t);
1958     }
1959     returnType = mDecl->getResultType()->isObjCQualifiedIdType()
1960                    ? Context->getObjCIdType() : mDecl->getResultType();
1961   } else {
1962     returnType = Context->getObjCIdType();
1963   }
1964   // Get the type, we will need to reference it in a couple spots.
1965   QualType msgSendType = MsgSendFlavor->getType();
1966   
1967   // Create a reference to the objc_msgSend() declaration.
1968   DeclRefExpr *DRE = new DeclRefExpr(MsgSendFlavor, msgSendType, 
1969                                      SourceLocation());
1970
1971   // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid). 
1972   // If we don't do this cast, we get the following bizarre warning/note:
1973   // xx.m:13: warning: function called through a non-compatible type
1974   // xx.m:13: note: if this code is reached, the program will abort
1975   cast = new CastExpr(Context->getPointerType(Context->VoidTy), DRE, 
1976                       SourceLocation());
1977     
1978   // Now do the "normal" pointer to function cast.
1979   QualType castType = Context->getFunctionType(returnType, 
1980     &ArgTypes[0], ArgTypes.size(),
1981     Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false);
1982   castType = Context->getPointerType(castType);
1983   cast = new CastExpr(castType, cast, SourceLocation());
1984
1985   // Don't forget the parens to enforce the proper binding.
1986   ParenExpr *PE = new ParenExpr(SourceLocation(), SourceLocation(), cast);
1987   
1988   const FunctionType *FT = msgSendType->getAsFunctionType();
1989   CallExpr *CE = new CallExpr(PE, &MsgExprs[0], MsgExprs.size(), 
1990                               FT->getResultType(), SourceLocation());
1991   Stmt *ReplacingStmt = CE;
1992   if (MsgSendStretFlavor) {
1993     // We have the method which returns a struct/union. Must also generate
1994     // call to objc_msgSend_stret and hang both varieties on a conditional
1995     // expression which dictate which one to envoke depending on size of
1996     // method's return type.
1997     
1998     // Create a reference to the objc_msgSend_stret() declaration.
1999     DeclRefExpr *STDRE = new DeclRefExpr(MsgSendStretFlavor, msgSendType, 
2000                                          SourceLocation());
2001     // Need to cast objc_msgSend_stret to "void *" (see above comment).
2002     cast = new CastExpr(Context->getPointerType(Context->VoidTy), STDRE, 
2003                         SourceLocation());
2004     // Now do the "normal" pointer to function cast.
2005     castType = Context->getFunctionType(returnType, 
2006       &ArgTypes[0], ArgTypes.size(),
2007       Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false);
2008     castType = Context->getPointerType(castType);
2009     cast = new CastExpr(castType, cast, SourceLocation());
2010     
2011     // Don't forget the parens to enforce the proper binding.
2012     PE = new ParenExpr(SourceLocation(), SourceLocation(), cast);
2013     
2014     FT = msgSendType->getAsFunctionType();
2015     CallExpr *STCE = new CallExpr(PE, &MsgExprs[0], MsgExprs.size(), 
2016                                   FT->getResultType(), SourceLocation());
2017     
2018     // Build sizeof(returnType)
2019     SizeOfAlignOfTypeExpr *sizeofExpr = new SizeOfAlignOfTypeExpr(true, 
2020                                           returnType, Context->getSizeType(), 
2021                                           SourceLocation(), SourceLocation());
2022     // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
2023     // FIXME: Value of 8 is base on ppc32/x86 ABI for the most common cases.
2024     // For X86 it is more complicated and some kind of target specific routine
2025     // is needed to decide what to do.
2026     unsigned IntSize = static_cast<unsigned>(
2027       Context->getTypeSize(Context->IntTy, SourceLocation()));
2028
2029     IntegerLiteral *limit = new IntegerLiteral(llvm::APInt(IntSize, 8), 
2030                                                Context->IntTy,
2031                                                SourceLocation());
2032     BinaryOperator *lessThanExpr = new BinaryOperator(sizeofExpr, limit, 
2033                                                       BinaryOperator::LE, 
2034                                                       Context->IntTy, 
2035                                                       SourceLocation());
2036     // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
2037     ConditionalOperator *CondExpr = 
2038       new ConditionalOperator(lessThanExpr, CE, STCE, returnType);
2039     ReplacingStmt = new ParenExpr(SourceLocation(), SourceLocation(), CondExpr);
2040   }
2041   return ReplacingStmt;
2042 }
2043
2044 Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) {
2045   Stmt *ReplacingStmt = SynthMessageExpr(Exp);
2046   // Now do the actual rewrite.
2047   ReplaceStmt(Exp, ReplacingStmt);
2048   
2049   delete Exp;
2050   return ReplacingStmt;
2051 }
2052
2053 /// RewriteObjCProtocolExpr - Rewrite a protocol expression into
2054 /// call to objc_getProtocol("proto-name").
2055 Stmt *RewriteTest::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
2056   if (!GetProtocolFunctionDecl)
2057     SynthGetProtocolFunctionDecl();
2058   // Create a call to objc_getProtocol("ProtocolName").
2059   llvm::SmallVector<Expr*, 8> ProtoExprs;
2060   QualType argType = Context->getPointerType(Context->CharTy);
2061   ProtoExprs.push_back(new StringLiteral(Exp->getProtocol()->getName(),
2062                                        strlen(Exp->getProtocol()->getName()),
2063                                        false, argType, SourceLocation(),
2064                                        SourceLocation()));
2065   CallExpr *ProtoExp = SynthesizeCallToFunctionDecl(GetProtocolFunctionDecl,
2066                                                     &ProtoExprs[0], 
2067                                                     ProtoExprs.size());
2068   ReplaceStmt(Exp, ProtoExp);
2069   delete Exp;
2070   return ProtoExp;
2071   
2072 }
2073
2074 /// SynthesizeObjCInternalStruct - Rewrite one internal struct corresponding to
2075 /// an objective-c class with ivars.
2076 void RewriteTest::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
2077                                                std::string &Result) {
2078   assert(CDecl && "Class missing in SynthesizeObjCInternalStruct");
2079   assert(CDecl->getName() && "Name missing in SynthesizeObjCInternalStruct");
2080   // Do not synthesize more than once.
2081   if (ObjCSynthesizedStructs.count(CDecl))
2082     return;
2083   ObjCInterfaceDecl *RCDecl = CDecl->getSuperClass();
2084   int NumIvars = CDecl->getNumInstanceVariables();
2085   SourceLocation LocStart = CDecl->getLocStart();
2086   SourceLocation LocEnd = CDecl->getLocEnd();
2087   
2088   const char *startBuf = SM->getCharacterData(LocStart);
2089   const char *endBuf = SM->getCharacterData(LocEnd);
2090   // If no ivars and no root or if its root, directly or indirectly,
2091   // have no ivars (thus not synthesized) then no need to synthesize this class.
2092   if (NumIvars <= 0 && (!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) {
2093     endBuf += Lexer::MeasureTokenLength(LocEnd, *SM);
2094     ReplaceText(LocStart, endBuf-startBuf, Result.c_str(), Result.size());
2095     return;
2096   }
2097   
2098   // FIXME: This has potential of causing problem. If 
2099   // SynthesizeObjCInternalStruct is ever called recursively.
2100   Result += "\nstruct ";
2101   Result += CDecl->getName();
2102   
2103   if (NumIvars > 0) {
2104     const char *cursor = strchr(startBuf, '{');
2105     assert((cursor && endBuf) 
2106            && "SynthesizeObjCInternalStruct - malformed @interface");
2107     
2108     // rewrite the original header *without* disturbing the '{'
2109     ReplaceText(LocStart, cursor-startBuf-1, Result.c_str(), Result.size());
2110     if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) {
2111       Result = "\n    struct ";
2112       Result += RCDecl->getName();
2113       // Note: We don't name the field decl. This simplifies the "codegen" for
2114       // accessing a superclasses instance variables (and is similar to what gcc
2115       // does internally). The unnamed struct field feature is enabled with
2116       // -fms-extensions. If the struct definition were "inlined", we wouldn't
2117       // need to use this switch. That said, I don't want to inline the def.
2118       Result += ";\n";
2119       
2120       // insert the super class structure definition.
2121       SourceLocation OnePastCurly =
2122         LocStart.getFileLocWithOffset(cursor-startBuf+1);
2123       InsertText(OnePastCurly, Result.c_str(), Result.size());
2124     }
2125     cursor++; // past '{'
2126     
2127     // Now comment out any visibility specifiers.
2128     while (cursor < endBuf) {
2129       if (*cursor == '@') {
2130         SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
2131         // Skip whitespace.
2132         for (++cursor; cursor[0] == ' ' || cursor[0] == '\t'; ++cursor)
2133           /*scan*/;
2134
2135         // FIXME: presence of @public, etc. inside comment results in
2136         // this transformation as well, which is still correct c-code.
2137         if (!strncmp(cursor, "public", strlen("public")) ||
2138             !strncmp(cursor, "private", strlen("private")) ||
2139             !strncmp(cursor, "protected", strlen("protected")))
2140           InsertText(atLoc, "// ", 3);
2141       }
2142       // FIXME: If there are cases where '<' is used in ivar declaration part
2143       // of user code, then scan the ivar list and use needToScanForQualifiers
2144       // for type checking.
2145       else if (*cursor == '<') {
2146         SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
2147         InsertText(atLoc, "/* ", 3);
2148         cursor = strchr(cursor, '>');
2149         cursor++;
2150         atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
2151         InsertText(atLoc, " */", 3);
2152       }
2153       cursor++;
2154     }
2155     // Don't forget to add a ';'!!
2156     InsertText(LocEnd.getFileLocWithOffset(1), ";", 1);
2157   } else { // we don't have any instance variables - insert super struct.
2158     endBuf += Lexer::MeasureTokenLength(LocEnd, *SM);
2159     Result += " {\n    struct ";
2160     Result += RCDecl->getName();
2161     // Note: We don't name the field decl. This simplifies the "codegen" for
2162     // accessing a superclasses instance variables (and is similar to what gcc
2163     // does internally). The unnamed struct field feature is enabled with
2164     // -fms-extensions. If the struct definition were "inlined", we wouldn't
2165     // need to use this switch. That said, I don't want to inline the def.
2166     Result += ";\n};\n";
2167     ReplaceText(LocStart, endBuf-startBuf, Result.c_str(), Result.size());
2168   }
2169   // Mark this struct as having been generated.
2170   if (!ObjCSynthesizedStructs.insert(CDecl))
2171   assert(false && "struct already synthesize- SynthesizeObjCInternalStruct");
2172 }
2173
2174 // RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or
2175 /// class methods.
2176 void RewriteTest::RewriteObjCMethodsMetaData(instmeth_iterator MethodBegin,
2177                                              instmeth_iterator MethodEnd,
2178                                              bool IsInstanceMethod,
2179                                              const char *prefix,
2180                                              const char *ClassName,
2181                                              std::string &Result) {
2182   if (MethodBegin == MethodEnd) return;
2183   
2184   static bool objc_impl_method = false;
2185   if (!objc_impl_method) {
2186     /* struct _objc_method {
2187        SEL _cmd;
2188        char *method_types;
2189        void *_imp;
2190        }
2191      */
2192     Result += "\nstruct _objc_method {\n";
2193     Result += "\tSEL _cmd;\n";
2194     Result += "\tchar *method_types;\n";
2195     Result += "\tvoid *_imp;\n";
2196     Result += "};\n";
2197     
2198     /* struct _objc_method_list {
2199      struct _objc_method_list *next_method;
2200      int method_count;
2201      struct _objc_method method_list[];
2202      }
2203      */
2204     Result += "\nstruct _objc_method_list {\n";
2205     Result += "\tstruct _objc_method_list *next_method;\n";
2206     Result += "\tint method_count;\n";
2207     Result += "\tstruct _objc_method method_list[];\n};\n";
2208     objc_impl_method = true;
2209   }
2210   
2211   // Build _objc_method_list for class's methods if needed
2212   Result += "\nstatic struct _objc_method_list _OBJC_";
2213   Result += prefix;
2214   Result += IsInstanceMethod ? "INSTANCE" : "CLASS";
2215   Result += "_METHODS_";
2216   Result += ClassName;
2217   Result += " __attribute__ ((section (\"__OBJC, __";
2218   Result += IsInstanceMethod ? "inst" : "cls";
2219   Result += "_meth\")))= ";
2220   Result += "{\n\t0, " + utostr(MethodEnd-MethodBegin) + "\n";
2221
2222   Result += "\t,{{(SEL)\"";
2223   Result += (*MethodBegin)->getSelector().getName().c_str();
2224   std::string MethodTypeString;
2225   Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
2226   Result += "\", \"";
2227   Result += MethodTypeString;
2228   Result += "\", ";
2229   Result += MethodInternalNames[*MethodBegin];
2230   Result += "}\n";
2231   for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) {
2232     Result += "\t  ,{(SEL)\"";
2233     Result += (*MethodBegin)->getSelector().getName().c_str();
2234     std::string MethodTypeString;
2235     Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
2236     Result += "\", \"";
2237     Result += MethodTypeString;
2238     Result += "\", ";
2239     Result += MethodInternalNames[*MethodBegin];
2240     Result += "}\n";
2241   }
2242   Result += "\t }\n};\n";
2243 }
2244
2245 /// RewriteObjCProtocolsMetaData - Rewrite protocols meta-data.
2246 void RewriteTest::RewriteObjCProtocolsMetaData(ObjCProtocolDecl **Protocols,
2247                                                int NumProtocols,
2248                                                const char *prefix,
2249                                                const char *ClassName,
2250                                                std::string &Result) {
2251   static bool objc_protocol_methods = false;
2252   if (NumProtocols > 0) {
2253     for (int i = 0; i < NumProtocols; i++) {
2254       ObjCProtocolDecl *PDecl = Protocols[i];
2255       // Output struct protocol_methods holder of method selector and type.
2256       if (!objc_protocol_methods &&
2257           (PDecl->getNumInstanceMethods() > 0 
2258            || PDecl->getNumClassMethods() > 0)) {
2259         /* struct protocol_methods {
2260          SEL _cmd;
2261          char *method_types;
2262          }
2263          */
2264         Result += "\nstruct protocol_methods {\n";
2265         Result += "\tSEL _cmd;\n";
2266         Result += "\tchar *method_types;\n";
2267         Result += "};\n";
2268         
2269         /* struct _objc_protocol_method_list {
2270          int protocol_method_count;
2271          struct protocol_methods protocols[];
2272          }
2273          */
2274         Result += "\nstruct _objc_protocol_method_list {\n";
2275         Result += "\tint protocol_method_count;\n";
2276         Result += "\tstruct protocol_methods protocols[];\n};\n";
2277         objc_protocol_methods = true;
2278       }
2279       
2280       int NumMethods = PDecl->getNumInstanceMethods();
2281       if(NumMethods > 0) {
2282         Result += "\nstatic struct _objc_protocol_method_list "
2283                "_OBJC_PROTOCOL_INSTANCE_METHODS_";
2284         Result += PDecl->getName();
2285         Result += " __attribute__ ((section (\"__OBJC, __cat_inst_meth\")))= "
2286           "{\n\t" + utostr(NumMethods) + "\n";
2287         
2288         // Output instance methods declared in this protocol.
2289         for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(), 
2290              E = PDecl->instmeth_end(); I != E; ++I) {
2291           if (I == PDecl->instmeth_begin())
2292             Result += "\t  ,{{(SEL)\"";
2293           else
2294             Result += "\t  ,{(SEL)\"";
2295           Result += (*I)->getSelector().getName().c_str();
2296           std::string MethodTypeString;
2297           Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
2298           Result += "\", \"";
2299           Result += MethodTypeString;
2300           Result += "\"}\n";
2301         }
2302         Result += "\t }\n};\n";
2303       }
2304       
2305       // Output class methods declared in this protocol.
2306       NumMethods = PDecl->getNumClassMethods();
2307       if (NumMethods > 0) {
2308         Result += "\nstatic struct _objc_protocol_method_list "
2309                "_OBJC_PROTOCOL_CLASS_METHODS_";
2310         Result += PDecl->getName();
2311         Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
2312                "{\n\t";
2313         Result += utostr(NumMethods);
2314         Result += "\n";
2315         
2316         // Output instance methods declared in this protocol.
2317         for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(), 
2318              E = PDecl->classmeth_end(); I != E; ++I) {
2319           if (I == PDecl->classmeth_begin())
2320             Result += "\t  ,{{(SEL)\"";
2321           else
2322             Result += "\t  ,{(SEL)\"";
2323           Result += (*I)->getSelector().getName().c_str();
2324           std::string MethodTypeString;
2325           Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
2326           Result += "\", \"";
2327           Result += MethodTypeString;
2328           Result += "\"}\n";
2329         }
2330         Result += "\t }\n};\n";
2331       }
2332       // Output:
2333       /* struct _objc_protocol {
2334        // Objective-C 1.0 extensions
2335        struct _objc_protocol_extension *isa;
2336        char *protocol_name;
2337        struct _objc_protocol **protocol_list;
2338        struct _objc_protocol_method_list *instance_methods;
2339        struct _objc_protocol_method_list *class_methods;
2340        };  
2341        */
2342       static bool objc_protocol = false;
2343       if (!objc_protocol) {
2344         Result += "\nstruct _objc_protocol {\n";
2345         Result += "\tstruct _objc_protocol_extension *isa;\n";
2346         Result += "\tchar *protocol_name;\n";
2347         Result += "\tstruct _objc_protocol **protocol_list;\n";
2348         Result += "\tstruct _objc_protocol_method_list *instance_methods;\n";
2349         Result += "\tstruct _objc_protocol_method_list *class_methods;\n";
2350         Result += "};\n";
2351         
2352         /* struct _objc_protocol_list {
2353          struct _objc_protocol_list *next;
2354          int    protocol_count;
2355          struct _objc_protocol *class_protocols[];
2356          }
2357          */
2358         Result += "\nstruct _objc_protocol_list {\n";
2359         Result += "\tstruct _objc_protocol_list *next;\n";
2360         Result += "\tint    protocol_count;\n";
2361         Result += "\tstruct _objc_protocol *class_protocols[];\n";
2362         Result += "};\n";
2363         objc_protocol = true;
2364       }
2365       
2366       Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_";
2367       Result += PDecl->getName();
2368       Result += " __attribute__ ((section (\"__OBJC, __protocol\")))= "
2369         "{\n\t0, \"";
2370       Result += PDecl->getName();
2371       Result += "\", 0, ";
2372       if (PDecl->getNumInstanceMethods() > 0) {
2373         Result += "&_OBJC_PROTOCOL_INSTANCE_METHODS_";
2374         Result += PDecl->getName();
2375         Result += ", ";
2376       }
2377       else
2378         Result += "0, ";
2379       if (PDecl->getNumClassMethods() > 0) {
2380         Result += "&_OBJC_PROTOCOL_CLASS_METHODS_";
2381         Result += PDecl->getName();
2382         Result += "\n";
2383       }
2384       else
2385         Result += "0\n";
2386       Result += "};\n";
2387     }
2388     // Output the top lovel protocol meta-data for the class.
2389     Result += "\nstatic struct _objc_protocol_list _OBJC_";
2390     Result += prefix;
2391     Result += "_PROTOCOLS_";
2392     Result += ClassName;
2393     Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
2394       "{\n\t0, ";
2395     Result += utostr(NumProtocols);
2396     Result += "\n";
2397     
2398     Result += "\t,{&_OBJC_PROTOCOL_";
2399     Result += Protocols[0]->getName();
2400     Result += " \n";
2401     
2402     for (int i = 1; i < NumProtocols; i++) {
2403       ObjCProtocolDecl *PDecl = Protocols[i];
2404       Result += "\t ,&_OBJC_PROTOCOL_";
2405       Result += PDecl->getName();
2406       Result += "\n";
2407     }
2408     Result += "\t }\n};\n";
2409   }  
2410 }
2411
2412 /// RewriteObjCCategoryImplDecl - Rewrite metadata for each category 
2413 /// implementation.
2414 void RewriteTest::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
2415                                               std::string &Result) {
2416   ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface();
2417   // Find category declaration for this implementation.
2418   ObjCCategoryDecl *CDecl;
2419   for (CDecl = ClassDecl->getCategoryList(); CDecl; 
2420        CDecl = CDecl->getNextClassCategory())
2421     if (CDecl->getIdentifier() == IDecl->getIdentifier())
2422       break;
2423   
2424   std::string FullCategoryName = ClassDecl->getName();
2425   FullCategoryName += '_';
2426   FullCategoryName += IDecl->getName();
2427     
2428   // Build _objc_method_list for class's instance methods if needed
2429   RewriteObjCMethodsMetaData(IDecl->instmeth_begin(), IDecl->instmeth_end(),
2430                              true, "CATEGORY_", FullCategoryName.c_str(),
2431                              Result);
2432   
2433   // Build _objc_method_list for class's class methods if needed
2434   RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
2435                              false, "CATEGORY_", FullCategoryName.c_str(),
2436                              Result);
2437   
2438   // Protocols referenced in class declaration?
2439   // Null CDecl is case of a category implementation with no category interface
2440   if (CDecl)
2441     RewriteObjCProtocolsMetaData(CDecl->getReferencedProtocols(),
2442                                  CDecl->getNumReferencedProtocols(),
2443                                  "CATEGORY",
2444                                  FullCategoryName.c_str(), Result);
2445   
2446   /* struct _objc_category {
2447    char *category_name;
2448    char *class_name;
2449    struct _objc_method_list *instance_methods;
2450    struct _objc_method_list *class_methods;
2451    struct _objc_protocol_list *protocols;
2452    // Objective-C 1.0 extensions
2453    uint32_t size;     // sizeof (struct _objc_category)
2454    struct _objc_property_list *instance_properties;  // category's own 
2455                                                      // @property decl.
2456    };   
2457    */
2458   
2459   static bool objc_category = false;
2460   if (!objc_category) {
2461     Result += "\nstruct _objc_category {\n";
2462     Result += "\tchar *category_name;\n";
2463     Result += "\tchar *class_name;\n";
2464     Result += "\tstruct _objc_method_list *instance_methods;\n";
2465     Result += "\tstruct _objc_method_list *class_methods;\n";
2466     Result += "\tstruct _objc_protocol_list *protocols;\n";
2467     Result += "\tunsigned int size;\n";   
2468     Result += "\tstruct _objc_property_list *instance_properties;\n";
2469     Result += "};\n";
2470     objc_category = true;
2471   }
2472   Result += "\nstatic struct _objc_category _OBJC_CATEGORY_";
2473   Result += FullCategoryName;
2474   Result += " __attribute__ ((section (\"__OBJC, __category\")))= {\n\t\"";
2475   Result += IDecl->getName();
2476   Result += "\"\n\t, \"";
2477   Result += ClassDecl->getName();
2478   Result += "\"\n";
2479   
2480   if (IDecl->getNumInstanceMethods() > 0) {
2481     Result += "\t, (struct _objc_method_list *)"
2482            "&_OBJC_CATEGORY_INSTANCE_METHODS_";
2483     Result += FullCategoryName;
2484     Result += "\n";
2485   }
2486   else
2487     Result += "\t, 0\n";
2488   if (IDecl->getNumClassMethods() > 0) {
2489     Result += "\t, (struct _objc_method_list *)"
2490            "&_OBJC_CATEGORY_CLASS_METHODS_";
2491     Result += FullCategoryName;
2492     Result += "\n";
2493   }
2494   else
2495     Result += "\t, 0\n";
2496   
2497   if (CDecl && CDecl->getNumReferencedProtocols() > 0) {
2498     Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_"; 
2499     Result += FullCategoryName;
2500     Result += "\n";
2501   }
2502   else
2503     Result += "\t, 0\n";
2504   Result += "\t, sizeof(struct _objc_category), 0\n};\n";
2505 }
2506
2507 /// SynthesizeIvarOffsetComputation - This rutine synthesizes computation of
2508 /// ivar offset.
2509 void RewriteTest::SynthesizeIvarOffsetComputation(ObjCImplementationDecl *IDecl, 
2510                                                   ObjCIvarDecl *ivar, 
2511                                                   std::string &Result) {
2512   Result += "offsetof(struct ";
2513   Result += IDecl->getName();
2514   Result += ", ";
2515   Result += ivar->getName();
2516   Result += ")";
2517 }
2518
2519 //===----------------------------------------------------------------------===//
2520 // Meta Data Emission
2521 //===----------------------------------------------------------------------===//
2522
2523 void RewriteTest::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
2524                                            std::string &Result) {
2525   ObjCInterfaceDecl *CDecl = IDecl->getClassInterface();
2526   
2527   // Explictly declared @interface's are already synthesized.
2528   if (CDecl->ImplicitInterfaceDecl()) {
2529     // FIXME: Implementation of a class with no @interface (legacy) doese not 
2530     // produce correct synthesis as yet.
2531     SynthesizeObjCInternalStruct(CDecl, Result);
2532   }
2533   
2534   // Build _objc_ivar_list metadata for classes ivars if needed
2535   int NumIvars = IDecl->getImplDeclNumIvars() > 0 
2536                    ? IDecl->getImplDeclNumIvars() 
2537                    : (CDecl ? CDecl->getNumInstanceVariables() : 0);
2538   if (NumIvars > 0) {
2539     static bool objc_ivar = false;
2540     if (!objc_ivar) {
2541       /* struct _objc_ivar {
2542           char *ivar_name;
2543           char *ivar_type;
2544           int ivar_offset;
2545         };  
2546        */
2547       Result += "\nstruct _objc_ivar {\n";
2548       Result += "\tchar *ivar_name;\n";
2549       Result += "\tchar *ivar_type;\n";
2550       Result += "\tint ivar_offset;\n";
2551       Result += "};\n";
2552       
2553       /* struct _objc_ivar_list {
2554        int ivar_count;
2555        struct _objc_ivar ivar_list[];
2556        };  
2557        */
2558       Result += "\nstruct _objc_ivar_list {\n";
2559       Result += "\tint ivar_count;\n";
2560       Result += "\tstruct _objc_ivar ivar_list[];\n};\n";
2561       objc_ivar = true;
2562     }
2563
2564     Result += "\nstatic struct _objc_ivar_list _OBJC_INSTANCE_VARIABLES_";
2565     Result += IDecl->getName();
2566     Result += " __attribute__ ((section (\"__OBJC, __instance_vars\")))= "
2567       "{\n\t";
2568     Result += utostr(NumIvars);
2569     Result += "\n";
2570     
2571     ObjCInterfaceDecl::ivar_iterator IVI, IVE;
2572     if (IDecl->getImplDeclNumIvars() > 0) {
2573       IVI = IDecl->ivar_begin();
2574       IVE = IDecl->ivar_end();
2575     } else {
2576       IVI = CDecl->ivar_begin();
2577       IVE = CDecl->ivar_end();
2578     }
2579     Result += "\t,{{\"";
2580     Result += (*IVI)->getName();
2581     Result += "\", \"";
2582     std::string StrEncoding;
2583     Context->getObjCEncodingForType((*IVI)->getType(), StrEncoding,
2584                                     EncodingRecordTypes);
2585     Result += StrEncoding;
2586     Result += "\", ";
2587     SynthesizeIvarOffsetComputation(IDecl, *IVI, Result);
2588     Result += "}\n";
2589     for (++IVI; IVI != IVE; ++IVI) {
2590       Result += "\t  ,{\"";
2591       Result += (*IVI)->getName();
2592       Result += "\", \"";
2593       std::string StrEncoding;
2594       Context->getObjCEncodingForType((*IVI)->getType(), StrEncoding,
2595                                       EncodingRecordTypes);
2596       Result += StrEncoding;
2597       Result += "\", ";
2598       SynthesizeIvarOffsetComputation(IDecl, (*IVI), Result);
2599       Result += "}\n";
2600     }
2601     
2602     Result += "\t }\n};\n";
2603   }
2604   
2605   // Build _objc_method_list for class's instance methods if needed
2606   RewriteObjCMethodsMetaData(IDecl->instmeth_begin(), IDecl->instmeth_end(), 
2607                              true, "", IDecl->getName(), Result);
2608   
2609   // Build _objc_method_list for class's class methods if needed
2610   RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
2611                              false, "", IDecl->getName(), Result);
2612     
2613   // Protocols referenced in class declaration?
2614   RewriteObjCProtocolsMetaData(CDecl->getReferencedProtocols(), 
2615                                CDecl->getNumIntfRefProtocols(),
2616                                "CLASS", CDecl->getName(), Result);
2617     
2618   
2619   // Declaration of class/meta-class metadata
2620   /* struct _objc_class {
2621    struct _objc_class *isa; // or const char *root_class_name when metadata
2622    const char *super_class_name;
2623    char *name;
2624    long version;
2625    long info;
2626    long instance_size;
2627    struct _objc_ivar_list *ivars;
2628    struct _objc_method_list *methods;
2629    struct objc_cache *cache;
2630    struct objc_protocol_list *protocols;
2631    const char *ivar_layout;
2632    struct _objc_class_ext  *ext;
2633    };  
2634   */
2635   static bool objc_class = false;
2636   if (!objc_class) {
2637     Result += "\nstruct _objc_class {\n";
2638     Result += "\tstruct _objc_class *isa;\n";
2639     Result += "\tconst char *super_class_name;\n";
2640     Result += "\tchar *name;\n";
2641     Result += "\tlong version;\n";
2642     Result += "\tlong info;\n";
2643     Result += "\tlong instance_size;\n";
2644     Result += "\tstruct _objc_ivar_list *ivars;\n";
2645     Result += "\tstruct _objc_method_list *methods;\n";
2646     Result += "\tstruct objc_cache *cache;\n";
2647     Result += "\tstruct _objc_protocol_list *protocols;\n";
2648     Result += "\tconst char *ivar_layout;\n";
2649     Result += "\tstruct _objc_class_ext  *ext;\n";
2650     Result += "};\n";
2651     objc_class = true;
2652   }
2653   
2654   // Meta-class metadata generation.
2655   ObjCInterfaceDecl *RootClass = 0;
2656   ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass();
2657   while (SuperClass) {
2658     RootClass = SuperClass;
2659     SuperClass = SuperClass->getSuperClass();
2660   }
2661   SuperClass = CDecl->getSuperClass();
2662   
2663   Result += "\nstatic struct _objc_class _OBJC_METACLASS_";
2664   Result += CDecl->getName();
2665   Result += " __attribute__ ((section (\"__OBJC, __meta_class\")))= "
2666   "{\n\t(struct _objc_class *)\"";
2667   Result += (RootClass ? RootClass->getName() : CDecl->getName());
2668   Result += "\"";
2669
2670   if (SuperClass) {
2671     Result += ", \"";
2672     Result += SuperClass->getName();
2673     Result += "\", \"";
2674     Result += CDecl->getName();
2675     Result += "\"";
2676   }
2677   else {
2678     Result += ", 0, \"";
2679     Result += CDecl->getName();
2680     Result += "\"";
2681   }
2682   // Set 'ivars' field for root class to 0. ObjC1 runtime does not use it.
2683   // 'info' field is initialized to CLS_META(2) for metaclass
2684   Result += ", 0,2, sizeof(struct _objc_class), 0";
2685   if (IDecl->getNumClassMethods() > 0) {
2686     Result += "\n\t, &_OBJC_CLASS_METHODS_";
2687     Result += IDecl->getName();
2688     Result += "\n"; 
2689   }
2690   else
2691     Result += ", 0\n";
2692   if (CDecl->getNumIntfRefProtocols() > 0) {
2693     Result += "\t,0, &_OBJC_CLASS_PROTOCOLS_";
2694     Result += CDecl->getName();
2695     Result += ",0,0\n";
2696   }
2697   else
2698     Result += "\t,0,0,0,0\n";
2699   Result += "};\n";
2700   
2701   // class metadata generation.
2702   Result += "\nstatic struct _objc_class _OBJC_CLASS_";
2703   Result += CDecl->getName();
2704   Result += " __attribute__ ((section (\"__OBJC, __class\")))= "
2705             "{\n\t&_OBJC_METACLASS_";
2706   Result += CDecl->getName();
2707   if (SuperClass) {
2708     Result += ", \"";
2709     Result += SuperClass->getName();
2710     Result += "\", \"";
2711     Result += CDecl->getName();
2712     Result += "\"";
2713   }
2714   else {
2715     Result += ", 0, \"";
2716     Result += CDecl->getName();
2717     Result += "\"";
2718   }
2719   // 'info' field is initialized to CLS_CLASS(1) for class
2720   Result += ", 0,1";
2721   if (!ObjCSynthesizedStructs.count(CDecl))
2722     Result += ",0";
2723   else {
2724     // class has size. Must synthesize its size.
2725     Result += ",sizeof(struct ";
2726     Result += CDecl->getName();
2727     Result += ")";
2728   }
2729   if (NumIvars > 0) {
2730     Result += ", &_OBJC_INSTANCE_VARIABLES_";
2731     Result += CDecl->getName();
2732     Result += "\n\t";
2733   }
2734   else
2735     Result += ",0";
2736   if (IDecl->getNumInstanceMethods() > 0) {
2737     Result += ", &_OBJC_INSTANCE_METHODS_";
2738     Result += CDecl->getName();
2739     Result += ", 0\n\t"; 
2740   }
2741   else
2742     Result += ",0,0";
2743   if (CDecl->getNumIntfRefProtocols() > 0) {
2744     Result += ", &_OBJC_CLASS_PROTOCOLS_";
2745     Result += CDecl->getName();
2746     Result += ", 0,0\n";
2747   }
2748   else
2749     Result += ",0,0,0\n";
2750   Result += "};\n";
2751 }
2752
2753 /// RewriteImplementations - This routine rewrites all method implementations
2754 /// and emits meta-data.
2755
2756 void RewriteTest::RewriteImplementations(std::string &Result) {
2757   int ClsDefCount = ClassImplementation.size();
2758   int CatDefCount = CategoryImplementation.size();
2759   
2760   if (ClsDefCount == 0 && CatDefCount == 0)
2761     return;
2762   // Rewrite implemented methods
2763   for (int i = 0; i < ClsDefCount; i++)
2764     RewriteImplementationDecl(ClassImplementation[i]);
2765   
2766   for (int i = 0; i < CatDefCount; i++)
2767     RewriteImplementationDecl(CategoryImplementation[i]);
2768   
2769   // This is needed for use of offsetof
2770   Result += "#include <stddef.h>\n";
2771     
2772   // For each implemented class, write out all its meta data.
2773   for (int i = 0; i < ClsDefCount; i++)
2774     RewriteObjCClassMetaData(ClassImplementation[i], Result);
2775   
2776   // For each implemented category, write out all its meta data.
2777   for (int i = 0; i < CatDefCount; i++)
2778     RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result);
2779   
2780   // Write objc_symtab metadata
2781   /*
2782    struct _objc_symtab
2783    {
2784    long sel_ref_cnt;
2785    SEL *refs;
2786    short cls_def_cnt;
2787    short cat_def_cnt;
2788    void *defs[cls_def_cnt + cat_def_cnt];
2789    }; 
2790    */
2791   
2792   Result += "\nstruct _objc_symtab {\n";
2793   Result += "\tlong sel_ref_cnt;\n";
2794   Result += "\tSEL *refs;\n";
2795   Result += "\tshort cls_def_cnt;\n";
2796   Result += "\tshort cat_def_cnt;\n";
2797   Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n";
2798   Result += "};\n\n";
2799   
2800   Result += "static struct _objc_symtab "
2801          "_OBJC_SYMBOLS __attribute__((section (\"__OBJC, __symbols\")))= {\n";
2802   Result += "\t0, 0, " + utostr(ClsDefCount) 
2803             + ", " + utostr(CatDefCount) + "\n";
2804   for (int i = 0; i < ClsDefCount; i++) {
2805     Result += "\t,&_OBJC_CLASS_";
2806     Result += ClassImplementation[i]->getName();
2807     Result += "\n";
2808   }
2809   
2810   for (int i = 0; i < CatDefCount; i++) {
2811     Result += "\t,&_OBJC_CATEGORY_";
2812     Result += CategoryImplementation[i]->getClassInterface()->getName();
2813     Result += "_";
2814     Result += CategoryImplementation[i]->getName();
2815     Result += "\n";
2816   }
2817   
2818   Result += "};\n\n";
2819   
2820   // Write objc_module metadata
2821   
2822   /*
2823    struct _objc_module {
2824     long version;
2825     long size;
2826     const char *name;
2827     struct _objc_symtab *symtab;
2828    }
2829   */
2830   
2831   Result += "\nstruct _objc_module {\n";
2832   Result += "\tlong version;\n";
2833   Result += "\tlong size;\n";
2834   Result += "\tconst char *name;\n";
2835   Result += "\tstruct _objc_symtab *symtab;\n";
2836   Result += "};\n\n";
2837   Result += "static struct _objc_module "
2838     "_OBJC_MODULES __attribute__ ((section (\"__OBJC, __module_info\")))= {\n";
2839   Result += "\t" + utostr(OBJC_ABI_VERSION) + 
2840   ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";
2841   Result += "};\n\n";
2842   
2843 }
2844