blob: 36943d6bc3b0077a000443752fc87031b0108344 [file] [log] [blame]
Chris Lattner77cd2a02007-10-11 00:43:27 +00001//===--- RewriteTest.cpp - Playground for the code rewriter ---------------===//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner0bc735f2007-12-29 19:59:25 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Chris Lattner77cd2a02007-10-11 00:43:27 +00007//
8//===----------------------------------------------------------------------===//
9//
10// Hacks and fun related to the code rewriter.
11//
12//===----------------------------------------------------------------------===//
13
14#include "ASTConsumers.h"
Chris Lattner8a12c272007-10-11 18:38:32 +000015#include "clang/Rewrite/Rewriter.h"
Chris Lattner77cd2a02007-10-11 00:43:27 +000016#include "clang/AST/AST.h"
17#include "clang/AST/ASTConsumer.h"
Chris Lattner8a12c272007-10-11 18:38:32 +000018#include "clang/Basic/SourceManager.h"
Steve Naroffebf2b562007-10-23 23:50:29 +000019#include "clang/Basic/IdentifierTable.h"
Chris Lattner07506182007-11-30 22:53:43 +000020#include "clang/Basic/Diagnostic.h"
Chris Lattner26de4652007-12-02 01:13:47 +000021#include "clang/Lex/Lexer.h"
Chris Lattner158ecb92007-10-25 17:07:24 +000022#include "llvm/ADT/StringExtras.h"
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +000023#include "llvm/ADT/SmallPtrSet.h"
Chris Lattner26de4652007-12-02 01:13:47 +000024#include "llvm/Support/MemoryBuffer.h"
Steve Naroff0113c9d2008-01-28 21:34:52 +000025#include "llvm/Support/CommandLine.h"
Steve Naroff874e2322007-11-15 10:28:18 +000026#include <sstream>
Chris Lattner77cd2a02007-10-11 00:43:27 +000027using namespace clang;
Chris Lattner158ecb92007-10-25 17:07:24 +000028using llvm::utostr;
Chris Lattner77cd2a02007-10-11 00:43:27 +000029
Steve Naroff0113c9d2008-01-28 21:34:52 +000030static llvm::cl::opt<bool>
31SilenceRewriteMacroWarning("Wno-rewrite-macros", llvm::cl::init(false),
32 llvm::cl::desc("Silence ObjC rewriting warnings"));
33
Chris Lattner77cd2a02007-10-11 00:43:27 +000034namespace {
Chris Lattner8a12c272007-10-11 18:38:32 +000035 class RewriteTest : public ASTConsumer {
Chris Lattner2c64b7b2007-10-16 21:07:07 +000036 Rewriter Rewrite;
Chris Lattnere365c502007-11-30 22:25:36 +000037 Diagnostic &Diags;
Steve Narofff69cc5d2008-01-30 19:17:43 +000038 unsigned RewriteFailedDiag;
39
Chris Lattner01c57482007-10-17 22:35:30 +000040 ASTContext *Context;
Chris Lattner77cd2a02007-10-11 00:43:27 +000041 SourceManager *SM;
Chris Lattner8a12c272007-10-11 18:38:32 +000042 unsigned MainFileID;
Chris Lattner26de4652007-12-02 01:13:47 +000043 const char *MainFileStart, *MainFileEnd;
Chris Lattner2c64b7b2007-10-16 21:07:07 +000044 SourceLocation LastIncLoc;
Ted Kremeneka526c5c2008-01-07 19:49:32 +000045 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;
Fariborz Jahaniane8d1c052008-01-15 23:58:23 +000050 llvm::SmallVector<Stmt *, 32> Stmts;
51 llvm::SmallVector<int, 8> ObjCBcLabelNo;
Fariborz Jahanian7d6b46d2008-01-22 22:44:46 +000052 llvm::SmallVector<const RecordType *, 8> EncodingRecordTypes;
Steve Naroffebf2b562007-10-23 23:50:29 +000053
54 FunctionDecl *MsgSendFunctionDecl;
Steve Naroff874e2322007-11-15 10:28:18 +000055 FunctionDecl *MsgSendSuperFunctionDecl;
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +000056 FunctionDecl *MsgSendStretFunctionDecl;
57 FunctionDecl *MsgSendSuperStretFunctionDecl;
Fariborz Jahanianacb49772007-12-03 21:26:48 +000058 FunctionDecl *MsgSendFpretFunctionDecl;
Steve Naroffebf2b562007-10-23 23:50:29 +000059 FunctionDecl *GetClassFunctionDecl;
Steve Naroff9bcb5fc2007-12-07 03:50:46 +000060 FunctionDecl *GetMetaClassFunctionDecl;
Steve Naroff934f2762007-10-24 22:48:43 +000061 FunctionDecl *SelGetUidFunctionDecl;
Steve Naroff96984642007-11-08 14:30:50 +000062 FunctionDecl *CFStringFunctionDecl;
Fariborz Jahanian36ee2cb2007-12-07 18:47:10 +000063 FunctionDecl *GetProtocolFunctionDecl;
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +000064
Steve Naroffbeaf2992007-11-03 11:27:19 +000065 // ObjC string constant support.
66 FileVarDecl *ConstantStringClassReference;
67 RecordDecl *NSStringRecord;
Steve Naroffab972d32007-11-04 22:37:50 +000068
Fariborz Jahanianb586cce2008-01-16 00:09:11 +000069 // ObjC foreach break/continue generation support.
Fariborz Jahaniane8d1c052008-01-15 23:58:23 +000070 int BcLabelCount;
71
Steve Naroff874e2322007-11-15 10:28:18 +000072 // Needed for super.
Ted Kremeneka526c5c2008-01-07 19:49:32 +000073 ObjCMethodDecl *CurMethodDecl;
Steve Naroff874e2322007-11-15 10:28:18 +000074 RecordDecl *SuperStructDecl;
75
Fariborz Jahanianb4b2f0c2008-01-18 01:15:54 +000076 // Needed for header files being rewritten
77 bool IsHeader;
78
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +000079 static const int OBJC_ABI_VERSION =7 ;
Chris Lattner77cd2a02007-10-11 00:43:27 +000080 public:
Ted Kremenek95041a22007-12-19 22:51:13 +000081 void Initialize(ASTContext &context) {
Chris Lattner01c57482007-10-17 22:35:30 +000082 Context = &context;
Ted Kremenek7a9d49f2007-12-11 21:27:55 +000083 SM = &Context->getSourceManager();
Steve Naroffebf2b562007-10-23 23:50:29 +000084 MsgSendFunctionDecl = 0;
Steve Naroff874e2322007-11-15 10:28:18 +000085 MsgSendSuperFunctionDecl = 0;
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +000086 MsgSendStretFunctionDecl = 0;
87 MsgSendSuperStretFunctionDecl = 0;
Fariborz Jahanianacb49772007-12-03 21:26:48 +000088 MsgSendFpretFunctionDecl = 0;
Steve Naroffc0006092007-10-24 01:09:48 +000089 GetClassFunctionDecl = 0;
Steve Naroff9bcb5fc2007-12-07 03:50:46 +000090 GetMetaClassFunctionDecl = 0;
Steve Naroff934f2762007-10-24 22:48:43 +000091 SelGetUidFunctionDecl = 0;
Steve Naroff96984642007-11-08 14:30:50 +000092 CFStringFunctionDecl = 0;
Fariborz Jahanian36ee2cb2007-12-07 18:47:10 +000093 GetProtocolFunctionDecl = 0;
Steve Naroffbeaf2992007-11-03 11:27:19 +000094 ConstantStringClassReference = 0;
95 NSStringRecord = 0;
Steve Naroff874e2322007-11-15 10:28:18 +000096 CurMethodDecl = 0;
97 SuperStructDecl = 0;
Fariborz Jahaniane8d1c052008-01-15 23:58:23 +000098 BcLabelCount = 0;
Steve Narofff69cc5d2008-01-30 19:17:43 +000099
Chris Lattner26de4652007-12-02 01:13:47 +0000100 // Get the ID and start/end of the main file.
Ted Kremenek95041a22007-12-19 22:51:13 +0000101 MainFileID = SM->getMainFileID();
Chris Lattner26de4652007-12-02 01:13:47 +0000102 const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID);
103 MainFileStart = MainBuf->getBufferStart();
104 MainFileEnd = MainBuf->getBufferEnd();
105
106
Ted Kremenek7a9d49f2007-12-11 21:27:55 +0000107 Rewrite.setSourceMgr(Context->getSourceManager());
Steve Naroffe3abbf52007-11-05 14:55:35 +0000108 // declaring objc_selector outside the parameter list removes a silly
109 // scope related warning...
Fariborz Jahanianb4b2f0c2008-01-18 01:15:54 +0000110 const char *s = "#pragma once\n"
111 "struct objc_selector; struct objc_class;\n"
Fariborz Jahanian36ee2cb2007-12-07 18:47:10 +0000112 "#ifndef OBJC_SUPER\n"
113 "struct objc_super { struct objc_object *o; "
114 "struct objc_object *superClass; };\n"
115 "#define OBJC_SUPER\n"
116 "#endif\n"
117 "#ifndef _REWRITER_typedef_Protocol\n"
118 "typedef struct objc_object Protocol;\n"
119 "#define _REWRITER_typedef_Protocol\n"
120 "#endif\n"
Steve Naroffe3abbf52007-11-05 14:55:35 +0000121 "extern struct objc_object *objc_msgSend"
Steve Naroffab972d32007-11-04 22:37:50 +0000122 "(struct objc_object *, struct objc_selector *, ...);\n"
Steve Naroff874e2322007-11-15 10:28:18 +0000123 "extern struct objc_object *objc_msgSendSuper"
124 "(struct objc_super *, struct objc_selector *, ...);\n"
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +0000125 "extern struct objc_object *objc_msgSend_stret"
126 "(struct objc_object *, struct objc_selector *, ...);\n"
127 "extern struct objc_object *objc_msgSendSuper_stret"
128 "(struct objc_super *, struct objc_selector *, ...);\n"
Fariborz Jahanianacb49772007-12-03 21:26:48 +0000129 "extern struct objc_object *objc_msgSend_fpret"
130 "(struct objc_object *, struct objc_selector *, ...);\n"
Steve Naroffab972d32007-11-04 22:37:50 +0000131 "extern struct objc_object *objc_getClass"
Steve Naroff21867b12007-11-07 18:43:40 +0000132 "(const char *);\n"
Steve Naroff9bcb5fc2007-12-07 03:50:46 +0000133 "extern struct objc_object *objc_getMetaClass"
134 "(const char *);\n"
Steve Naroff21867b12007-11-07 18:43:40 +0000135 "extern void objc_exception_throw(struct objc_object *);\n"
136 "extern void objc_exception_try_enter(void *);\n"
137 "extern void objc_exception_try_exit(void *);\n"
138 "extern struct objc_object *objc_exception_extract(void *);\n"
139 "extern int objc_exception_match"
Fariborz Jahanian95673922007-11-14 22:26:25 +0000140 "(struct objc_class *, struct objc_object *, ...);\n"
Fariborz Jahanian36ee2cb2007-12-07 18:47:10 +0000141 "extern Protocol *objc_getProtocol(const char *);\n"
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +0000142 "#include <objc/objc.h>\n"
Fariborz Jahanian88007422008-01-10 23:04:06 +0000143 "#ifndef __FASTENUMERATIONSTATE\n"
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +0000144 "struct __objcFastEnumerationState {\n\t"
145 "unsigned long state;\n\t"
146 "id *itemsPtr;\n\t"
147 "unsigned long *mutationsPtr;\n\t"
Fariborz Jahanian88007422008-01-10 23:04:06 +0000148 "unsigned long extra[5];\n};\n"
149 "#define __FASTENUMERATIONSTATE\n"
150 "#endif\n";
Fariborz Jahanianb4b2f0c2008-01-18 01:15:54 +0000151 if (IsHeader) {
152 // insert the whole string when rewriting a header file
153 Rewrite.InsertText(SourceLocation::getFileLoc(MainFileID, 0),
154 s, strlen(s));
155 }
156 else {
157 // Not rewriting header, exclude the #pragma once pragma
158 const char *p = s + strlen("#pragma once\n");
159 Rewrite.InsertText(SourceLocation::getFileLoc(MainFileID, 0),
160 p, strlen(p));
161 }
Chris Lattner77cd2a02007-10-11 00:43:27 +0000162 }
Chris Lattner8a12c272007-10-11 18:38:32 +0000163
Chris Lattnerf04da132007-10-24 17:06:59 +0000164 // Top Level Driver code.
165 virtual void HandleTopLevelDecl(Decl *D);
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000166 void HandleDeclInMainFile(Decl *D);
Steve Naroff0113c9d2008-01-28 21:34:52 +0000167 RewriteTest(bool isHeader, Diagnostic &D) : Diags(D) {
Steve Narofff69cc5d2008-01-30 19:17:43 +0000168 IsHeader = isHeader;
Steve Naroff0113c9d2008-01-28 21:34:52 +0000169 RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
170 "rewriting sub-expression within a macro (may not be correct)");
Steve Narofff69cc5d2008-01-30 19:17:43 +0000171 }
Chris Lattnerf04da132007-10-24 17:06:59 +0000172 ~RewriteTest();
Chris Lattnerdcbc5b02008-01-31 19:37:57 +0000173
174 void ReplaceStmt(Stmt *Old, Stmt *New) {
175 if (!Rewrite.ReplaceStmt(Old, New))
176 return;
177
178 // Replacement failed, report a warning unless disabled.
179 if (SilenceRewriteMacroWarning) return;
180
181 SourceRange Range = Old->getSourceRange();
182 Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag,
183 0, 0, &Range, 1);
184 }
185
186
Chris Lattnerf04da132007-10-24 17:06:59 +0000187
188 // Syntactic Rewriting.
Steve Naroffab972d32007-11-04 22:37:50 +0000189 void RewritePrologue(SourceLocation Loc);
Fariborz Jahanian452b8992008-01-19 00:30:35 +0000190 void RewriteInclude();
Chris Lattnerf04da132007-10-24 17:06:59 +0000191 void RewriteTabs();
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000192 void RewriteForwardClassDecl(ObjCClassDecl *Dcl);
193 void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl);
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000194 void RewriteImplementationDecl(NamedDecl *Dcl);
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000195 void RewriteObjCMethodDecl(ObjCMethodDecl *MDecl, std::string &ResultStr);
196 void RewriteCategoryDecl(ObjCCategoryDecl *Dcl);
197 void RewriteProtocolDecl(ObjCProtocolDecl *Dcl);
198 void RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *Dcl);
199 void RewriteMethodDeclaration(ObjCMethodDecl *Method);
200 void RewriteProperties(int nProperties, ObjCPropertyDecl **Properties);
Steve Naroff09b266e2007-10-30 23:14:51 +0000201 void RewriteFunctionDecl(FunctionDecl *FD);
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000202 void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl);
Steve Naroffd5255f52007-11-01 13:24:47 +0000203 bool needToScanForQualifiers(QualType T);
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000204 ObjCInterfaceDecl *isSuperReceiver(Expr *recExpr);
Steve Naroff874e2322007-11-15 10:28:18 +0000205 QualType getSuperStructType();
Chris Lattner311ff022007-10-16 22:36:42 +0000206
Chris Lattnerf04da132007-10-24 17:06:59 +0000207 // Expression Rewriting.
Steve Narofff3473a72007-11-09 15:20:18 +0000208 Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S);
Chris Lattnere64b7772007-10-24 16:57:36 +0000209 Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
Steve Naroff7e3411b2007-11-15 02:58:25 +0000210 Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV);
Steve Naroffb42f8412007-11-05 14:50:49 +0000211 Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp);
Chris Lattnere64b7772007-10-24 16:57:36 +0000212 Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
Steve Naroffbeaf2992007-11-03 11:27:19 +0000213 Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp);
Fariborz Jahanian36ee2cb2007-12-07 18:47:10 +0000214 Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp);
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000215 Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S);
Fariborz Jahaniana0f55792008-01-29 22:59:37 +0000216 Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S);
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000217 Stmt *RewriteObjCCatchStmt(ObjCAtCatchStmt *S);
218 Stmt *RewriteObjCFinallyStmt(ObjCAtFinallyStmt *S);
219 Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S);
Chris Lattner338d1e22008-01-31 05:10:40 +0000220 Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
221 SourceLocation OrigEnd);
Steve Naroff934f2762007-10-24 22:48:43 +0000222 CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD,
223 Expr **args, unsigned nargs);
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +0000224 Stmt *SynthMessageExpr(ObjCMessageExpr *Exp);
Fariborz Jahaniane8d1c052008-01-15 23:58:23 +0000225 Stmt *RewriteBreakStmt(BreakStmt *S);
226 Stmt *RewriteContinueStmt(ContinueStmt *S);
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +0000227 void SynthCountByEnumWithState(std::string &buf);
228
Steve Naroff09b266e2007-10-30 23:14:51 +0000229 void SynthMsgSendFunctionDecl();
Steve Naroff874e2322007-11-15 10:28:18 +0000230 void SynthMsgSendSuperFunctionDecl();
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +0000231 void SynthMsgSendStretFunctionDecl();
Fariborz Jahanianacb49772007-12-03 21:26:48 +0000232 void SynthMsgSendFpretFunctionDecl();
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +0000233 void SynthMsgSendSuperStretFunctionDecl();
Steve Naroff09b266e2007-10-30 23:14:51 +0000234 void SynthGetClassFunctionDecl();
Steve Naroff9bcb5fc2007-12-07 03:50:46 +0000235 void SynthGetMetaClassFunctionDecl();
Steve Naroff96984642007-11-08 14:30:50 +0000236 void SynthCFStringFunctionDecl();
Fariborz Jahaniana70711b2007-12-04 21:47:40 +0000237 void SynthSelGetUidFunctionDecl();
Fariborz Jahanian36ee2cb2007-12-07 18:47:10 +0000238 void SynthGetProtocolFunctionDecl();
Steve Naroff96984642007-11-08 14:30:50 +0000239
Chris Lattnerf04da132007-10-24 17:06:59 +0000240 // Metadata emission.
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000241 void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000242 std::string &Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000243
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000244 void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000245 std::string &Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000246
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000247 typedef ObjCCategoryImplDecl::instmeth_iterator instmeth_iterator;
248 void RewriteObjCMethodsMetaData(instmeth_iterator MethodBegin,
Chris Lattnerab4c4d52007-12-12 07:46:12 +0000249 instmeth_iterator MethodEnd,
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +0000250 bool IsInstanceMethod,
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000251 const char *prefix,
Chris Lattner158ecb92007-10-25 17:07:24 +0000252 const char *ClassName,
253 std::string &Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000254
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000255 void RewriteObjCProtocolsMetaData(ObjCProtocolDecl **Protocols,
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000256 int NumProtocols,
257 const char *prefix,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000258 const char *ClassName,
259 std::string &Result);
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000260 void SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000261 std::string &Result);
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000262 void SynthesizeIvarOffsetComputation(ObjCImplementationDecl *IDecl,
263 ObjCIvarDecl *ivar,
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000264 std::string &Result);
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +0000265 void RewriteImplementations(std::string &Result);
Chris Lattner77cd2a02007-10-11 00:43:27 +0000266 };
267}
268
Fariborz Jahanianb4b2f0c2008-01-18 01:15:54 +0000269static bool IsHeaderFile(const std::string &Filename) {
270 std::string::size_type DotPos = Filename.rfind('.');
271
272 if (DotPos == std::string::npos) {
273 // no file extension
274 return false;
275 }
276
277 std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end());
278 // C header: .h
279 // C++ header: .hh or .H;
280 return Ext == "h" || Ext == "hh" || Ext == "H";
281}
282
283ASTConsumer *clang::CreateCodeRewriterTest(const std::string& InFile,
284 Diagnostic &Diags) {
285 return new RewriteTest(IsHeaderFile(InFile), Diags);
Chris Lattnere365c502007-11-30 22:25:36 +0000286}
Chris Lattner77cd2a02007-10-11 00:43:27 +0000287
Chris Lattnerf04da132007-10-24 17:06:59 +0000288//===----------------------------------------------------------------------===//
289// Top Level Driver Code
290//===----------------------------------------------------------------------===//
291
Chris Lattner8a12c272007-10-11 18:38:32 +0000292void RewriteTest::HandleTopLevelDecl(Decl *D) {
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000293 // Two cases: either the decl could be in the main file, or it could be in a
294 // #included file. If the former, rewrite it now. If the later, check to see
295 // if we rewrote the #include/#import.
296 SourceLocation Loc = D->getLocation();
297 Loc = SM->getLogicalLoc(Loc);
298
299 // If this is for a builtin, ignore it.
300 if (Loc.isInvalid()) return;
301
Steve Naroffebf2b562007-10-23 23:50:29 +0000302 // Look for built-in declarations that we need to refer during the rewrite.
303 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Steve Naroff09b266e2007-10-30 23:14:51 +0000304 RewriteFunctionDecl(FD);
Steve Naroffbeaf2992007-11-03 11:27:19 +0000305 } else if (FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
306 // declared in <Foundation/NSString.h>
307 if (strcmp(FVD->getName(), "_NSConstantStringClassReference") == 0) {
308 ConstantStringClassReference = FVD;
309 return;
310 }
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000311 } else if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D)) {
Steve Naroffbef11852007-10-26 20:53:56 +0000312 RewriteInterfaceDecl(MD);
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000313 } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) {
Steve Naroff423cb562007-10-30 13:30:57 +0000314 RewriteCategoryDecl(CD);
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000315 } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
Steve Naroff752d6ef2007-10-30 16:42:30 +0000316 RewriteProtocolDecl(PD);
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000317 } else if (ObjCForwardProtocolDecl *FP =
318 dyn_cast<ObjCForwardProtocolDecl>(D)){
Fariborz Jahaniand175ddf2007-11-14 00:42:16 +0000319 RewriteForwardProtocolDecl(FP);
Steve Naroffebf2b562007-10-23 23:50:29 +0000320 }
Chris Lattnerf04da132007-10-24 17:06:59 +0000321 // If we have a decl in the main file, see if we should rewrite it.
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000322 if (SM->getDecomposedFileLoc(Loc).first == MainFileID)
323 return HandleDeclInMainFile(D);
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000324}
325
Chris Lattnerf04da132007-10-24 17:06:59 +0000326/// HandleDeclInMainFile - This is called for each top-level decl defined in the
327/// main file of the input.
328void RewriteTest::HandleDeclInMainFile(Decl *D) {
329 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
330 if (Stmt *Body = FD->getBody())
Steve Narofff3473a72007-11-09 15:20:18 +0000331 FD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
Steve Narofff69cc5d2008-01-30 19:17:43 +0000332
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000333 if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
Steve Naroff874e2322007-11-15 10:28:18 +0000334 if (Stmt *Body = MD->getBody()) {
335 //Body->dump();
336 CurMethodDecl = MD;
Steve Naroff71c0a952007-11-13 23:01:27 +0000337 MD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
Steve Naroff874e2322007-11-15 10:28:18 +0000338 CurMethodDecl = 0;
339 }
Steve Naroff71c0a952007-11-13 23:01:27 +0000340 }
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000341 if (ObjCImplementationDecl *CI = dyn_cast<ObjCImplementationDecl>(D))
Chris Lattnerf04da132007-10-24 17:06:59 +0000342 ClassImplementation.push_back(CI);
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000343 else if (ObjCCategoryImplDecl *CI = dyn_cast<ObjCCategoryImplDecl>(D))
Chris Lattnerf04da132007-10-24 17:06:59 +0000344 CategoryImplementation.push_back(CI);
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000345 else if (ObjCClassDecl *CD = dyn_cast<ObjCClassDecl>(D))
Chris Lattnerf04da132007-10-24 17:06:59 +0000346 RewriteForwardClassDecl(CD);
Steve Narofff3473a72007-11-09 15:20:18 +0000347 else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000348 RewriteObjCQualifiedInterfaceTypes(VD);
Steve Narofff3473a72007-11-09 15:20:18 +0000349 if (VD->getInit())
350 RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
351 }
Chris Lattnerf04da132007-10-24 17:06:59 +0000352 // Nothing yet.
353}
354
355RewriteTest::~RewriteTest() {
356 // Get the top-level buffer that this corresponds to.
Chris Lattner74a0c772007-11-08 04:27:23 +0000357
358 // Rewrite tabs if we care.
359 //RewriteTabs();
Chris Lattnerf04da132007-10-24 17:06:59 +0000360
Fariborz Jahanian452b8992008-01-19 00:30:35 +0000361 RewriteInclude();
362
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000363 // Rewrite Objective-c meta data*
364 std::string ResultStr;
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +0000365 RewriteImplementations(ResultStr);
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000366
Chris Lattnerf04da132007-10-24 17:06:59 +0000367 // Get the buffer corresponding to MainFileID. If we haven't changed it, then
368 // we are done.
369 if (const RewriteBuffer *RewriteBuf =
370 Rewrite.getRewriteBufferFor(MainFileID)) {
Steve Naroffbeaf2992007-11-03 11:27:19 +0000371 //printf("Changed:\n");
Chris Lattnerf04da132007-10-24 17:06:59 +0000372 std::string S(RewriteBuf->begin(), RewriteBuf->end());
373 printf("%s\n", S.c_str());
374 } else {
375 printf("No changes\n");
376 }
Fariborz Jahanian4402d812007-11-07 18:40:28 +0000377 // Emit metadata.
378 printf("%s", ResultStr.c_str());
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000379}
380
Chris Lattnerf04da132007-10-24 17:06:59 +0000381//===----------------------------------------------------------------------===//
382// Syntactic (non-AST) Rewriting Code
383//===----------------------------------------------------------------------===//
384
Fariborz Jahanian452b8992008-01-19 00:30:35 +0000385void RewriteTest::RewriteInclude() {
386 SourceLocation LocStart = SourceLocation::getFileLoc(MainFileID, 0);
387 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
388 const char *MainBufStart = MainBuf.first;
389 const char *MainBufEnd = MainBuf.second;
390 size_t ImportLen = strlen("import");
391 size_t IncludeLen = strlen("include");
392
Fariborz Jahanianaf57b462008-01-19 01:03:17 +0000393 // Loop over the whole file, looking for includes.
Fariborz Jahanian452b8992008-01-19 00:30:35 +0000394 for (const char *BufPtr = MainBufStart; BufPtr < MainBufEnd; ++BufPtr) {
395 if (*BufPtr == '#') {
396 if (++BufPtr == MainBufEnd)
397 return;
398 while (*BufPtr == ' ' || *BufPtr == '\t')
399 if (++BufPtr == MainBufEnd)
400 return;
401 if (!strncmp(BufPtr, "import", ImportLen)) {
402 // replace import with include
403 SourceLocation ImportLoc =
404 LocStart.getFileLocWithOffset(BufPtr-MainBufStart);
405 Rewrite.ReplaceText(ImportLoc, ImportLen, "include", IncludeLen);
406 BufPtr += ImportLen;
407 }
408 }
409 }
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000410}
411
Chris Lattnerf04da132007-10-24 17:06:59 +0000412void RewriteTest::RewriteTabs() {
413 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
414 const char *MainBufStart = MainBuf.first;
415 const char *MainBufEnd = MainBuf.second;
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +0000416
Chris Lattnerf04da132007-10-24 17:06:59 +0000417 // Loop over the whole file, looking for tabs.
418 for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) {
419 if (*BufPtr != '\t')
420 continue;
421
422 // Okay, we found a tab. This tab will turn into at least one character,
423 // but it depends on which 'virtual column' it is in. Compute that now.
424 unsigned VCol = 0;
425 while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' &&
426 BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r')
427 ++VCol;
428
429 // Okay, now that we know the virtual column, we know how many spaces to
430 // insert. We assume 8-character tab-stops.
431 unsigned Spaces = 8-(VCol & 7);
432
433 // Get the location of the tab.
434 SourceLocation TabLoc =
435 SourceLocation::getFileLoc(MainFileID, BufPtr-MainBufStart);
436
437 // Rewrite the single tab character into a sequence of spaces.
438 Rewrite.ReplaceText(TabLoc, 1, " ", Spaces);
439 }
Chris Lattner8a12c272007-10-11 18:38:32 +0000440}
441
442
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000443void RewriteTest::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) {
Chris Lattnerf04da132007-10-24 17:06:59 +0000444 int numDecls = ClassDecl->getNumForwardDecls();
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000445 ObjCInterfaceDecl **ForwardDecls = ClassDecl->getForwardDecls();
Chris Lattnerf04da132007-10-24 17:06:59 +0000446
447 // Get the start location and compute the semi location.
448 SourceLocation startLoc = ClassDecl->getLocation();
449 const char *startBuf = SM->getCharacterData(startLoc);
450 const char *semiPtr = strchr(startBuf, ';');
451
452 // Translate to typedef's that forward reference structs with the same name
453 // as the class. As a convenience, we include the original declaration
454 // as a comment.
455 std::string typedefString;
456 typedefString += "// ";
Steve Naroff934f2762007-10-24 22:48:43 +0000457 typedefString.append(startBuf, semiPtr-startBuf+1);
458 typedefString += "\n";
459 for (int i = 0; i < numDecls; i++) {
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000460 ObjCInterfaceDecl *ForwardDecl = ForwardDecls[i];
Steve Naroff32174822007-11-09 12:50:28 +0000461 typedefString += "#ifndef _REWRITER_typedef_";
462 typedefString += ForwardDecl->getName();
463 typedefString += "\n";
464 typedefString += "#define _REWRITER_typedef_";
465 typedefString += ForwardDecl->getName();
466 typedefString += "\n";
Steve Naroff352336b2007-11-05 14:36:37 +0000467 typedefString += "typedef struct objc_object ";
Steve Naroff934f2762007-10-24 22:48:43 +0000468 typedefString += ForwardDecl->getName();
Steve Naroff32174822007-11-09 12:50:28 +0000469 typedefString += ";\n#endif\n";
Steve Naroff934f2762007-10-24 22:48:43 +0000470 }
471
472 // Replace the @class with typedefs corresponding to the classes.
473 Rewrite.ReplaceText(startLoc, semiPtr-startBuf+1,
474 typedefString.c_str(), typedefString.size());
Chris Lattnerf04da132007-10-24 17:06:59 +0000475}
476
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000477void RewriteTest::RewriteMethodDeclaration(ObjCMethodDecl *Method) {
Steve Naroff58dbdeb2007-12-14 23:37:57 +0000478 SourceLocation LocStart = Method->getLocStart();
479 SourceLocation LocEnd = Method->getLocEnd();
Steve Naroff423cb562007-10-30 13:30:57 +0000480
Steve Naroff58dbdeb2007-12-14 23:37:57 +0000481 if (SM->getLineNumber(LocEnd) > SM->getLineNumber(LocStart)) {
Steve Narofff69cc5d2008-01-30 19:17:43 +0000482 Rewrite.InsertText(LocStart, "/* ", 3);
483 Rewrite.ReplaceText(LocEnd, 1, ";*/ ", 4);
Steve Naroff58dbdeb2007-12-14 23:37:57 +0000484 } else {
Steve Narofff69cc5d2008-01-30 19:17:43 +0000485 Rewrite.InsertText(LocStart, "// ", 3);
Steve Naroff423cb562007-10-30 13:30:57 +0000486 }
487}
488
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000489void RewriteTest::RewriteProperties(int nProperties, ObjCPropertyDecl **Properties)
Fariborz Jahanian957cf652007-11-07 00:09:37 +0000490{
491 for (int i = 0; i < nProperties; i++) {
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000492 ObjCPropertyDecl *Property = Properties[i];
Fariborz Jahanian957cf652007-11-07 00:09:37 +0000493 SourceLocation Loc = Property->getLocation();
494
495 Rewrite.ReplaceText(Loc, 0, "// ", 3);
496
497 // FIXME: handle properties that are declared across multiple lines.
498 }
499}
500
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000501void RewriteTest::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
Steve Naroff423cb562007-10-30 13:30:57 +0000502 SourceLocation LocStart = CatDecl->getLocStart();
503
504 // FIXME: handle category headers that are declared across multiple lines.
505 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
506
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000507 for (ObjCCategoryDecl::instmeth_iterator I = CatDecl->instmeth_begin(),
Steve Naroff58dbdeb2007-12-14 23:37:57 +0000508 E = CatDecl->instmeth_end(); I != E; ++I)
509 RewriteMethodDeclaration(*I);
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000510 for (ObjCCategoryDecl::classmeth_iterator I = CatDecl->classmeth_begin(),
Steve Naroff58dbdeb2007-12-14 23:37:57 +0000511 E = CatDecl->classmeth_end(); I != E; ++I)
512 RewriteMethodDeclaration(*I);
513
Steve Naroff423cb562007-10-30 13:30:57 +0000514 // Lastly, comment out the @end.
515 Rewrite.ReplaceText(CatDecl->getAtEndLoc(), 0, "// ", 3);
516}
517
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000518void RewriteTest::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
Fariborz Jahanianb82b3ea2007-11-14 01:37:46 +0000519 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
Fariborz Jahanianb82b3ea2007-11-14 01:37:46 +0000520
Steve Naroff752d6ef2007-10-30 16:42:30 +0000521 SourceLocation LocStart = PDecl->getLocStart();
522
523 // FIXME: handle protocol headers that are declared across multiple lines.
524 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
525
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000526 for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(),
Steve Naroff58dbdeb2007-12-14 23:37:57 +0000527 E = PDecl->instmeth_end(); I != E; ++I)
528 RewriteMethodDeclaration(*I);
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000529 for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(),
Steve Naroff58dbdeb2007-12-14 23:37:57 +0000530 E = PDecl->classmeth_end(); I != E; ++I)
531 RewriteMethodDeclaration(*I);
532
Steve Naroff752d6ef2007-10-30 16:42:30 +0000533 // Lastly, comment out the @end.
Fariborz Jahanianb82b3ea2007-11-14 01:37:46 +0000534 SourceLocation LocEnd = PDecl->getAtEndLoc();
535 Rewrite.ReplaceText(LocEnd, 0, "// ", 3);
Steve Naroff8cc764c2007-11-14 15:03:57 +0000536
Fariborz Jahanianb82b3ea2007-11-14 01:37:46 +0000537 // Must comment out @optional/@required
538 const char *startBuf = SM->getCharacterData(LocStart);
539 const char *endBuf = SM->getCharacterData(LocEnd);
540 for (const char *p = startBuf; p < endBuf; p++) {
541 if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) {
542 std::string CommentedOptional = "/* @optional */";
Steve Naroff8cc764c2007-11-14 15:03:57 +0000543 SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
Fariborz Jahanianb82b3ea2007-11-14 01:37:46 +0000544 Rewrite.ReplaceText(OptionalLoc, strlen("@optional"),
545 CommentedOptional.c_str(), CommentedOptional.size());
546
547 }
548 else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) {
549 std::string CommentedRequired = "/* @required */";
Steve Naroff8cc764c2007-11-14 15:03:57 +0000550 SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
Fariborz Jahanianb82b3ea2007-11-14 01:37:46 +0000551 Rewrite.ReplaceText(OptionalLoc, strlen("@required"),
552 CommentedRequired.c_str(), CommentedRequired.size());
553
554 }
555 }
Steve Naroff752d6ef2007-10-30 16:42:30 +0000556}
557
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000558void RewriteTest::RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *PDecl) {
Fariborz Jahaniand175ddf2007-11-14 00:42:16 +0000559 SourceLocation LocStart = PDecl->getLocation();
Steve Naroffb7fa9922007-11-14 03:37:28 +0000560 if (LocStart.isInvalid())
561 assert(false && "Invalid SourceLocation");
Fariborz Jahaniand175ddf2007-11-14 00:42:16 +0000562 // FIXME: handle forward protocol that are declared across multiple lines.
563 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
564}
565
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000566void RewriteTest::RewriteObjCMethodDecl(ObjCMethodDecl *OMD,
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000567 std::string &ResultStr) {
568 ResultStr += "\nstatic ";
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000569 if (OMD->getResultType()->isObjCQualifiedIdType())
Fariborz Jahanianc5692492007-12-17 21:03:50 +0000570 ResultStr += "id";
571 else
572 ResultStr += OMD->getResultType().getAsString();
Fariborz Jahanian531a1ea2008-01-10 01:39:52 +0000573 ResultStr += " ";
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000574
575 // Unique method name
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000576 std::string NameStr;
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000577
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000578 if (OMD->isInstance())
579 NameStr += "_I_";
580 else
581 NameStr += "_C_";
582
583 NameStr += OMD->getClassInterface()->getName();
584 NameStr += "_";
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000585
586 NamedDecl *MethodContext = OMD->getMethodContext();
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000587 if (ObjCCategoryImplDecl *CID =
588 dyn_cast<ObjCCategoryImplDecl>(MethodContext)) {
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000589 NameStr += CID->getName();
590 NameStr += "_";
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000591 }
592 // Append selector names, replacing ':' with '_'
593 const char *selName = OMD->getSelector().getName().c_str();
594 if (!strchr(selName, ':'))
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000595 NameStr += OMD->getSelector().getName();
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000596 else {
597 std::string selString = OMD->getSelector().getName();
598 int len = selString.size();
599 for (int i = 0; i < len; i++)
600 if (selString[i] == ':')
601 selString[i] = '_';
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000602 NameStr += selString;
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000603 }
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000604 // Remember this name for metadata emission
605 MethodInternalNames[OMD] = NameStr;
606 ResultStr += NameStr;
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000607
608 // Rewrite arguments
609 ResultStr += "(";
610
611 // invisible arguments
612 if (OMD->isInstance()) {
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000613 QualType selfTy = Context->getObjCInterfaceType(OMD->getClassInterface());
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000614 selfTy = Context->getPointerType(selfTy);
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000615 if (ObjCSynthesizedStructs.count(OMD->getClassInterface()))
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000616 ResultStr += "struct ";
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000617 ResultStr += selfTy.getAsString();
618 }
619 else
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000620 ResultStr += Context->getObjCIdType().getAsString();
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000621
622 ResultStr += " self, ";
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000623 ResultStr += Context->getObjCSelType().getAsString();
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000624 ResultStr += " _cmd";
625
626 // Method arguments.
627 for (int i = 0; i < OMD->getNumParams(); i++) {
628 ParmVarDecl *PDecl = OMD->getParamDecl(i);
629 ResultStr += ", ";
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000630 if (PDecl->getType()->isObjCQualifiedIdType())
Fariborz Jahanianc5692492007-12-17 21:03:50 +0000631 ResultStr += "id";
632 else
633 ResultStr += PDecl->getType().getAsString();
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000634 ResultStr += " ";
635 ResultStr += PDecl->getName();
636 }
Fariborz Jahanian7c39ff72008-01-21 20:14:23 +0000637 if (OMD->isVariadic())
638 ResultStr += ", ...";
Fariborz Jahanian531a1ea2008-01-10 01:39:52 +0000639 ResultStr += ") ";
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000640
641}
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000642void RewriteTest::RewriteImplementationDecl(NamedDecl *OID) {
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000643 ObjCImplementationDecl *IMD = dyn_cast<ObjCImplementationDecl>(OID);
644 ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(OID);
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000645
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000646 if (IMD)
647 Rewrite.InsertText(IMD->getLocStart(), "// ", 3);
648 else
649 Rewrite.InsertText(CID->getLocStart(), "// ", 3);
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000650
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000651 for (ObjCCategoryImplDecl::instmeth_iterator
Chris Lattnerab4c4d52007-12-12 07:46:12 +0000652 I = IMD ? IMD->instmeth_begin() : CID->instmeth_begin(),
653 E = IMD ? IMD->instmeth_end() : CID->instmeth_end(); I != E; ++I) {
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000654 std::string ResultStr;
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000655 ObjCMethodDecl *OMD = *I;
656 RewriteObjCMethodDecl(OMD, ResultStr);
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000657 SourceLocation LocStart = OMD->getLocStart();
658 SourceLocation LocEnd = OMD->getBody()->getLocStart();
659
660 const char *startBuf = SM->getCharacterData(LocStart);
661 const char *endBuf = SM->getCharacterData(LocEnd);
662 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
663 ResultStr.c_str(), ResultStr.size());
664 }
665
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000666 for (ObjCCategoryImplDecl::classmeth_iterator
Chris Lattnerab4c4d52007-12-12 07:46:12 +0000667 I = IMD ? IMD->classmeth_begin() : CID->classmeth_begin(),
668 E = IMD ? IMD->classmeth_end() : CID->classmeth_end(); I != E; ++I) {
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000669 std::string ResultStr;
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000670 ObjCMethodDecl *OMD = *I;
671 RewriteObjCMethodDecl(OMD, ResultStr);
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000672 SourceLocation LocStart = OMD->getLocStart();
673 SourceLocation LocEnd = OMD->getBody()->getLocStart();
674
675 const char *startBuf = SM->getCharacterData(LocStart);
676 const char *endBuf = SM->getCharacterData(LocEnd);
677 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
678 ResultStr.c_str(), ResultStr.size());
679 }
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000680 if (IMD)
681 Rewrite.InsertText(IMD->getLocEnd(), "// ", 3);
682 else
683 Rewrite.InsertText(CID->getLocEnd(), "// ", 3);
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000684}
685
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000686void RewriteTest::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
Steve Narofff908a872007-10-30 02:23:23 +0000687 std::string ResultStr;
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000688 if (!ObjCForwardDecls.count(ClassDecl)) {
Steve Naroff6c6a2db2007-11-01 03:35:41 +0000689 // we haven't seen a forward decl - generate a typedef.
Steve Naroff5086a8d2007-11-14 23:02:56 +0000690 ResultStr = "#ifndef _REWRITER_typedef_";
Steve Naroff32174822007-11-09 12:50:28 +0000691 ResultStr += ClassDecl->getName();
692 ResultStr += "\n";
693 ResultStr += "#define _REWRITER_typedef_";
694 ResultStr += ClassDecl->getName();
695 ResultStr += "\n";
Fariborz Jahanian87ce5d12007-12-03 22:25:42 +0000696 ResultStr += "typedef struct ";
697 ResultStr += ClassDecl->getName();
698 ResultStr += " ";
Steve Naroff6c6a2db2007-11-01 03:35:41 +0000699 ResultStr += ClassDecl->getName();
Steve Naroff32174822007-11-09 12:50:28 +0000700 ResultStr += ";\n#endif\n";
Steve Naroff6c6a2db2007-11-01 03:35:41 +0000701
702 // Mark this typedef as having been generated.
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000703 ObjCForwardDecls.insert(ClassDecl);
Steve Naroff6c6a2db2007-11-01 03:35:41 +0000704 }
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000705 SynthesizeObjCInternalStruct(ClassDecl, ResultStr);
Steve Narofff908a872007-10-30 02:23:23 +0000706
Fariborz Jahanian957cf652007-11-07 00:09:37 +0000707 RewriteProperties(ClassDecl->getNumPropertyDecl(),
708 ClassDecl->getPropertyDecl());
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000709 for (ObjCInterfaceDecl::instmeth_iterator I = ClassDecl->instmeth_begin(),
Steve Naroff58dbdeb2007-12-14 23:37:57 +0000710 E = ClassDecl->instmeth_end(); I != E; ++I)
711 RewriteMethodDeclaration(*I);
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000712 for (ObjCInterfaceDecl::classmeth_iterator I = ClassDecl->classmeth_begin(),
Steve Naroff58dbdeb2007-12-14 23:37:57 +0000713 E = ClassDecl->classmeth_end(); I != E; ++I)
714 RewriteMethodDeclaration(*I);
715
Steve Naroff2feac5e2007-10-30 03:43:13 +0000716 // Lastly, comment out the @end.
717 Rewrite.ReplaceText(ClassDecl->getAtEndLoc(), 0, "// ", 3);
Steve Naroffbef11852007-10-26 20:53:56 +0000718}
719
Steve Naroff7e3411b2007-11-15 02:58:25 +0000720Stmt *RewriteTest::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000721 ObjCIvarDecl *D = IV->getDecl();
Steve Naroff7e3411b2007-11-15 02:58:25 +0000722 if (IV->isFreeIvar()) {
723 Expr *Replacement = new MemberExpr(IV->getBase(), true, D,
724 IV->getLocation());
Chris Lattnerdcbc5b02008-01-31 19:37:57 +0000725 ReplaceStmt(IV, Replacement);
Steve Naroff7e3411b2007-11-15 02:58:25 +0000726 delete IV;
727 return Replacement;
Steve Naroffc2a689b2007-11-15 11:33:00 +0000728 } else {
Fariborz Jahanian7da8d942008-01-23 20:34:40 +0000729#if 0
730 /// This code is not right. It seems unnecessary. It breaks use of
731 /// ivar reference used as 'receiver' of an expression; as in:
732 /// [newInv->_container addObject:0];
Steve Naroffc2a689b2007-11-15 11:33:00 +0000733 if (CurMethodDecl) {
734 if (const PointerType *pType = IV->getBase()->getType()->getAsPointerType()) {
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000735 ObjCInterfaceType *intT = dyn_cast<ObjCInterfaceType>(pType->getPointeeType());
Steve Naroffc2a689b2007-11-15 11:33:00 +0000736 if (CurMethodDecl->getClassInterface() == intT->getDecl()) {
737 IdentifierInfo *II = intT->getDecl()->getIdentifier();
738 RecordDecl *RD = new RecordDecl(Decl::Struct, SourceLocation(),
739 II, 0);
740 QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
741
742 CastExpr *castExpr = new CastExpr(castT, IV->getBase(), SourceLocation());
743 // Don't forget the parens to enforce the proper binding.
744 ParenExpr *PE = new ParenExpr(SourceLocation(), SourceLocation(), castExpr);
Chris Lattnerdcbc5b02008-01-31 19:37:57 +0000745 ReplaceStmt(IV->getBase(), PE);
Steve Naroffc2a689b2007-11-15 11:33:00 +0000746 delete IV->getBase();
747 return PE;
748 }
749 }
750 }
Fariborz Jahanian7da8d942008-01-23 20:34:40 +0000751#endif
Steve Naroff7e3411b2007-11-15 02:58:25 +0000752 return IV;
Steve Naroffc2a689b2007-11-15 11:33:00 +0000753 }
Steve Naroff7e3411b2007-11-15 02:58:25 +0000754}
755
Chris Lattnerf04da132007-10-24 17:06:59 +0000756//===----------------------------------------------------------------------===//
757// Function Body / Expression rewriting
758//===----------------------------------------------------------------------===//
759
Steve Narofff3473a72007-11-09 15:20:18 +0000760Stmt *RewriteTest::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
Fariborz Jahaniane8d1c052008-01-15 23:58:23 +0000761 if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
762 isa<DoStmt>(S) || isa<ForStmt>(S))
763 Stmts.push_back(S);
764 else if (isa<ObjCForCollectionStmt>(S)) {
765 Stmts.push_back(S);
766 ObjCBcLabelNo.push_back(++BcLabelCount);
767 }
768
Chris Lattner338d1e22008-01-31 05:10:40 +0000769 SourceLocation OrigStmtEnd = S->getLocEnd();
770
771 // Start by rewriting all children.
Chris Lattner311ff022007-10-16 22:36:42 +0000772 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
773 CI != E; ++CI)
Steve Naroff75730982007-11-07 04:08:17 +0000774 if (*CI) {
Steve Narofff3473a72007-11-09 15:20:18 +0000775 Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(*CI);
Steve Naroff75730982007-11-07 04:08:17 +0000776 if (newStmt)
777 *CI = newStmt;
778 }
Steve Naroffebf2b562007-10-23 23:50:29 +0000779
780 // Handle specific things.
781 if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
782 return RewriteAtEncode(AtEncode);
Steve Naroff7e3411b2007-11-15 02:58:25 +0000783
784 if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S))
785 return RewriteObjCIvarRefExpr(IvarRefExpr);
Steve Naroffb42f8412007-11-05 14:50:49 +0000786
787 if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S))
788 return RewriteAtSelector(AtSelector);
Steve Narofff69cc5d2008-01-30 19:17:43 +0000789
Steve Naroffbeaf2992007-11-03 11:27:19 +0000790 if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S))
791 return RewriteObjCStringLiteral(AtString);
Steve Naroffebf2b562007-10-23 23:50:29 +0000792
Steve Naroff934f2762007-10-24 22:48:43 +0000793 if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {
794 // Before we rewrite it, put the original message expression in a comment.
795 SourceLocation startLoc = MessExpr->getLocStart();
796 SourceLocation endLoc = MessExpr->getLocEnd();
797
798 const char *startBuf = SM->getCharacterData(startLoc);
799 const char *endBuf = SM->getCharacterData(endLoc);
800
801 std::string messString;
802 messString += "// ";
803 messString.append(startBuf, endBuf-startBuf+1);
804 messString += "\n";
Steve Naroffbef11852007-10-26 20:53:56 +0000805
Steve Naroff934f2762007-10-24 22:48:43 +0000806 // FIXME: Missing definition of Rewrite.InsertText(clang::SourceLocation, char const*, unsigned int).
807 // Rewrite.InsertText(startLoc, messString.c_str(), messString.size());
808 // Tried this, but it didn't work either...
Steve Naroff752d6ef2007-10-30 16:42:30 +0000809 // Rewrite.ReplaceText(startLoc, 0, messString.c_str(), messString.size());
Steve Naroffebf2b562007-10-23 23:50:29 +0000810 return RewriteMessageExpr(MessExpr);
Steve Naroff934f2762007-10-24 22:48:43 +0000811 }
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000812
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000813 if (ObjCAtTryStmt *StmtTry = dyn_cast<ObjCAtTryStmt>(S))
814 return RewriteObjCTryStmt(StmtTry);
Steve Naroff2bd03922007-11-07 15:32:26 +0000815
Fariborz Jahaniana0f55792008-01-29 22:59:37 +0000816 if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast<ObjCAtSynchronizedStmt>(S))
817 return RewriteObjCSynchronizedStmt(StmtTry);
818
Ted Kremeneka526c5c2008-01-07 19:49:32 +0000819 if (ObjCAtThrowStmt *StmtThrow = dyn_cast<ObjCAtThrowStmt>(S))
820 return RewriteObjCThrowStmt(StmtThrow);
Fariborz Jahanian36ee2cb2007-12-07 18:47:10 +0000821
822 if (ObjCProtocolExpr *ProtocolExp = dyn_cast<ObjCProtocolExpr>(S))
823 return RewriteObjCProtocolExpr(ProtocolExp);
Fariborz Jahanian10d24f02008-01-07 21:40:22 +0000824
825 if (ObjCForCollectionStmt *StmtForCollection =
826 dyn_cast<ObjCForCollectionStmt>(S))
Chris Lattner338d1e22008-01-31 05:10:40 +0000827 return RewriteObjCForCollectionStmt(StmtForCollection, OrigStmtEnd);
Fariborz Jahaniane8d1c052008-01-15 23:58:23 +0000828 if (BreakStmt *StmtBreakStmt =
829 dyn_cast<BreakStmt>(S))
830 return RewriteBreakStmt(StmtBreakStmt);
831 if (ContinueStmt *StmtContinueStmt =
832 dyn_cast<ContinueStmt>(S))
833 return RewriteContinueStmt(StmtContinueStmt);
Fariborz Jahanian10d24f02008-01-07 21:40:22 +0000834
Fariborz Jahaniane8d1c052008-01-15 23:58:23 +0000835 if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
836 isa<DoStmt>(S) || isa<ForStmt>(S)) {
837 assert(!Stmts.empty() && "Statement stack is empty");
838 assert ((isa<SwitchStmt>(Stmts.back()) || isa<WhileStmt>(Stmts.back()) ||
839 isa<DoStmt>(Stmts.back()) || isa<ForStmt>(Stmts.back()))
840 && "Statement stack mismatch");
841 Stmts.pop_back();
842 }
Steve Naroff874e2322007-11-15 10:28:18 +0000843#if 0
844 if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) {
845 CastExpr *Replacement = new CastExpr(ICE->getType(), ICE->getSubExpr(), SourceLocation());
846 // Get the new text.
847 std::ostringstream Buf;
848 Replacement->printPretty(Buf);
849 const std::string &Str = Buf.str();
850
851 printf("CAST = %s\n", &Str[0]);
852 Rewrite.InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size());
853 delete S;
854 return Replacement;
855 }
856#endif
Chris Lattnere64b7772007-10-24 16:57:36 +0000857 // Return this stmt unmodified.
858 return S;
Chris Lattner311ff022007-10-16 22:36:42 +0000859}
Fariborz Jahanian10d24f02008-01-07 21:40:22 +0000860
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +0000861/// SynthCountByEnumWithState - To print:
862/// ((unsigned int (*)
863/// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
864/// (void *)objc_msgSend)((id)l_collection,
865/// sel_registerName(
866/// "countByEnumeratingWithState:objects:count:"),
867/// &enumState,
868/// (id *)items, (unsigned int)16)
869///
870void RewriteTest::SynthCountByEnumWithState(std::string &buf) {
871 buf += "((unsigned int (*) (id, SEL, struct __objcFastEnumerationState *, "
872 "id *, unsigned int))(void *)objc_msgSend)";
873 buf += "\n\t\t";
874 buf += "((id)l_collection,\n\t\t";
875 buf += "sel_registerName(\"countByEnumeratingWithState:objects:count:\"),";
876 buf += "\n\t\t";
877 buf += "&enumState, "
878 "(id *)items, (unsigned int)16)";
879}
Fariborz Jahanian10d24f02008-01-07 21:40:22 +0000880
Fariborz Jahaniane8d1c052008-01-15 23:58:23 +0000881/// RewriteBreakStmt - Rewrite for a break-stmt inside an ObjC2's foreach
882/// statement to exit to its outer synthesized loop.
883///
884Stmt *RewriteTest::RewriteBreakStmt(BreakStmt *S) {
885 if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back()))
886 return S;
887 // replace break with goto __break_label
888 std::string buf;
889
890 SourceLocation startLoc = S->getLocStart();
891 buf = "goto __break_label_";
892 buf += utostr(ObjCBcLabelNo.back());
893 Rewrite.ReplaceText(startLoc, strlen("break"), buf.c_str(), buf.size());
894
895 return 0;
896}
897
898/// RewriteContinueStmt - Rewrite for a continue-stmt inside an ObjC2's foreach
899/// statement to continue with its inner synthesized loop.
900///
901Stmt *RewriteTest::RewriteContinueStmt(ContinueStmt *S) {
902 if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back()))
903 return S;
904 // replace continue with goto __continue_label
905 std::string buf;
906
907 SourceLocation startLoc = S->getLocStart();
908 buf = "goto __continue_label_";
909 buf += utostr(ObjCBcLabelNo.back());
910 Rewrite.ReplaceText(startLoc, strlen("continue"), buf.c_str(), buf.size());
911
912 return 0;
913}
914
Fariborz Jahaniana0f55792008-01-29 22:59:37 +0000915/// RewriteObjCForCollectionStmt - Rewriter for ObjC2's foreach statement.
Fariborz Jahanian10d24f02008-01-07 21:40:22 +0000916/// It rewrites:
917/// for ( type elem in collection) { stmts; }
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +0000918
Fariborz Jahanian10d24f02008-01-07 21:40:22 +0000919/// Into:
920/// {
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +0000921/// type elem;
922/// struct __objcFastEnumerationState enumState = { 0 };
Fariborz Jahanian10d24f02008-01-07 21:40:22 +0000923/// id items[16];
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +0000924/// id l_collection = (id)collection;
925/// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState
926/// objects:items count:16];
Fariborz Jahanian10d24f02008-01-07 21:40:22 +0000927/// if (limit) {
928/// unsigned long startMutations = *enumState.mutationsPtr;
929/// do {
930/// unsigned long counter = 0;
931/// do {
932/// if (startMutations != *enumState.mutationsPtr)
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +0000933/// objc_enumerationMutation(l_collection);
Fariborz Jahanian88f50f32008-01-09 18:15:42 +0000934/// elem = (type)enumState.itemsPtr[counter++];
Fariborz Jahanian10d24f02008-01-07 21:40:22 +0000935/// stmts;
Fariborz Jahaniane8d1c052008-01-15 23:58:23 +0000936/// __continue_label: ;
Fariborz Jahanian10d24f02008-01-07 21:40:22 +0000937/// } while (counter < limit);
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +0000938/// } while (limit = [l_collection countByEnumeratingWithState:&enumState
939/// objects:items count:16]);
940/// elem = nil;
Fariborz Jahaniane8d1c052008-01-15 23:58:23 +0000941/// __break_label: ;
Fariborz Jahanian10d24f02008-01-07 21:40:22 +0000942/// }
943/// else
944/// elem = nil;
945/// }
946///
Chris Lattner338d1e22008-01-31 05:10:40 +0000947Stmt *RewriteTest::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
948 SourceLocation OrigEnd) {
Fariborz Jahaniane8d1c052008-01-15 23:58:23 +0000949 assert(!Stmts.empty() && "ObjCForCollectionStmt - Statement stack empty");
950 assert(isa<ObjCForCollectionStmt>(Stmts.back()) &&
951 "ObjCForCollectionStmt Statement stack mismatch");
952 assert(!ObjCBcLabelNo.empty() &&
953 "ObjCForCollectionStmt - Label No stack empty");
954
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +0000955 SourceLocation startLoc = S->getLocStart();
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +0000956 const char *startBuf = SM->getCharacterData(startLoc);
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +0000957 const char *elementName;
Fariborz Jahanian88f50f32008-01-09 18:15:42 +0000958 std::string elementTypeAsString;
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +0000959 std::string buf;
960 buf = "\n{\n\t";
961 if (DeclStmt *DS = dyn_cast<DeclStmt>(S->getElement())) {
962 // type elem;
963 QualType ElementType = cast<ValueDecl>(DS->getDecl())->getType();
Fariborz Jahanian88f50f32008-01-09 18:15:42 +0000964 elementTypeAsString = ElementType.getAsString();
965 buf += elementTypeAsString;
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +0000966 buf += " ";
967 elementName = DS->getDecl()->getName();
968 buf += elementName;
969 buf += ";\n\t";
970 }
Fariborz Jahanian88f50f32008-01-09 18:15:42 +0000971 else if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S->getElement())) {
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +0000972 elementName = DR->getDecl()->getName();
Fariborz Jahanian88f50f32008-01-09 18:15:42 +0000973 elementTypeAsString = DR->getDecl()->getType().getAsString();
974 }
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +0000975 else
976 assert(false && "RewriteObjCForCollectionStmt - bad element kind");
977
978 // struct __objcFastEnumerationState enumState = { 0 };
979 buf += "struct __objcFastEnumerationState enumState = { 0 };\n\t";
980 // id items[16];
981 buf += "id items[16];\n\t";
982 // id l_collection = (id)
983 buf += "id l_collection = (id)";
Fariborz Jahanian75712282008-01-10 00:24:29 +0000984 // Find start location of 'collection' the hard way!
985 const char *startCollectionBuf = startBuf;
986 startCollectionBuf += 3; // skip 'for'
987 startCollectionBuf = strchr(startCollectionBuf, '(');
988 startCollectionBuf++; // skip '('
989 // find 'in' and skip it.
990 while (*startCollectionBuf != ' ' ||
991 *(startCollectionBuf+1) != 'i' || *(startCollectionBuf+2) != 'n' ||
992 (*(startCollectionBuf+3) != ' ' &&
993 *(startCollectionBuf+3) != '[' && *(startCollectionBuf+3) != '('))
994 startCollectionBuf++;
995 startCollectionBuf += 3;
996
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +0000997 // Replace: "for (type element in" with string constructed thus far.
998 Rewrite.ReplaceText(startLoc, startCollectionBuf - startBuf,
999 buf.c_str(), buf.size());
1000 // Replace ')' in for '(' type elem in collection ')' with ';'
Fariborz Jahanian75712282008-01-10 00:24:29 +00001001 SourceLocation rightParenLoc = S->getRParenLoc();
1002 const char *rparenBuf = SM->getCharacterData(rightParenLoc);
1003 SourceLocation lparenLoc = startLoc.getFileLocWithOffset(rparenBuf-startBuf);
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +00001004 buf = ";\n\t";
1005
1006 // unsigned long limit = [l_collection countByEnumeratingWithState:&enumState
1007 // objects:items count:16];
1008 // which is synthesized into:
1009 // unsigned int limit =
1010 // ((unsigned int (*)
1011 // (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
1012 // (void *)objc_msgSend)((id)l_collection,
1013 // sel_registerName(
1014 // "countByEnumeratingWithState:objects:count:"),
1015 // (struct __objcFastEnumerationState *)&state,
1016 // (id *)items, (unsigned int)16);
1017 buf += "unsigned long limit =\n\t\t";
1018 SynthCountByEnumWithState(buf);
1019 buf += ";\n\t";
1020 /// if (limit) {
1021 /// unsigned long startMutations = *enumState.mutationsPtr;
1022 /// do {
1023 /// unsigned long counter = 0;
1024 /// do {
1025 /// if (startMutations != *enumState.mutationsPtr)
1026 /// objc_enumerationMutation(l_collection);
Fariborz Jahanian88f50f32008-01-09 18:15:42 +00001027 /// elem = (type)enumState.itemsPtr[counter++];
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +00001028 buf += "if (limit) {\n\t";
1029 buf += "unsigned long startMutations = *enumState.mutationsPtr;\n\t";
1030 buf += "do {\n\t\t";
1031 buf += "unsigned long counter = 0;\n\t\t";
1032 buf += "do {\n\t\t\t";
1033 buf += "if (startMutations != *enumState.mutationsPtr)\n\t\t\t\t";
1034 buf += "objc_enumerationMutation(l_collection);\n\t\t\t";
1035 buf += elementName;
Fariborz Jahanian88f50f32008-01-09 18:15:42 +00001036 buf += " = (";
1037 buf += elementTypeAsString;
1038 buf += ")enumState.itemsPtr[counter++];";
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +00001039 // Replace ')' in for '(' type elem in collection ')' with all of these.
1040 Rewrite.ReplaceText(lparenLoc, 1, buf.c_str(), buf.size());
1041
Fariborz Jahaniane8d1c052008-01-15 23:58:23 +00001042 /// __continue_label: ;
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +00001043 /// } while (counter < limit);
1044 /// } while (limit = [l_collection countByEnumeratingWithState:&enumState
1045 /// objects:items count:16]);
1046 /// elem = nil;
Fariborz Jahaniane8d1c052008-01-15 23:58:23 +00001047 /// __break_label: ;
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +00001048 /// }
1049 /// else
1050 /// elem = nil;
1051 /// }
Fariborz Jahaniane8d1c052008-01-15 23:58:23 +00001052 ///
1053 buf = ";\n\t";
1054 buf += "__continue_label_";
1055 buf += utostr(ObjCBcLabelNo.back());
1056 buf += ": ;";
1057 buf += "\n\t\t";
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +00001058 buf += "} while (counter < limit);\n\t";
1059 buf += "} while (limit = ";
1060 SynthCountByEnumWithState(buf);
1061 buf += ");\n\t";
1062 buf += elementName;
1063 buf += " = nil;\n\t";
Fariborz Jahaniane8d1c052008-01-15 23:58:23 +00001064 buf += "__break_label_";
1065 buf += utostr(ObjCBcLabelNo.back());
1066 buf += ": ;\n\t";
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +00001067 buf += "}\n\t";
1068 buf += "else\n\t\t";
1069 buf += elementName;
1070 buf += " = nil;\n";
1071 buf += "}\n";
1072 // Insert all these *after* the statement body.
Chris Lattner338d1e22008-01-31 05:10:40 +00001073 SourceLocation endBodyLoc = OrigEnd.getFileLocWithOffset(1);
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +00001074 Rewrite.InsertText(endBodyLoc, buf.c_str(), buf.size());
Fariborz Jahaniane8d1c052008-01-15 23:58:23 +00001075 Stmts.pop_back();
1076 ObjCBcLabelNo.pop_back();
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +00001077 return 0;
Fariborz Jahanian10d24f02008-01-07 21:40:22 +00001078}
1079
Fariborz Jahaniana0f55792008-01-29 22:59:37 +00001080/// RewriteObjCSynchronizedStmt -
1081/// This routine rewrites @synchronized(expr) stmt;
1082/// into:
1083/// objc_sync_enter(expr);
1084/// @try stmt @finally { objc_sync_exit(expr); }
1085///
1086Stmt *RewriteTest::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
1087 // Get the start location and compute the semi location.
1088 SourceLocation startLoc = S->getLocStart();
1089 const char *startBuf = SM->getCharacterData(startLoc);
1090
1091 assert((*startBuf == '@') && "bogus @synchronized location");
1092
1093 std::string buf;
1094 buf = "objc_sync_enter";
1095 Rewrite.ReplaceText(startLoc, 13, buf.c_str(), buf.size());
1096 SourceLocation endLoc = S->getSynchExpr()->getLocEnd();
1097 const char *endBuf = SM->getCharacterData(endLoc);
1098 endBuf++;
1099 const char *rparenBuf = strchr(endBuf, ')');
1100 SourceLocation rparenLoc = startLoc.getFileLocWithOffset(rparenBuf-startBuf);
1101 buf = ");\n";
1102 // declare a new scope with two variables, _stack and _rethrow.
1103 buf += "/* @try scope begin */ \n{ struct _objc_exception_data {\n";
1104 buf += "int buf[18/*32-bit i386*/];\n";
1105 buf += "char *pointers[4];} _stack;\n";
1106 buf += "id volatile _rethrow = 0;\n";
1107 buf += "objc_exception_try_enter(&_stack);\n";
1108 buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";
1109 Rewrite.ReplaceText(rparenLoc, 1, buf.c_str(), buf.size());
1110 startLoc = S->getSynchBody()->getLocEnd();
1111 startBuf = SM->getCharacterData(startLoc);
1112
1113 assert((*startBuf == '}') && "bogus @try block");
1114 SourceLocation lastCurlyLoc = startLoc;
1115 buf = "}\nelse {\n";
1116 buf += " _rethrow = objc_exception_extract(&_stack);\n";
1117 buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
1118 // FIXME: This must be objc_sync_exit(syncExpr);
1119 buf += " objc_sync_exit();\n";
1120 buf += " if (_rethrow) objc_exception_throw(_rethrow);\n";
1121 buf += "}\n";
1122 buf += "}";
1123
1124 Rewrite.ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size());
1125 return 0;
1126}
1127
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001128Stmt *RewriteTest::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
Steve Naroff75730982007-11-07 04:08:17 +00001129 // Get the start location and compute the semi location.
1130 SourceLocation startLoc = S->getLocStart();
1131 const char *startBuf = SM->getCharacterData(startLoc);
1132
1133 assert((*startBuf == '@') && "bogus @try location");
1134
1135 std::string buf;
1136 // declare a new scope with two variables, _stack and _rethrow.
1137 buf = "/* @try scope begin */ { struct _objc_exception_data {\n";
1138 buf += "int buf[18/*32-bit i386*/];\n";
1139 buf += "char *pointers[4];} _stack;\n";
1140 buf += "id volatile _rethrow = 0;\n";
1141 buf += "objc_exception_try_enter(&_stack);\n";
Steve Naroff21867b12007-11-07 18:43:40 +00001142 buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";
Steve Naroff75730982007-11-07 04:08:17 +00001143
1144 Rewrite.ReplaceText(startLoc, 4, buf.c_str(), buf.size());
1145
1146 startLoc = S->getTryBody()->getLocEnd();
1147 startBuf = SM->getCharacterData(startLoc);
1148
1149 assert((*startBuf == '}') && "bogus @try block");
1150
1151 SourceLocation lastCurlyLoc = startLoc;
1152
1153 startLoc = startLoc.getFileLocWithOffset(1);
1154 buf = " /* @catch begin */ else {\n";
1155 buf += " id _caught = objc_exception_extract(&_stack);\n";
1156 buf += " objc_exception_try_enter (&_stack);\n";
Steve Naroff21867b12007-11-07 18:43:40 +00001157 buf += " if (_setjmp(_stack.buf))\n";
Steve Naroff75730982007-11-07 04:08:17 +00001158 buf += " _rethrow = objc_exception_extract(&_stack);\n";
1159 buf += " else { /* @catch continue */";
1160
Chris Lattner28d1fe82007-11-08 04:41:51 +00001161 Rewrite.InsertText(startLoc, buf.c_str(), buf.size());
Steve Naroff75730982007-11-07 04:08:17 +00001162
1163 bool sawIdTypedCatch = false;
1164 Stmt *lastCatchBody = 0;
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001165 ObjCAtCatchStmt *catchList = S->getCatchStmts();
Steve Naroff75730982007-11-07 04:08:17 +00001166 while (catchList) {
1167 Stmt *catchStmt = catchList->getCatchParamStmt();
1168
1169 if (catchList == S->getCatchStmts())
1170 buf = "if ("; // we are generating code for the first catch clause
1171 else
1172 buf = "else if (";
1173 startLoc = catchList->getLocStart();
1174 startBuf = SM->getCharacterData(startLoc);
1175
1176 assert((*startBuf == '@') && "bogus @catch location");
1177
1178 const char *lParenLoc = strchr(startBuf, '(');
1179
1180 if (DeclStmt *declStmt = dyn_cast<DeclStmt>(catchStmt)) {
1181 QualType t = dyn_cast<ValueDecl>(declStmt->getDecl())->getType();
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001182 if (t == Context->getObjCIdType()) {
Steve Naroff75730982007-11-07 04:08:17 +00001183 buf += "1) { ";
1184 Rewrite.ReplaceText(startLoc, lParenLoc-startBuf+1,
1185 buf.c_str(), buf.size());
1186 sawIdTypedCatch = true;
1187 } else if (const PointerType *pType = t->getAsPointerType()) {
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001188 ObjCInterfaceType *cls; // Should be a pointer to a class.
Steve Naroff75730982007-11-07 04:08:17 +00001189
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001190 cls = dyn_cast<ObjCInterfaceType>(pType->getPointeeType().getTypePtr());
Steve Naroff75730982007-11-07 04:08:17 +00001191 if (cls) {
Steve Naroff21867b12007-11-07 18:43:40 +00001192 buf += "objc_exception_match((struct objc_class *)objc_getClass(\"";
Steve Naroff75730982007-11-07 04:08:17 +00001193 buf += cls->getDecl()->getName();
Steve Naroff21867b12007-11-07 18:43:40 +00001194 buf += "\"), (struct objc_object *)_caught)) { ";
Steve Naroff75730982007-11-07 04:08:17 +00001195 Rewrite.ReplaceText(startLoc, lParenLoc-startBuf+1,
1196 buf.c_str(), buf.size());
1197 }
1198 }
1199 // Now rewrite the body...
1200 lastCatchBody = catchList->getCatchBody();
1201 SourceLocation rParenLoc = catchList->getRParenLoc();
1202 SourceLocation bodyLoc = lastCatchBody->getLocStart();
1203 const char *bodyBuf = SM->getCharacterData(bodyLoc);
1204 const char *rParenBuf = SM->getCharacterData(rParenLoc);
1205 assert((*rParenBuf == ')') && "bogus @catch paren location");
1206 assert((*bodyBuf == '{') && "bogus @catch body location");
1207
1208 buf = " = _caught;";
1209 // Here we replace ") {" with "= _caught;" (which initializes and
1210 // declares the @catch parameter).
1211 Rewrite.ReplaceText(rParenLoc, bodyBuf-rParenBuf+1,
1212 buf.c_str(), buf.size());
Steve Naroff2bd03922007-11-07 15:32:26 +00001213 } else if (!isa<NullStmt>(catchStmt)) {
Steve Naroff75730982007-11-07 04:08:17 +00001214 assert(false && "@catch rewrite bug");
Steve Naroff2bd03922007-11-07 15:32:26 +00001215 }
Steve Naroff75730982007-11-07 04:08:17 +00001216 catchList = catchList->getNextCatchStmt();
1217 }
1218 // Complete the catch list...
1219 if (lastCatchBody) {
1220 SourceLocation bodyLoc = lastCatchBody->getLocEnd();
1221 const char *bodyBuf = SM->getCharacterData(bodyLoc);
1222 assert((*bodyBuf == '}') && "bogus @catch body location");
1223 bodyLoc = bodyLoc.getFileLocWithOffset(1);
1224 buf = " } } /* @catch end */\n";
1225
Chris Lattner28d1fe82007-11-08 04:41:51 +00001226 Rewrite.InsertText(bodyLoc, buf.c_str(), buf.size());
Steve Naroff75730982007-11-07 04:08:17 +00001227
1228 // Set lastCurlyLoc
1229 lastCurlyLoc = lastCatchBody->getLocEnd();
1230 }
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001231 if (ObjCAtFinallyStmt *finalStmt = S->getFinallyStmt()) {
Steve Naroff75730982007-11-07 04:08:17 +00001232 startLoc = finalStmt->getLocStart();
1233 startBuf = SM->getCharacterData(startLoc);
1234 assert((*startBuf == '@') && "bogus @finally start");
1235
1236 buf = "/* @finally */";
1237 Rewrite.ReplaceText(startLoc, 8, buf.c_str(), buf.size());
1238
1239 Stmt *body = finalStmt->getFinallyBody();
1240 SourceLocation startLoc = body->getLocStart();
1241 SourceLocation endLoc = body->getLocEnd();
1242 const char *startBuf = SM->getCharacterData(startLoc);
1243 const char *endBuf = SM->getCharacterData(endLoc);
1244 assert((*startBuf == '{') && "bogus @finally body location");
1245 assert((*endBuf == '}') && "bogus @finally body location");
1246
1247 startLoc = startLoc.getFileLocWithOffset(1);
1248 buf = " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
Chris Lattner28d1fe82007-11-08 04:41:51 +00001249 Rewrite.InsertText(startLoc, buf.c_str(), buf.size());
Steve Naroff75730982007-11-07 04:08:17 +00001250 endLoc = endLoc.getFileLocWithOffset(-1);
1251 buf = " if (_rethrow) objc_exception_throw(_rethrow);\n";
Chris Lattner28d1fe82007-11-08 04:41:51 +00001252 Rewrite.InsertText(endLoc, buf.c_str(), buf.size());
Steve Naroff75730982007-11-07 04:08:17 +00001253
1254 // Set lastCurlyLoc
1255 lastCurlyLoc = body->getLocEnd();
1256 }
1257 // Now emit the final closing curly brace...
1258 lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1);
1259 buf = " } /* @try scope end */\n";
Chris Lattner28d1fe82007-11-08 04:41:51 +00001260 Rewrite.InsertText(lastCurlyLoc, buf.c_str(), buf.size());
Fariborz Jahanian909f02a2007-11-05 17:47:33 +00001261 return 0;
1262}
1263
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001264Stmt *RewriteTest::RewriteObjCCatchStmt(ObjCAtCatchStmt *S) {
Fariborz Jahanian909f02a2007-11-05 17:47:33 +00001265 return 0;
1266}
1267
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001268Stmt *RewriteTest::RewriteObjCFinallyStmt(ObjCAtFinallyStmt *S) {
Fariborz Jahanian909f02a2007-11-05 17:47:33 +00001269 return 0;
1270}
1271
Chris Lattnerdcbc5b02008-01-31 19:37:57 +00001272// This can't be done with ReplaceStmt(S, ThrowExpr), since
Steve Naroff2bd03922007-11-07 15:32:26 +00001273// the throw expression is typically a message expression that's already
1274// been rewritten! (which implies the SourceLocation's are invalid).
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001275Stmt *RewriteTest::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) {
Steve Naroff2bd03922007-11-07 15:32:26 +00001276 // Get the start location and compute the semi location.
1277 SourceLocation startLoc = S->getLocStart();
1278 const char *startBuf = SM->getCharacterData(startLoc);
1279
1280 assert((*startBuf == '@') && "bogus @throw location");
1281
1282 std::string buf;
1283 /* void objc_exception_throw(id) __attribute__((noreturn)); */
Steve Naroff20ebf8f2008-01-19 00:42:38 +00001284 if (S->getThrowExpr())
1285 buf = "objc_exception_throw(";
1286 else // add an implicit argument
1287 buf = "objc_exception_throw(_caught";
Steve Naroff2bd03922007-11-07 15:32:26 +00001288 Rewrite.ReplaceText(startLoc, 6, buf.c_str(), buf.size());
1289 const char *semiBuf = strchr(startBuf, ';');
1290 assert((*semiBuf == ';') && "@throw: can't find ';'");
1291 SourceLocation semiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf);
1292 buf = ");";
1293 Rewrite.ReplaceText(semiLoc, 1, buf.c_str(), buf.size());
1294 return 0;
1295}
Fariborz Jahanian909f02a2007-11-05 17:47:33 +00001296
Chris Lattnere64b7772007-10-24 16:57:36 +00001297Stmt *RewriteTest::RewriteAtEncode(ObjCEncodeExpr *Exp) {
Chris Lattner01c57482007-10-17 22:35:30 +00001298 // Create a new string expression.
1299 QualType StrType = Context->getPointerType(Context->CharTy);
Anders Carlsson85f9bce2007-10-29 05:01:08 +00001300 std::string StrEncoding;
Fariborz Jahanian7d6b46d2008-01-22 22:44:46 +00001301 Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding,
1302 EncodingRecordTypes);
Anders Carlsson85f9bce2007-10-29 05:01:08 +00001303 Expr *Replacement = new StringLiteral(StrEncoding.c_str(),
1304 StrEncoding.length(), false, StrType,
Chris Lattner01c57482007-10-17 22:35:30 +00001305 SourceLocation(), SourceLocation());
Chris Lattnerdcbc5b02008-01-31 19:37:57 +00001306 ReplaceStmt(Exp, Replacement);
Chris Lattnere365c502007-11-30 22:25:36 +00001307
Chris Lattner07506182007-11-30 22:53:43 +00001308 // Replace this subexpr in the parent.
Chris Lattnere64b7772007-10-24 16:57:36 +00001309 delete Exp;
1310 return Replacement;
Chris Lattner311ff022007-10-16 22:36:42 +00001311}
1312
Steve Naroffb42f8412007-11-05 14:50:49 +00001313Stmt *RewriteTest::RewriteAtSelector(ObjCSelectorExpr *Exp) {
1314 assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");
1315 // Create a call to sel_registerName("selName").
1316 llvm::SmallVector<Expr*, 8> SelExprs;
1317 QualType argType = Context->getPointerType(Context->CharTy);
1318 SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
1319 Exp->getSelector().getName().size(),
1320 false, argType, SourceLocation(),
1321 SourceLocation()));
1322 CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
1323 &SelExprs[0], SelExprs.size());
Chris Lattnerdcbc5b02008-01-31 19:37:57 +00001324 ReplaceStmt(Exp, SelExp);
Steve Naroffb42f8412007-11-05 14:50:49 +00001325 delete Exp;
1326 return SelExp;
1327}
1328
Steve Naroff934f2762007-10-24 22:48:43 +00001329CallExpr *RewriteTest::SynthesizeCallToFunctionDecl(
1330 FunctionDecl *FD, Expr **args, unsigned nargs) {
Steve Naroffebf2b562007-10-23 23:50:29 +00001331 // Get the type, we will need to reference it in a couple spots.
Steve Naroff934f2762007-10-24 22:48:43 +00001332 QualType msgSendType = FD->getType();
Steve Naroffebf2b562007-10-23 23:50:29 +00001333
1334 // Create a reference to the objc_msgSend() declaration.
Steve Naroff934f2762007-10-24 22:48:43 +00001335 DeclRefExpr *DRE = new DeclRefExpr(FD, msgSendType, SourceLocation());
Steve Naroffebf2b562007-10-23 23:50:29 +00001336
1337 // Now, we cast the reference to a pointer to the objc_msgSend type.
Chris Lattnerf04da132007-10-24 17:06:59 +00001338 QualType pToFunc = Context->getPointerType(msgSendType);
Steve Naroffebf2b562007-10-23 23:50:29 +00001339 ImplicitCastExpr *ICE = new ImplicitCastExpr(pToFunc, DRE);
1340
1341 const FunctionType *FT = msgSendType->getAsFunctionType();
Chris Lattnere64b7772007-10-24 16:57:36 +00001342
Steve Naroff934f2762007-10-24 22:48:43 +00001343 return new CallExpr(ICE, args, nargs, FT->getResultType(), SourceLocation());
1344}
1345
Steve Naroffd5255f52007-11-01 13:24:47 +00001346static bool scanForProtocolRefs(const char *startBuf, const char *endBuf,
1347 const char *&startRef, const char *&endRef) {
1348 while (startBuf < endBuf) {
1349 if (*startBuf == '<')
1350 startRef = startBuf; // mark the start.
1351 if (*startBuf == '>') {
Steve Naroff32174822007-11-09 12:50:28 +00001352 if (startRef && *startRef == '<') {
1353 endRef = startBuf; // mark the end.
1354 return true;
1355 }
1356 return false;
Steve Naroffd5255f52007-11-01 13:24:47 +00001357 }
1358 startBuf++;
1359 }
1360 return false;
1361}
1362
Fariborz Jahanian61477f72007-12-11 22:50:14 +00001363static void scanToNextArgument(const char *&argRef) {
1364 int angle = 0;
1365 while (*argRef != ')' && (*argRef != ',' || angle > 0)) {
1366 if (*argRef == '<')
1367 angle++;
1368 else if (*argRef == '>')
1369 angle--;
1370 argRef++;
1371 }
1372 assert(angle == 0 && "scanToNextArgument - bad protocol type syntax");
1373}
Fariborz Jahanian291e04b2007-12-11 23:04:08 +00001374
Steve Naroffd5255f52007-11-01 13:24:47 +00001375bool RewriteTest::needToScanForQualifiers(QualType T) {
Fariborz Jahanianc5692492007-12-17 21:03:50 +00001376
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001377 if (T == Context->getObjCIdType())
Steve Naroffd5255f52007-11-01 13:24:47 +00001378 return true;
1379
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001380 if (T->isObjCQualifiedIdType())
Fariborz Jahanianc5692492007-12-17 21:03:50 +00001381 return true;
1382
Steve Naroffd5255f52007-11-01 13:24:47 +00001383 if (const PointerType *pType = T->getAsPointerType()) {
Steve Naroff9165ad32007-10-31 04:38:33 +00001384 Type *pointeeType = pType->getPointeeType().getTypePtr();
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001385 if (isa<ObjCQualifiedInterfaceType>(pointeeType))
Steve Naroff9165ad32007-10-31 04:38:33 +00001386 return true; // we have "Class <Protocol> *".
1387 }
Steve Naroffd5255f52007-11-01 13:24:47 +00001388 return false;
1389}
1390
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001391void RewriteTest::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
Fariborz Jahanian61477f72007-12-11 22:50:14 +00001392 SourceLocation Loc;
1393 QualType Type;
1394 const FunctionTypeProto *proto = 0;
1395 if (VarDecl *VD = dyn_cast<VarDecl>(Dcl)) {
1396 Loc = VD->getLocation();
1397 Type = VD->getType();
1398 }
1399 else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Dcl)) {
1400 Loc = FD->getLocation();
1401 // Check for ObjC 'id' and class types that have been adorned with protocol
1402 // information (id<p>, C<p>*). The protocol references need to be rewritten!
1403 const FunctionType *funcType = FD->getType()->getAsFunctionType();
1404 assert(funcType && "missing function type");
1405 proto = dyn_cast<FunctionTypeProto>(funcType);
1406 if (!proto)
1407 return;
1408 Type = proto->getResultType();
1409 }
1410 else
1411 return;
Steve Naroffd5255f52007-11-01 13:24:47 +00001412
Fariborz Jahanian61477f72007-12-11 22:50:14 +00001413 if (needToScanForQualifiers(Type)) {
Steve Naroffd5255f52007-11-01 13:24:47 +00001414 // Since types are unique, we need to scan the buffer.
Steve Naroffd5255f52007-11-01 13:24:47 +00001415
1416 const char *endBuf = SM->getCharacterData(Loc);
1417 const char *startBuf = endBuf;
Chris Lattner26de4652007-12-02 01:13:47 +00001418 while (*startBuf != ';' && startBuf != MainFileStart)
Steve Naroffd5255f52007-11-01 13:24:47 +00001419 startBuf--; // scan backward (from the decl location) for return type.
1420 const char *startRef = 0, *endRef = 0;
1421 if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
1422 // Get the locations of the startRef, endRef.
1423 SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-endBuf);
1424 SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-endBuf+1);
1425 // Comment out the protocol references.
Chris Lattner28d1fe82007-11-08 04:41:51 +00001426 Rewrite.InsertText(LessLoc, "/*", 2);
1427 Rewrite.InsertText(GreaterLoc, "*/", 2);
Steve Naroff9165ad32007-10-31 04:38:33 +00001428 }
1429 }
Fariborz Jahanian61477f72007-12-11 22:50:14 +00001430 if (!proto)
1431 return; // most likely, was a variable
Steve Naroffd5255f52007-11-01 13:24:47 +00001432 // Now check arguments.
Fariborz Jahanian61477f72007-12-11 22:50:14 +00001433 const char *startBuf = SM->getCharacterData(Loc);
1434 const char *startFuncBuf = startBuf;
Steve Naroffd5255f52007-11-01 13:24:47 +00001435 for (unsigned i = 0; i < proto->getNumArgs(); i++) {
1436 if (needToScanForQualifiers(proto->getArgType(i))) {
1437 // Since types are unique, we need to scan the buffer.
Steve Naroffd5255f52007-11-01 13:24:47 +00001438
Steve Naroffd5255f52007-11-01 13:24:47 +00001439 const char *endBuf = startBuf;
Fariborz Jahanian61477f72007-12-11 22:50:14 +00001440 // scan forward (from the decl location) for argument types.
1441 scanToNextArgument(endBuf);
Steve Naroffd5255f52007-11-01 13:24:47 +00001442 const char *startRef = 0, *endRef = 0;
1443 if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
1444 // Get the locations of the startRef, endRef.
Fariborz Jahanian291e04b2007-12-11 23:04:08 +00001445 SourceLocation LessLoc =
1446 Loc.getFileLocWithOffset(startRef-startFuncBuf);
1447 SourceLocation GreaterLoc =
1448 Loc.getFileLocWithOffset(endRef-startFuncBuf+1);
Steve Naroffd5255f52007-11-01 13:24:47 +00001449 // Comment out the protocol references.
Chris Lattner28d1fe82007-11-08 04:41:51 +00001450 Rewrite.InsertText(LessLoc, "/*", 2);
1451 Rewrite.InsertText(GreaterLoc, "*/", 2);
Steve Naroffd5255f52007-11-01 13:24:47 +00001452 }
Fariborz Jahanian61477f72007-12-11 22:50:14 +00001453 startBuf = ++endBuf;
1454 }
1455 else {
1456 while (*startBuf != ')' && *startBuf != ',')
1457 startBuf++; // scan forward (from the decl location) for argument types.
1458 startBuf++;
1459 }
Steve Naroffd5255f52007-11-01 13:24:47 +00001460 }
Steve Naroff9165ad32007-10-31 04:38:33 +00001461}
1462
Fariborz Jahaniana70711b2007-12-04 21:47:40 +00001463// SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str);
1464void RewriteTest::SynthSelGetUidFunctionDecl() {
1465 IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName");
1466 llvm::SmallVector<QualType, 16> ArgTys;
1467 ArgTys.push_back(Context->getPointerType(
1468 Context->CharTy.getQualifiedType(QualType::Const)));
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001469 QualType getFuncType = Context->getFunctionType(Context->getObjCSelType(),
Fariborz Jahaniana70711b2007-12-04 21:47:40 +00001470 &ArgTys[0], ArgTys.size(),
1471 false /*isVariadic*/);
1472 SelGetUidFunctionDecl = new FunctionDecl(SourceLocation(),
1473 SelGetUidIdent, getFuncType,
1474 FunctionDecl::Extern, false, 0);
1475}
1476
Fariborz Jahanian36ee2cb2007-12-07 18:47:10 +00001477// SynthGetProtocolFunctionDecl - Protocol objc_getProtocol(const char *proto);
1478void RewriteTest::SynthGetProtocolFunctionDecl() {
1479 IdentifierInfo *SelGetProtoIdent = &Context->Idents.get("objc_getProtocol");
1480 llvm::SmallVector<QualType, 16> ArgTys;
1481 ArgTys.push_back(Context->getPointerType(
1482 Context->CharTy.getQualifiedType(QualType::Const)));
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001483 QualType getFuncType = Context->getFunctionType(Context->getObjCProtoType(),
Fariborz Jahanian36ee2cb2007-12-07 18:47:10 +00001484 &ArgTys[0], ArgTys.size(),
1485 false /*isVariadic*/);
1486 GetProtocolFunctionDecl = new FunctionDecl(SourceLocation(),
1487 SelGetProtoIdent, getFuncType,
1488 FunctionDecl::Extern, false, 0);
1489}
1490
Steve Naroff09b266e2007-10-30 23:14:51 +00001491void RewriteTest::RewriteFunctionDecl(FunctionDecl *FD) {
1492 // declared in <objc/objc.h>
Steve Naroffbeaf2992007-11-03 11:27:19 +00001493 if (strcmp(FD->getName(), "sel_registerName") == 0) {
Steve Naroff09b266e2007-10-30 23:14:51 +00001494 SelGetUidFunctionDecl = FD;
Steve Naroff9165ad32007-10-31 04:38:33 +00001495 return;
1496 }
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001497 RewriteObjCQualifiedInterfaceTypes(FD);
Steve Naroff09b266e2007-10-30 23:14:51 +00001498}
1499
1500// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
1501void RewriteTest::SynthMsgSendFunctionDecl() {
1502 IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend");
1503 llvm::SmallVector<QualType, 16> ArgTys;
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001504 QualType argT = Context->getObjCIdType();
Steve Naroff09b266e2007-10-30 23:14:51 +00001505 assert(!argT.isNull() && "Can't find 'id' type");
1506 ArgTys.push_back(argT);
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001507 argT = Context->getObjCSelType();
Steve Naroff09b266e2007-10-30 23:14:51 +00001508 assert(!argT.isNull() && "Can't find 'SEL' type");
1509 ArgTys.push_back(argT);
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001510 QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
Steve Naroff09b266e2007-10-30 23:14:51 +00001511 &ArgTys[0], ArgTys.size(),
1512 true /*isVariadic*/);
1513 MsgSendFunctionDecl = new FunctionDecl(SourceLocation(),
1514 msgSendIdent, msgSendType,
1515 FunctionDecl::Extern, false, 0);
1516}
1517
Steve Naroff874e2322007-11-15 10:28:18 +00001518// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...);
1519void RewriteTest::SynthMsgSendSuperFunctionDecl() {
1520 IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper");
1521 llvm::SmallVector<QualType, 16> ArgTys;
1522 RecordDecl *RD = new RecordDecl(Decl::Struct, SourceLocation(),
1523 &Context->Idents.get("objc_super"), 0);
1524 QualType argT = Context->getPointerType(Context->getTagDeclType(RD));
1525 assert(!argT.isNull() && "Can't build 'struct objc_super *' type");
1526 ArgTys.push_back(argT);
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001527 argT = Context->getObjCSelType();
Steve Naroff874e2322007-11-15 10:28:18 +00001528 assert(!argT.isNull() && "Can't find 'SEL' type");
1529 ArgTys.push_back(argT);
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001530 QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
Steve Naroff874e2322007-11-15 10:28:18 +00001531 &ArgTys[0], ArgTys.size(),
1532 true /*isVariadic*/);
1533 MsgSendSuperFunctionDecl = new FunctionDecl(SourceLocation(),
1534 msgSendIdent, msgSendType,
1535 FunctionDecl::Extern, false, 0);
1536}
1537
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +00001538// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...);
1539void RewriteTest::SynthMsgSendStretFunctionDecl() {
1540 IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_stret");
1541 llvm::SmallVector<QualType, 16> ArgTys;
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001542 QualType argT = Context->getObjCIdType();
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +00001543 assert(!argT.isNull() && "Can't find 'id' type");
1544 ArgTys.push_back(argT);
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001545 argT = Context->getObjCSelType();
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +00001546 assert(!argT.isNull() && "Can't find 'SEL' type");
1547 ArgTys.push_back(argT);
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001548 QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +00001549 &ArgTys[0], ArgTys.size(),
1550 true /*isVariadic*/);
1551 MsgSendStretFunctionDecl = new FunctionDecl(SourceLocation(),
1552 msgSendIdent, msgSendType,
1553 FunctionDecl::Extern, false, 0);
1554}
1555
1556// SynthMsgSendSuperStretFunctionDecl -
1557// id objc_msgSendSuper_stret(struct objc_super *, SEL op, ...);
1558void RewriteTest::SynthMsgSendSuperStretFunctionDecl() {
1559 IdentifierInfo *msgSendIdent =
1560 &Context->Idents.get("objc_msgSendSuper_stret");
1561 llvm::SmallVector<QualType, 16> ArgTys;
1562 RecordDecl *RD = new RecordDecl(Decl::Struct, SourceLocation(),
1563 &Context->Idents.get("objc_super"), 0);
1564 QualType argT = Context->getPointerType(Context->getTagDeclType(RD));
1565 assert(!argT.isNull() && "Can't build 'struct objc_super *' type");
1566 ArgTys.push_back(argT);
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001567 argT = Context->getObjCSelType();
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +00001568 assert(!argT.isNull() && "Can't find 'SEL' type");
1569 ArgTys.push_back(argT);
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001570 QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +00001571 &ArgTys[0], ArgTys.size(),
1572 true /*isVariadic*/);
1573 MsgSendSuperStretFunctionDecl = new FunctionDecl(SourceLocation(),
1574 msgSendIdent, msgSendType,
1575 FunctionDecl::Extern, false, 0);
1576}
1577
Fariborz Jahanianacb49772007-12-03 21:26:48 +00001578// SynthMsgSendFpretFunctionDecl - id objc_msgSend_fpret(id self, SEL op, ...);
1579void RewriteTest::SynthMsgSendFpretFunctionDecl() {
1580 IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_fpret");
1581 llvm::SmallVector<QualType, 16> ArgTys;
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001582 QualType argT = Context->getObjCIdType();
Fariborz Jahanianacb49772007-12-03 21:26:48 +00001583 assert(!argT.isNull() && "Can't find 'id' type");
1584 ArgTys.push_back(argT);
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001585 argT = Context->getObjCSelType();
Fariborz Jahanianacb49772007-12-03 21:26:48 +00001586 assert(!argT.isNull() && "Can't find 'SEL' type");
1587 ArgTys.push_back(argT);
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001588 QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
Fariborz Jahanianacb49772007-12-03 21:26:48 +00001589 &ArgTys[0], ArgTys.size(),
1590 true /*isVariadic*/);
1591 MsgSendFpretFunctionDecl = new FunctionDecl(SourceLocation(),
1592 msgSendIdent, msgSendType,
1593 FunctionDecl::Extern, false, 0);
1594}
1595
Steve Naroff09b266e2007-10-30 23:14:51 +00001596// SynthGetClassFunctionDecl - id objc_getClass(const char *name);
1597void RewriteTest::SynthGetClassFunctionDecl() {
1598 IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass");
1599 llvm::SmallVector<QualType, 16> ArgTys;
1600 ArgTys.push_back(Context->getPointerType(
1601 Context->CharTy.getQualifiedType(QualType::Const)));
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001602 QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
Steve Naroff09b266e2007-10-30 23:14:51 +00001603 &ArgTys[0], ArgTys.size(),
1604 false /*isVariadic*/);
1605 GetClassFunctionDecl = new FunctionDecl(SourceLocation(),
1606 getClassIdent, getClassType,
1607 FunctionDecl::Extern, false, 0);
1608}
1609
Steve Naroff9bcb5fc2007-12-07 03:50:46 +00001610// SynthGetMetaClassFunctionDecl - id objc_getClass(const char *name);
1611void RewriteTest::SynthGetMetaClassFunctionDecl() {
1612 IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass");
1613 llvm::SmallVector<QualType, 16> ArgTys;
1614 ArgTys.push_back(Context->getPointerType(
1615 Context->CharTy.getQualifiedType(QualType::Const)));
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001616 QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
Steve Naroff9bcb5fc2007-12-07 03:50:46 +00001617 &ArgTys[0], ArgTys.size(),
1618 false /*isVariadic*/);
1619 GetMetaClassFunctionDecl = new FunctionDecl(SourceLocation(),
1620 getClassIdent, getClassType,
1621 FunctionDecl::Extern, false, 0);
1622}
1623
Steve Naroff96984642007-11-08 14:30:50 +00001624// SynthCFStringFunctionDecl - id __builtin___CFStringMakeConstantString(const char *name);
1625void RewriteTest::SynthCFStringFunctionDecl() {
1626 IdentifierInfo *getClassIdent = &Context->Idents.get("__builtin___CFStringMakeConstantString");
1627 llvm::SmallVector<QualType, 16> ArgTys;
1628 ArgTys.push_back(Context->getPointerType(
1629 Context->CharTy.getQualifiedType(QualType::Const)));
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001630 QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
Steve Naroff96984642007-11-08 14:30:50 +00001631 &ArgTys[0], ArgTys.size(),
1632 false /*isVariadic*/);
1633 CFStringFunctionDecl = new FunctionDecl(SourceLocation(),
1634 getClassIdent, getClassType,
1635 FunctionDecl::Extern, false, 0);
1636}
1637
Steve Naroffbeaf2992007-11-03 11:27:19 +00001638Stmt *RewriteTest::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
Steve Naroff96984642007-11-08 14:30:50 +00001639#if 1
1640 // This rewrite is specific to GCC, which has builtin support for CFString.
1641 if (!CFStringFunctionDecl)
1642 SynthCFStringFunctionDecl();
1643 // Create a call to __builtin___CFStringMakeConstantString("cstr").
1644 llvm::SmallVector<Expr*, 8> StrExpr;
1645 StrExpr.push_back(Exp->getString());
1646 CallExpr *call = SynthesizeCallToFunctionDecl(CFStringFunctionDecl,
1647 &StrExpr[0], StrExpr.size());
1648 // cast to NSConstantString *
1649 CastExpr *cast = new CastExpr(Exp->getType(), call, SourceLocation());
Chris Lattnerdcbc5b02008-01-31 19:37:57 +00001650 ReplaceStmt(Exp, cast);
Steve Naroff96984642007-11-08 14:30:50 +00001651 delete Exp;
1652 return cast;
1653#else
Steve Naroffbeaf2992007-11-03 11:27:19 +00001654 assert(ConstantStringClassReference && "Can't find constant string reference");
1655 llvm::SmallVector<Expr*, 4> InitExprs;
1656
1657 // Synthesize "(Class)&_NSConstantStringClassReference"
1658 DeclRefExpr *ClsRef = new DeclRefExpr(ConstantStringClassReference,
1659 ConstantStringClassReference->getType(),
1660 SourceLocation());
1661 QualType expType = Context->getPointerType(ClsRef->getType());
1662 UnaryOperator *Unop = new UnaryOperator(ClsRef, UnaryOperator::AddrOf,
1663 expType, SourceLocation());
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001664 CastExpr *cast = new CastExpr(Context->getObjCClassType(), Unop,
Steve Naroffbeaf2992007-11-03 11:27:19 +00001665 SourceLocation());
1666 InitExprs.push_back(cast); // set the 'isa'.
1667 InitExprs.push_back(Exp->getString()); // set "char *bytes".
1668 unsigned IntSize = static_cast<unsigned>(
1669 Context->getTypeSize(Context->IntTy, Exp->getLocStart()));
1670 llvm::APInt IntVal(IntSize, Exp->getString()->getByteLength());
1671 IntegerLiteral *len = new IntegerLiteral(IntVal, Context->IntTy,
1672 Exp->getLocStart());
1673 InitExprs.push_back(len); // set "int numBytes".
1674
1675 // struct NSConstantString
1676 QualType CFConstantStrType = Context->getCFConstantStringType();
1677 // (struct NSConstantString) { <exprs from above> }
1678 InitListExpr *ILE = new InitListExpr(SourceLocation(),
1679 &InitExprs[0], InitExprs.size(),
1680 SourceLocation());
Steve Naroffe9b12192008-01-14 18:19:28 +00001681 CompoundLiteralExpr *StrRep = new CompoundLiteralExpr(CFConstantStrType, ILE, false);
Steve Naroffbeaf2992007-11-03 11:27:19 +00001682 // struct NSConstantString *
1683 expType = Context->getPointerType(StrRep->getType());
1684 Unop = new UnaryOperator(StrRep, UnaryOperator::AddrOf, expType,
1685 SourceLocation());
Steve Naroff352336b2007-11-05 14:36:37 +00001686 // cast to NSConstantString *
1687 cast = new CastExpr(Exp->getType(), Unop, SourceLocation());
Chris Lattnerdcbc5b02008-01-31 19:37:57 +00001688 ReplaceStmt(Exp, cast);
Steve Naroffbeaf2992007-11-03 11:27:19 +00001689 delete Exp;
Steve Naroff352336b2007-11-05 14:36:37 +00001690 return cast;
Steve Naroff96984642007-11-08 14:30:50 +00001691#endif
Steve Naroffbeaf2992007-11-03 11:27:19 +00001692}
1693
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001694ObjCInterfaceDecl *RewriteTest::isSuperReceiver(Expr *recExpr) {
Steve Naroff9bcb5fc2007-12-07 03:50:46 +00001695 // check if we are sending a message to 'super'
1696 if (CurMethodDecl && CurMethodDecl->isInstance()) {
Steve Naroff874e2322007-11-15 10:28:18 +00001697 if (CastExpr *CE = dyn_cast<CastExpr>(recExpr)) {
1698 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) {
1699 if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
1700 if (!strcmp(PVD->getName(), "self")) {
Fariborz Jahanianc5692492007-12-17 21:03:50 +00001701 // is this id<P1..> type?
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001702 if (CE->getType()->isObjCQualifiedIdType())
Fariborz Jahanianc5692492007-12-17 21:03:50 +00001703 return 0;
Steve Naroff874e2322007-11-15 10:28:18 +00001704 if (const PointerType *PT = CE->getType()->getAsPointerType()) {
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001705 if (ObjCInterfaceType *IT =
1706 dyn_cast<ObjCInterfaceType>(PT->getPointeeType())) {
Steve Naroff874e2322007-11-15 10:28:18 +00001707 if (IT->getDecl() ==
1708 CurMethodDecl->getClassInterface()->getSuperClass())
1709 return IT->getDecl();
1710 }
1711 }
1712 }
1713 }
1714 }
Steve Naroff9bcb5fc2007-12-07 03:50:46 +00001715 }
Steve Naroff874e2322007-11-15 10:28:18 +00001716 }
1717 return 0;
1718}
1719
1720// struct objc_super { struct objc_object *receiver; struct objc_class *super; };
1721QualType RewriteTest::getSuperStructType() {
1722 if (!SuperStructDecl) {
1723 SuperStructDecl = new RecordDecl(Decl::Struct, SourceLocation(),
1724 &Context->Idents.get("objc_super"), 0);
1725 QualType FieldTypes[2];
1726
1727 // struct objc_object *receiver;
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001728 FieldTypes[0] = Context->getObjCIdType();
Steve Naroff874e2322007-11-15 10:28:18 +00001729 // struct objc_class *super;
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001730 FieldTypes[1] = Context->getObjCClassType();
Steve Naroff874e2322007-11-15 10:28:18 +00001731 // Create fields
1732 FieldDecl *FieldDecls[2];
1733
1734 for (unsigned i = 0; i < 2; ++i)
1735 FieldDecls[i] = new FieldDecl(SourceLocation(), 0, FieldTypes[i]);
1736
1737 SuperStructDecl->defineBody(FieldDecls, 4);
1738 }
1739 return Context->getTagDeclType(SuperStructDecl);
1740}
1741
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +00001742Stmt *RewriteTest::SynthMessageExpr(ObjCMessageExpr *Exp) {
Fariborz Jahaniana70711b2007-12-04 21:47:40 +00001743 if (!SelGetUidFunctionDecl)
1744 SynthSelGetUidFunctionDecl();
Steve Naroff09b266e2007-10-30 23:14:51 +00001745 if (!MsgSendFunctionDecl)
1746 SynthMsgSendFunctionDecl();
Steve Naroff874e2322007-11-15 10:28:18 +00001747 if (!MsgSendSuperFunctionDecl)
1748 SynthMsgSendSuperFunctionDecl();
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +00001749 if (!MsgSendStretFunctionDecl)
1750 SynthMsgSendStretFunctionDecl();
1751 if (!MsgSendSuperStretFunctionDecl)
1752 SynthMsgSendSuperStretFunctionDecl();
Fariborz Jahanianacb49772007-12-03 21:26:48 +00001753 if (!MsgSendFpretFunctionDecl)
1754 SynthMsgSendFpretFunctionDecl();
Steve Naroff09b266e2007-10-30 23:14:51 +00001755 if (!GetClassFunctionDecl)
1756 SynthGetClassFunctionDecl();
Steve Naroff9bcb5fc2007-12-07 03:50:46 +00001757 if (!GetMetaClassFunctionDecl)
1758 SynthGetMetaClassFunctionDecl();
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +00001759
Steve Naroff874e2322007-11-15 10:28:18 +00001760 // default to objc_msgSend().
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +00001761 FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl;
1762 // May need to use objc_msgSend_stret() as well.
1763 FunctionDecl *MsgSendStretFlavor = 0;
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001764 if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) {
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +00001765 QualType resultType = mDecl->getResultType();
1766 if (resultType.getCanonicalType()->isStructureType()
1767 || resultType.getCanonicalType()->isUnionType())
1768 MsgSendStretFlavor = MsgSendStretFunctionDecl;
Fariborz Jahanianacb49772007-12-03 21:26:48 +00001769 else if (resultType.getCanonicalType()->isRealFloatingType())
1770 MsgSendFlavor = MsgSendFpretFunctionDecl;
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +00001771 }
Steve Naroff874e2322007-11-15 10:28:18 +00001772
Steve Naroff934f2762007-10-24 22:48:43 +00001773 // Synthesize a call to objc_msgSend().
1774 llvm::SmallVector<Expr*, 8> MsgExprs;
1775 IdentifierInfo *clsName = Exp->getClassName();
1776
1777 // Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend().
1778 if (clsName) { // class message.
Steve Naroff9bcb5fc2007-12-07 03:50:46 +00001779 if (!strcmp(clsName->getName(), "super")) {
1780 MsgSendFlavor = MsgSendSuperFunctionDecl;
1781 if (MsgSendStretFlavor)
1782 MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
1783 assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
1784
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001785 ObjCInterfaceDecl *SuperDecl =
Steve Naroff9bcb5fc2007-12-07 03:50:46 +00001786 CurMethodDecl->getClassInterface()->getSuperClass();
1787
1788 llvm::SmallVector<Expr*, 4> InitExprs;
1789
1790 // set the receiver to self, the first argument to all methods.
1791 InitExprs.push_back(new DeclRefExpr(CurMethodDecl->getSelfDecl(),
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001792 Context->getObjCIdType(),
Steve Naroff9bcb5fc2007-12-07 03:50:46 +00001793 SourceLocation()));
1794 llvm::SmallVector<Expr*, 8> ClsExprs;
1795 QualType argType = Context->getPointerType(Context->CharTy);
1796 ClsExprs.push_back(new StringLiteral(SuperDecl->getIdentifier()->getName(),
1797 SuperDecl->getIdentifier()->getLength(),
1798 false, argType, SourceLocation(),
1799 SourceLocation()));
1800 CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
1801 &ClsExprs[0],
1802 ClsExprs.size());
1803 // To turn off a warning, type-cast to 'id'
1804 InitExprs.push_back(
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001805 new CastExpr(Context->getObjCIdType(),
Steve Naroff9bcb5fc2007-12-07 03:50:46 +00001806 Cls, SourceLocation())); // set 'super class', using objc_getClass().
1807 // struct objc_super
1808 QualType superType = getSuperStructType();
1809 // (struct objc_super) { <exprs from above> }
1810 InitListExpr *ILE = new InitListExpr(SourceLocation(),
1811 &InitExprs[0], InitExprs.size(),
1812 SourceLocation());
Chris Lattner0fc53df2008-01-02 21:46:24 +00001813 CompoundLiteralExpr *SuperRep = new CompoundLiteralExpr(SourceLocation(),
Steve Naroffe9b12192008-01-14 18:19:28 +00001814 superType, ILE, false);
Steve Naroff9bcb5fc2007-12-07 03:50:46 +00001815 // struct objc_super *
1816 Expr *Unop = new UnaryOperator(SuperRep, UnaryOperator::AddrOf,
1817 Context->getPointerType(SuperRep->getType()),
1818 SourceLocation());
1819 MsgExprs.push_back(Unop);
1820 } else {
1821 llvm::SmallVector<Expr*, 8> ClsExprs;
1822 QualType argType = Context->getPointerType(Context->CharTy);
1823 ClsExprs.push_back(new StringLiteral(clsName->getName(),
1824 clsName->getLength(),
1825 false, argType, SourceLocation(),
1826 SourceLocation()));
1827 CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
1828 &ClsExprs[0],
1829 ClsExprs.size());
1830 MsgExprs.push_back(Cls);
1831 }
Steve Naroff6568d4d2007-11-14 23:54:14 +00001832 } else { // instance message.
1833 Expr *recExpr = Exp->getReceiver();
Steve Naroff874e2322007-11-15 10:28:18 +00001834
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001835 if (ObjCInterfaceDecl *SuperDecl = isSuperReceiver(recExpr)) {
Steve Naroff874e2322007-11-15 10:28:18 +00001836 MsgSendFlavor = MsgSendSuperFunctionDecl;
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +00001837 if (MsgSendStretFlavor)
1838 MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
Steve Naroff874e2322007-11-15 10:28:18 +00001839 assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
1840
1841 llvm::SmallVector<Expr*, 4> InitExprs;
1842
Fariborz Jahanianceee3e82007-12-04 22:32:58 +00001843 InitExprs.push_back(
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001844 new CastExpr(Context->getObjCIdType(),
Fariborz Jahanianceee3e82007-12-04 22:32:58 +00001845 recExpr, SourceLocation())); // set the 'receiver'.
Steve Naroff874e2322007-11-15 10:28:18 +00001846
1847 llvm::SmallVector<Expr*, 8> ClsExprs;
1848 QualType argType = Context->getPointerType(Context->CharTy);
Steve Naroff9bcb5fc2007-12-07 03:50:46 +00001849 ClsExprs.push_back(new StringLiteral(SuperDecl->getIdentifier()->getName(),
1850 SuperDecl->getIdentifier()->getLength(),
Steve Naroff874e2322007-11-15 10:28:18 +00001851 false, argType, SourceLocation(),
1852 SourceLocation()));
1853 CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
Fariborz Jahanianceee3e82007-12-04 22:32:58 +00001854 &ClsExprs[0],
1855 ClsExprs.size());
Fariborz Jahanian71274312007-12-05 17:29:46 +00001856 // To turn off a warning, type-cast to 'id'
Fariborz Jahanianceee3e82007-12-04 22:32:58 +00001857 InitExprs.push_back(
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001858 new CastExpr(Context->getObjCIdType(),
Fariborz Jahanianceee3e82007-12-04 22:32:58 +00001859 Cls, SourceLocation())); // set 'super class', using objc_getClass().
Steve Naroff874e2322007-11-15 10:28:18 +00001860 // struct objc_super
1861 QualType superType = getSuperStructType();
1862 // (struct objc_super) { <exprs from above> }
1863 InitListExpr *ILE = new InitListExpr(SourceLocation(),
1864 &InitExprs[0], InitExprs.size(),
1865 SourceLocation());
Chris Lattner0fc53df2008-01-02 21:46:24 +00001866 CompoundLiteralExpr *SuperRep = new CompoundLiteralExpr(SourceLocation(),
Steve Naroffe9b12192008-01-14 18:19:28 +00001867 superType, ILE, false);
Steve Naroff874e2322007-11-15 10:28:18 +00001868 // struct objc_super *
1869 Expr *Unop = new UnaryOperator(SuperRep, UnaryOperator::AddrOf,
1870 Context->getPointerType(SuperRep->getType()),
1871 SourceLocation());
1872 MsgExprs.push_back(Unop);
1873 } else {
Fariborz Jahanian7dd82832007-12-07 21:21:21 +00001874 // Remove all type-casts because it may contain objc-style types; e.g.
1875 // Foo<Proto> *.
1876 while (CastExpr *CE = dyn_cast<CastExpr>(recExpr))
1877 recExpr = CE->getSubExpr();
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001878 recExpr = new CastExpr(Context->getObjCIdType(), recExpr, SourceLocation());
Steve Naroff874e2322007-11-15 10:28:18 +00001879 MsgExprs.push_back(recExpr);
1880 }
Steve Naroff6568d4d2007-11-14 23:54:14 +00001881 }
Steve Naroffbeaf2992007-11-03 11:27:19 +00001882 // Create a call to sel_registerName("selName"), it will be the 2nd argument.
Steve Naroff934f2762007-10-24 22:48:43 +00001883 llvm::SmallVector<Expr*, 8> SelExprs;
1884 QualType argType = Context->getPointerType(Context->CharTy);
1885 SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
1886 Exp->getSelector().getName().size(),
1887 false, argType, SourceLocation(),
1888 SourceLocation()));
1889 CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
1890 &SelExprs[0], SelExprs.size());
1891 MsgExprs.push_back(SelExp);
1892
1893 // Now push any user supplied arguments.
1894 for (unsigned i = 0; i < Exp->getNumArgs(); i++) {
Steve Naroff6568d4d2007-11-14 23:54:14 +00001895 Expr *userExpr = Exp->getArg(i);
Steve Naroff7e3411b2007-11-15 02:58:25 +00001896 // Make all implicit casts explicit...ICE comes in handy:-)
1897 if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) {
1898 // Reuse the ICE type, it is exactly what the doctor ordered.
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001899 userExpr = new CastExpr(ICE->getType()->isObjCQualifiedIdType()
1900 ? Context->getObjCIdType()
Fariborz Jahanianc5692492007-12-17 21:03:50 +00001901 : ICE->getType(), userExpr, SourceLocation());
Fariborz Jahaniand58fabf2007-12-18 21:33:44 +00001902 }
1903 // Make id<P...> cast into an 'id' cast.
1904 else if (CastExpr *CE = dyn_cast<CastExpr>(userExpr)) {
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001905 if (CE->getType()->isObjCQualifiedIdType()) {
Fariborz Jahaniand58fabf2007-12-18 21:33:44 +00001906 while ((CE = dyn_cast<CastExpr>(userExpr)))
1907 userExpr = CE->getSubExpr();
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001908 userExpr = new CastExpr(Context->getObjCIdType(),
Fariborz Jahaniand58fabf2007-12-18 21:33:44 +00001909 userExpr, SourceLocation());
1910 }
Steve Naroff7e3411b2007-11-15 02:58:25 +00001911 }
Steve Naroff6568d4d2007-11-14 23:54:14 +00001912 MsgExprs.push_back(userExpr);
Steve Naroff934f2762007-10-24 22:48:43 +00001913 // We've transferred the ownership to MsgExprs. Null out the argument in
1914 // the original expression, since we will delete it below.
1915 Exp->setArg(i, 0);
1916 }
Steve Naroffab972d32007-11-04 22:37:50 +00001917 // Generate the funky cast.
1918 CastExpr *cast;
1919 llvm::SmallVector<QualType, 8> ArgTypes;
1920 QualType returnType;
1921
1922 // Push 'id' and 'SEL', the 2 implicit arguments.
Steve Naroffc3a438c2007-11-15 10:43:57 +00001923 if (MsgSendFlavor == MsgSendSuperFunctionDecl)
1924 ArgTypes.push_back(Context->getPointerType(getSuperStructType()));
1925 else
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001926 ArgTypes.push_back(Context->getObjCIdType());
1927 ArgTypes.push_back(Context->getObjCSelType());
1928 if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) {
Steve Naroffab972d32007-11-04 22:37:50 +00001929 // Push any user argument types.
Steve Naroff352336b2007-11-05 14:36:37 +00001930 for (int i = 0; i < mDecl->getNumParams(); i++) {
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001931 QualType t = mDecl->getParamDecl(i)->getType()->isObjCQualifiedIdType()
1932 ? Context->getObjCIdType()
Fariborz Jahanianc5692492007-12-17 21:03:50 +00001933 : mDecl->getParamDecl(i)->getType();
Steve Naroff352336b2007-11-05 14:36:37 +00001934 ArgTypes.push_back(t);
1935 }
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001936 returnType = mDecl->getResultType()->isObjCQualifiedIdType()
1937 ? Context->getObjCIdType() : mDecl->getResultType();
Steve Naroffab972d32007-11-04 22:37:50 +00001938 } else {
Ted Kremeneka526c5c2008-01-07 19:49:32 +00001939 returnType = Context->getObjCIdType();
Steve Naroffab972d32007-11-04 22:37:50 +00001940 }
1941 // Get the type, we will need to reference it in a couple spots.
Steve Naroff874e2322007-11-15 10:28:18 +00001942 QualType msgSendType = MsgSendFlavor->getType();
Steve Naroffab972d32007-11-04 22:37:50 +00001943
1944 // Create a reference to the objc_msgSend() declaration.
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +00001945 DeclRefExpr *DRE = new DeclRefExpr(MsgSendFlavor, msgSendType,
1946 SourceLocation());
Steve Naroffab972d32007-11-04 22:37:50 +00001947
1948 // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid).
1949 // If we don't do this cast, we get the following bizarre warning/note:
1950 // xx.m:13: warning: function called through a non-compatible type
1951 // xx.m:13: note: if this code is reached, the program will abort
1952 cast = new CastExpr(Context->getPointerType(Context->VoidTy), DRE,
1953 SourceLocation());
Steve Naroff335eafa2007-11-15 12:35:21 +00001954
Steve Naroffab972d32007-11-04 22:37:50 +00001955 // Now do the "normal" pointer to function cast.
1956 QualType castType = Context->getFunctionType(returnType,
Fariborz Jahaniand0ee6f92007-12-06 19:49:56 +00001957 &ArgTypes[0], ArgTypes.size(),
1958 Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false);
Steve Naroffab972d32007-11-04 22:37:50 +00001959 castType = Context->getPointerType(castType);
1960 cast = new CastExpr(castType, cast, SourceLocation());
1961
1962 // Don't forget the parens to enforce the proper binding.
1963 ParenExpr *PE = new ParenExpr(SourceLocation(), SourceLocation(), cast);
1964
1965 const FunctionType *FT = msgSendType->getAsFunctionType();
1966 CallExpr *CE = new CallExpr(PE, &MsgExprs[0], MsgExprs.size(),
1967 FT->getResultType(), SourceLocation());
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +00001968 Stmt *ReplacingStmt = CE;
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +00001969 if (MsgSendStretFlavor) {
1970 // We have the method which returns a struct/union. Must also generate
1971 // call to objc_msgSend_stret and hang both varieties on a conditional
1972 // expression which dictate which one to envoke depending on size of
1973 // method's return type.
1974
1975 // Create a reference to the objc_msgSend_stret() declaration.
1976 DeclRefExpr *STDRE = new DeclRefExpr(MsgSendStretFlavor, msgSendType,
1977 SourceLocation());
1978 // Need to cast objc_msgSend_stret to "void *" (see above comment).
1979 cast = new CastExpr(Context->getPointerType(Context->VoidTy), STDRE,
1980 SourceLocation());
1981 // Now do the "normal" pointer to function cast.
1982 castType = Context->getFunctionType(returnType,
Fariborz Jahaniand0ee6f92007-12-06 19:49:56 +00001983 &ArgTypes[0], ArgTypes.size(),
1984 Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false);
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +00001985 castType = Context->getPointerType(castType);
1986 cast = new CastExpr(castType, cast, SourceLocation());
1987
1988 // Don't forget the parens to enforce the proper binding.
1989 PE = new ParenExpr(SourceLocation(), SourceLocation(), cast);
1990
1991 FT = msgSendType->getAsFunctionType();
1992 CallExpr *STCE = new CallExpr(PE, &MsgExprs[0], MsgExprs.size(),
1993 FT->getResultType(), SourceLocation());
1994
1995 // Build sizeof(returnType)
1996 SizeOfAlignOfTypeExpr *sizeofExpr = new SizeOfAlignOfTypeExpr(true,
1997 returnType, Context->getSizeType(),
1998 SourceLocation(), SourceLocation());
1999 // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
2000 // FIXME: Value of 8 is base on ppc32/x86 ABI for the most common cases.
2001 // For X86 it is more complicated and some kind of target specific routine
2002 // is needed to decide what to do.
2003 unsigned IntSize = static_cast<unsigned>(
2004 Context->getTypeSize(Context->IntTy, SourceLocation()));
2005
2006 IntegerLiteral *limit = new IntegerLiteral(llvm::APInt(IntSize, 8),
2007 Context->IntTy,
2008 SourceLocation());
2009 BinaryOperator *lessThanExpr = new BinaryOperator(sizeofExpr, limit,
2010 BinaryOperator::LE,
2011 Context->IntTy,
2012 SourceLocation());
2013 // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
2014 ConditionalOperator *CondExpr =
2015 new ConditionalOperator(lessThanExpr, CE, STCE, returnType);
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +00002016 ReplacingStmt = new ParenExpr(SourceLocation(), SourceLocation(), CondExpr);
Fariborz Jahanian80a6a5a2007-12-03 19:17:29 +00002017 }
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +00002018 return ReplacingStmt;
2019}
2020
2021Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) {
2022 Stmt *ReplacingStmt = SynthMessageExpr(Exp);
Steve Naroff934f2762007-10-24 22:48:43 +00002023 // Now do the actual rewrite.
Chris Lattnerdcbc5b02008-01-31 19:37:57 +00002024 ReplaceStmt(Exp, ReplacingStmt);
Steve Naroff934f2762007-10-24 22:48:43 +00002025
Chris Lattnere64b7772007-10-24 16:57:36 +00002026 delete Exp;
Fariborz Jahanian33b9c4e2008-01-08 22:06:28 +00002027 return ReplacingStmt;
Steve Naroffebf2b562007-10-23 23:50:29 +00002028}
2029
Fariborz Jahanian36ee2cb2007-12-07 18:47:10 +00002030/// RewriteObjCProtocolExpr - Rewrite a protocol expression into
2031/// call to objc_getProtocol("proto-name").
2032Stmt *RewriteTest::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
2033 if (!GetProtocolFunctionDecl)
2034 SynthGetProtocolFunctionDecl();
2035 // Create a call to objc_getProtocol("ProtocolName").
2036 llvm::SmallVector<Expr*, 8> ProtoExprs;
2037 QualType argType = Context->getPointerType(Context->CharTy);
2038 ProtoExprs.push_back(new StringLiteral(Exp->getProtocol()->getName(),
2039 strlen(Exp->getProtocol()->getName()),
2040 false, argType, SourceLocation(),
2041 SourceLocation()));
2042 CallExpr *ProtoExp = SynthesizeCallToFunctionDecl(GetProtocolFunctionDecl,
2043 &ProtoExprs[0],
2044 ProtoExprs.size());
Chris Lattnerdcbc5b02008-01-31 19:37:57 +00002045 ReplaceStmt(Exp, ProtoExp);
Fariborz Jahanian36ee2cb2007-12-07 18:47:10 +00002046 delete Exp;
2047 return ProtoExp;
2048
2049}
2050
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002051/// SynthesizeObjCInternalStruct - Rewrite one internal struct corresponding to
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00002052/// an objective-c class with ivars.
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002053void RewriteTest::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00002054 std::string &Result) {
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002055 assert(CDecl && "Class missing in SynthesizeObjCInternalStruct");
2056 assert(CDecl->getName() && "Name missing in SynthesizeObjCInternalStruct");
Fariborz Jahanian212b7682007-10-31 23:08:24 +00002057 // Do not synthesize more than once.
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002058 if (ObjCSynthesizedStructs.count(CDecl))
Fariborz Jahanian212b7682007-10-31 23:08:24 +00002059 return;
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002060 ObjCInterfaceDecl *RCDecl = CDecl->getSuperClass();
Steve Naroff03300712007-11-12 13:56:41 +00002061 int NumIvars = CDecl->getNumInstanceVariables();
Steve Narofffea763e82007-11-14 19:25:57 +00002062 SourceLocation LocStart = CDecl->getLocStart();
2063 SourceLocation LocEnd = CDecl->getLocEnd();
2064
2065 const char *startBuf = SM->getCharacterData(LocStart);
2066 const char *endBuf = SM->getCharacterData(LocEnd);
Fariborz Jahanian2c7038b2007-11-26 19:52:57 +00002067 // If no ivars and no root or if its root, directly or indirectly,
2068 // have no ivars (thus not synthesized) then no need to synthesize this class.
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002069 if (NumIvars <= 0 && (!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) {
Fariborz Jahanian2c7038b2007-11-26 19:52:57 +00002070 endBuf += Lexer::MeasureTokenLength(LocEnd, *SM);
2071 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
2072 Result.c_str(), Result.size());
2073 return;
2074 }
2075
2076 // FIXME: This has potential of causing problem. If
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002077 // SynthesizeObjCInternalStruct is ever called recursively.
Fariborz Jahanian2c7038b2007-11-26 19:52:57 +00002078 Result += "\nstruct ";
2079 Result += CDecl->getName();
Steve Narofffea763e82007-11-14 19:25:57 +00002080
Fariborz Jahanianfdc08a02007-10-31 17:29:28 +00002081 if (NumIvars > 0) {
Steve Narofffea763e82007-11-14 19:25:57 +00002082 const char *cursor = strchr(startBuf, '{');
2083 assert((cursor && endBuf)
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002084 && "SynthesizeObjCInternalStruct - malformed @interface");
Steve Narofffea763e82007-11-14 19:25:57 +00002085
2086 // rewrite the original header *without* disturbing the '{'
2087 Rewrite.ReplaceText(LocStart, cursor-startBuf-1,
2088 Result.c_str(), Result.size());
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002089 if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) {
Steve Narofffea763e82007-11-14 19:25:57 +00002090 Result = "\n struct ";
2091 Result += RCDecl->getName();
Steve Narofff69cc5d2008-01-30 19:17:43 +00002092 // Note: We don't name the field decl. This simplifies the "codegen" for
2093 // accessing a superclasses instance variables (and is similar to what gcc
2094 // does internally). The unnamed struct field feature is enabled with
2095 // -fms-extensions. If the struct definition were "inlined", we wouldn't
2096 // need to use this switch. That said, I don't want to inline the def.
Steve Narofffea763e82007-11-14 19:25:57 +00002097 Result += ";\n";
2098
2099 // insert the super class structure definition.
2100 SourceLocation OnePastCurly = LocStart.getFileLocWithOffset(cursor-startBuf+1);
2101 Rewrite.InsertText(OnePastCurly, Result.c_str(), Result.size());
2102 }
2103 cursor++; // past '{'
2104
2105 // Now comment out any visibility specifiers.
2106 while (cursor < endBuf) {
2107 if (*cursor == '@') {
2108 SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
Chris Lattnerdf6a51b2007-11-14 22:57:51 +00002109 // Skip whitespace.
2110 for (++cursor; cursor[0] == ' ' || cursor[0] == '\t'; ++cursor)
2111 /*scan*/;
2112
Fariborz Jahanianfdc08a02007-10-31 17:29:28 +00002113 // FIXME: presence of @public, etc. inside comment results in
2114 // this transformation as well, which is still correct c-code.
Steve Narofffea763e82007-11-14 19:25:57 +00002115 if (!strncmp(cursor, "public", strlen("public")) ||
2116 !strncmp(cursor, "private", strlen("private")) ||
Fariborz Jahanian95673922007-11-14 22:26:25 +00002117 !strncmp(cursor, "protected", strlen("protected")))
Steve Narofffea763e82007-11-14 19:25:57 +00002118 Rewrite.InsertText(atLoc, "// ", 3);
Fariborz Jahanianfdc08a02007-10-31 17:29:28 +00002119 }
Fariborz Jahanian95673922007-11-14 22:26:25 +00002120 // FIXME: If there are cases where '<' is used in ivar declaration part
2121 // of user code, then scan the ivar list and use needToScanForQualifiers
2122 // for type checking.
2123 else if (*cursor == '<') {
2124 SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
2125 Rewrite.InsertText(atLoc, "/* ", 3);
2126 cursor = strchr(cursor, '>');
2127 cursor++;
2128 atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
2129 Rewrite.InsertText(atLoc, " */", 3);
2130 }
Steve Narofffea763e82007-11-14 19:25:57 +00002131 cursor++;
Fariborz Jahanianfdc08a02007-10-31 17:29:28 +00002132 }
Steve Narofffea763e82007-11-14 19:25:57 +00002133 // Don't forget to add a ';'!!
2134 Rewrite.InsertText(LocEnd.getFileLocWithOffset(1), ";", 1);
2135 } else { // we don't have any instance variables - insert super struct.
2136 endBuf += Lexer::MeasureTokenLength(LocEnd, *SM);
2137 Result += " {\n struct ";
2138 Result += RCDecl->getName();
Steve Narofff69cc5d2008-01-30 19:17:43 +00002139 // Note: We don't name the field decl. This simplifies the "codegen" for
2140 // accessing a superclasses instance variables (and is similar to what gcc
2141 // does internally). The unnamed struct field feature is enabled with
2142 // -fms-extensions. If the struct definition were "inlined", we wouldn't
2143 // need to use this switch. That said, I don't want to inline the def.
Steve Narofffea763e82007-11-14 19:25:57 +00002144 Result += ";\n};\n";
2145 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
2146 Result.c_str(), Result.size());
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00002147 }
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00002148 // Mark this struct as having been generated.
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002149 if (!ObjCSynthesizedStructs.insert(CDecl))
2150 assert(false && "struct already synthesize- SynthesizeObjCInternalStruct");
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00002151}
2152
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002153// RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002154/// class methods.
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002155void RewriteTest::RewriteObjCMethodsMetaData(instmeth_iterator MethodBegin,
Chris Lattnerab4c4d52007-12-12 07:46:12 +00002156 instmeth_iterator MethodEnd,
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +00002157 bool IsInstanceMethod,
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002158 const char *prefix,
Chris Lattner158ecb92007-10-25 17:07:24 +00002159 const char *ClassName,
2160 std::string &Result) {
Chris Lattnerab4c4d52007-12-12 07:46:12 +00002161 if (MethodBegin == MethodEnd) return;
2162
Fariborz Jahaniane887c092007-10-22 21:41:37 +00002163 static bool objc_impl_method = false;
Chris Lattnerab4c4d52007-12-12 07:46:12 +00002164 if (!objc_impl_method) {
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002165 /* struct _objc_method {
Fariborz Jahaniane887c092007-10-22 21:41:37 +00002166 SEL _cmd;
2167 char *method_types;
2168 void *_imp;
2169 }
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002170 */
Chris Lattner158ecb92007-10-25 17:07:24 +00002171 Result += "\nstruct _objc_method {\n";
2172 Result += "\tSEL _cmd;\n";
2173 Result += "\tchar *method_types;\n";
2174 Result += "\tvoid *_imp;\n";
2175 Result += "};\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002176
2177 /* struct _objc_method_list {
2178 struct _objc_method_list *next_method;
2179 int method_count;
2180 struct _objc_method method_list[];
2181 }
2182 */
2183 Result += "\nstruct _objc_method_list {\n";
2184 Result += "\tstruct _objc_method_list *next_method;\n";
2185 Result += "\tint method_count;\n";
2186 Result += "\tstruct _objc_method method_list[];\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002187 objc_impl_method = true;
Fariborz Jahanian776d6ff2007-10-19 00:36:46 +00002188 }
Chris Lattnerab4c4d52007-12-12 07:46:12 +00002189
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002190 // Build _objc_method_list for class's methods if needed
Chris Lattnerab4c4d52007-12-12 07:46:12 +00002191 Result += "\nstatic struct _objc_method_list _OBJC_";
2192 Result += prefix;
2193 Result += IsInstanceMethod ? "INSTANCE" : "CLASS";
2194 Result += "_METHODS_";
2195 Result += ClassName;
2196 Result += " __attribute__ ((section (\"__OBJC, __";
2197 Result += IsInstanceMethod ? "inst" : "cls";
2198 Result += "_meth\")))= ";
2199 Result += "{\n\t0, " + utostr(MethodEnd-MethodBegin) + "\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002200
Chris Lattnerab4c4d52007-12-12 07:46:12 +00002201 Result += "\t,{{(SEL)\"";
2202 Result += (*MethodBegin)->getSelector().getName().c_str();
2203 std::string MethodTypeString;
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002204 Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
Chris Lattnerab4c4d52007-12-12 07:46:12 +00002205 Result += "\", \"";
2206 Result += MethodTypeString;
2207 Result += "\", ";
2208 Result += MethodInternalNames[*MethodBegin];
2209 Result += "}\n";
2210 for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) {
2211 Result += "\t ,{(SEL)\"";
2212 Result += (*MethodBegin)->getSelector().getName().c_str();
Fariborz Jahanian33e1d642007-10-29 22:57:28 +00002213 std::string MethodTypeString;
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002214 Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
Fariborz Jahanian33e1d642007-10-29 22:57:28 +00002215 Result += "\", \"";
2216 Result += MethodTypeString;
Fariborz Jahanianb7908b52007-11-13 21:02:00 +00002217 Result += "\", ";
Chris Lattnerab4c4d52007-12-12 07:46:12 +00002218 Result += MethodInternalNames[*MethodBegin];
Fariborz Jahanianb7908b52007-11-13 21:02:00 +00002219 Result += "}\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00002220 }
Chris Lattnerab4c4d52007-12-12 07:46:12 +00002221 Result += "\t }\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002222}
2223
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002224/// RewriteObjCProtocolsMetaData - Rewrite protocols meta-data.
2225void RewriteTest::RewriteObjCProtocolsMetaData(ObjCProtocolDecl **Protocols,
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002226 int NumProtocols,
2227 const char *prefix,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002228 const char *ClassName,
2229 std::string &Result) {
Fariborz Jahaniane887c092007-10-22 21:41:37 +00002230 static bool objc_protocol_methods = false;
Fariborz Jahaniane887c092007-10-22 21:41:37 +00002231 if (NumProtocols > 0) {
Fariborz Jahaniane887c092007-10-22 21:41:37 +00002232 for (int i = 0; i < NumProtocols; i++) {
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002233 ObjCProtocolDecl *PDecl = Protocols[i];
Fariborz Jahaniane887c092007-10-22 21:41:37 +00002234 // Output struct protocol_methods holder of method selector and type.
2235 if (!objc_protocol_methods &&
2236 (PDecl->getNumInstanceMethods() > 0
2237 || PDecl->getNumClassMethods() > 0)) {
2238 /* struct protocol_methods {
2239 SEL _cmd;
2240 char *method_types;
2241 }
2242 */
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002243 Result += "\nstruct protocol_methods {\n";
2244 Result += "\tSEL _cmd;\n";
2245 Result += "\tchar *method_types;\n";
2246 Result += "};\n";
2247
2248 /* struct _objc_protocol_method_list {
2249 int protocol_method_count;
2250 struct protocol_methods protocols[];
2251 }
2252 */
2253 Result += "\nstruct _objc_protocol_method_list {\n";
2254 Result += "\tint protocol_method_count;\n";
2255 Result += "\tstruct protocol_methods protocols[];\n};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00002256 objc_protocol_methods = true;
2257 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002258
Fariborz Jahanianfc591ac2007-12-17 17:56:10 +00002259 int NumMethods = PDecl->getNumInstanceMethods();
2260 if(NumMethods > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002261 Result += "\nstatic struct _objc_protocol_method_list "
2262 "_OBJC_PROTOCOL_INSTANCE_METHODS_";
2263 Result += PDecl->getName();
2264 Result += " __attribute__ ((section (\"__OBJC, __cat_inst_meth\")))= "
2265 "{\n\t" + utostr(NumMethods) + "\n";
2266
Fariborz Jahanianfc591ac2007-12-17 17:56:10 +00002267 // Output instance methods declared in this protocol.
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002268 for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(),
Fariborz Jahanianfc591ac2007-12-17 17:56:10 +00002269 E = PDecl->instmeth_end(); I != E; ++I) {
2270 if (I == PDecl->instmeth_begin())
2271 Result += "\t ,{{(SEL)\"";
2272 else
2273 Result += "\t ,{(SEL)\"";
2274 Result += (*I)->getSelector().getName().c_str();
2275 std::string MethodTypeString;
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002276 Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
Fariborz Jahanianfc591ac2007-12-17 17:56:10 +00002277 Result += "\", \"";
2278 Result += MethodTypeString;
2279 Result += "\"}\n";
2280 }
2281 Result += "\t }\n};\n";
2282 }
Fariborz Jahaniane887c092007-10-22 21:41:37 +00002283
2284 // Output class methods declared in this protocol.
2285 NumMethods = PDecl->getNumClassMethods();
2286 if (NumMethods > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002287 Result += "\nstatic struct _objc_protocol_method_list "
2288 "_OBJC_PROTOCOL_CLASS_METHODS_";
2289 Result += PDecl->getName();
2290 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
2291 "{\n\t";
2292 Result += utostr(NumMethods);
2293 Result += "\n";
2294
Fariborz Jahanianc6e2c2a2007-12-17 18:07:01 +00002295 // Output instance methods declared in this protocol.
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002296 for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(),
Fariborz Jahanianc6e2c2a2007-12-17 18:07:01 +00002297 E = PDecl->classmeth_end(); I != E; ++I) {
2298 if (I == PDecl->classmeth_begin())
2299 Result += "\t ,{{(SEL)\"";
2300 else
2301 Result += "\t ,{(SEL)\"";
Steve Naroff58dbdeb2007-12-14 23:37:57 +00002302 Result += (*I)->getSelector().getName().c_str();
Fariborz Jahanian33e1d642007-10-29 22:57:28 +00002303 std::string MethodTypeString;
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002304 Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
Fariborz Jahanian33e1d642007-10-29 22:57:28 +00002305 Result += "\", \"";
2306 Result += MethodTypeString;
2307 Result += "\"}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002308 }
2309 Result += "\t }\n};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00002310 }
2311 // Output:
2312 /* struct _objc_protocol {
2313 // Objective-C 1.0 extensions
2314 struct _objc_protocol_extension *isa;
2315 char *protocol_name;
2316 struct _objc_protocol **protocol_list;
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002317 struct _objc_protocol_method_list *instance_methods;
2318 struct _objc_protocol_method_list *class_methods;
Fariborz Jahaniane887c092007-10-22 21:41:37 +00002319 };
2320 */
2321 static bool objc_protocol = false;
2322 if (!objc_protocol) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002323 Result += "\nstruct _objc_protocol {\n";
2324 Result += "\tstruct _objc_protocol_extension *isa;\n";
2325 Result += "\tchar *protocol_name;\n";
2326 Result += "\tstruct _objc_protocol **protocol_list;\n";
2327 Result += "\tstruct _objc_protocol_method_list *instance_methods;\n";
2328 Result += "\tstruct _objc_protocol_method_list *class_methods;\n";
2329 Result += "};\n";
2330
2331 /* struct _objc_protocol_list {
2332 struct _objc_protocol_list *next;
2333 int protocol_count;
2334 struct _objc_protocol *class_protocols[];
2335 }
2336 */
2337 Result += "\nstruct _objc_protocol_list {\n";
2338 Result += "\tstruct _objc_protocol_list *next;\n";
2339 Result += "\tint protocol_count;\n";
2340 Result += "\tstruct _objc_protocol *class_protocols[];\n";
2341 Result += "};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00002342 objc_protocol = true;
2343 }
2344
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002345 Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_";
2346 Result += PDecl->getName();
2347 Result += " __attribute__ ((section (\"__OBJC, __protocol\")))= "
2348 "{\n\t0, \"";
2349 Result += PDecl->getName();
2350 Result += "\", 0, ";
Steve Naroff58dbdeb2007-12-14 23:37:57 +00002351 if (PDecl->getNumInstanceMethods() > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002352 Result += "&_OBJC_PROTOCOL_INSTANCE_METHODS_";
2353 Result += PDecl->getName();
2354 Result += ", ";
2355 }
Fariborz Jahaniane887c092007-10-22 21:41:37 +00002356 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002357 Result += "0, ";
Steve Naroff58dbdeb2007-12-14 23:37:57 +00002358 if (PDecl->getNumClassMethods() > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002359 Result += "&_OBJC_PROTOCOL_CLASS_METHODS_";
2360 Result += PDecl->getName();
2361 Result += "\n";
2362 }
Fariborz Jahaniane887c092007-10-22 21:41:37 +00002363 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002364 Result += "0\n";
2365 Result += "};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00002366 }
Fariborz Jahaniane887c092007-10-22 21:41:37 +00002367 // Output the top lovel protocol meta-data for the class.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002368 Result += "\nstatic struct _objc_protocol_list _OBJC_";
2369 Result += prefix;
2370 Result += "_PROTOCOLS_";
2371 Result += ClassName;
2372 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
2373 "{\n\t0, ";
2374 Result += utostr(NumProtocols);
2375 Result += "\n";
2376
2377 Result += "\t,{&_OBJC_PROTOCOL_";
2378 Result += Protocols[0]->getName();
2379 Result += " \n";
2380
2381 for (int i = 1; i < NumProtocols; i++) {
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002382 ObjCProtocolDecl *PDecl = Protocols[i];
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002383 Result += "\t ,&_OBJC_PROTOCOL_";
2384 Result += PDecl->getName();
2385 Result += "\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00002386 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002387 Result += "\t }\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002388 }
2389}
2390
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002391/// RewriteObjCCategoryImplDecl - Rewrite metadata for each category
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002392/// implementation.
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002393void RewriteTest::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002394 std::string &Result) {
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002395 ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface();
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002396 // Find category declaration for this implementation.
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002397 ObjCCategoryDecl *CDecl;
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002398 for (CDecl = ClassDecl->getCategoryList(); CDecl;
2399 CDecl = CDecl->getNextClassCategory())
2400 if (CDecl->getIdentifier() == IDecl->getIdentifier())
2401 break;
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002402
Chris Lattnereb44eee2007-12-23 01:40:15 +00002403 std::string FullCategoryName = ClassDecl->getName();
2404 FullCategoryName += '_';
2405 FullCategoryName += IDecl->getName();
2406
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002407 // Build _objc_method_list for class's instance methods if needed
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002408 RewriteObjCMethodsMetaData(IDecl->instmeth_begin(), IDecl->instmeth_end(),
Chris Lattnereb44eee2007-12-23 01:40:15 +00002409 true, "CATEGORY_", FullCategoryName.c_str(),
2410 Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002411
2412 // Build _objc_method_list for class's class methods if needed
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002413 RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
Chris Lattnereb44eee2007-12-23 01:40:15 +00002414 false, "CATEGORY_", FullCategoryName.c_str(),
2415 Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002416
2417 // Protocols referenced in class declaration?
Fariborz Jahanianbac97d42007-11-13 22:09:49 +00002418 // Null CDecl is case of a category implementation with no category interface
2419 if (CDecl)
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002420 RewriteObjCProtocolsMetaData(CDecl->getReferencedProtocols(),
Fariborz Jahanianbac97d42007-11-13 22:09:49 +00002421 CDecl->getNumReferencedProtocols(),
2422 "CATEGORY",
Chris Lattnereb44eee2007-12-23 01:40:15 +00002423 FullCategoryName.c_str(), Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002424
2425 /* struct _objc_category {
2426 char *category_name;
2427 char *class_name;
2428 struct _objc_method_list *instance_methods;
2429 struct _objc_method_list *class_methods;
2430 struct _objc_protocol_list *protocols;
2431 // Objective-C 1.0 extensions
2432 uint32_t size; // sizeof (struct _objc_category)
2433 struct _objc_property_list *instance_properties; // category's own
2434 // @property decl.
2435 };
2436 */
2437
2438 static bool objc_category = false;
2439 if (!objc_category) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002440 Result += "\nstruct _objc_category {\n";
2441 Result += "\tchar *category_name;\n";
2442 Result += "\tchar *class_name;\n";
2443 Result += "\tstruct _objc_method_list *instance_methods;\n";
2444 Result += "\tstruct _objc_method_list *class_methods;\n";
2445 Result += "\tstruct _objc_protocol_list *protocols;\n";
2446 Result += "\tunsigned int size;\n";
2447 Result += "\tstruct _objc_property_list *instance_properties;\n";
2448 Result += "};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002449 objc_category = true;
Fariborz Jahaniane887c092007-10-22 21:41:37 +00002450 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002451 Result += "\nstatic struct _objc_category _OBJC_CATEGORY_";
2452 Result += FullCategoryName;
2453 Result += " __attribute__ ((section (\"__OBJC, __category\")))= {\n\t\"";
2454 Result += IDecl->getName();
2455 Result += "\"\n\t, \"";
2456 Result += ClassDecl->getName();
2457 Result += "\"\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002458
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002459 if (IDecl->getNumInstanceMethods() > 0) {
2460 Result += "\t, (struct _objc_method_list *)"
2461 "&_OBJC_CATEGORY_INSTANCE_METHODS_";
2462 Result += FullCategoryName;
2463 Result += "\n";
2464 }
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002465 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002466 Result += "\t, 0\n";
2467 if (IDecl->getNumClassMethods() > 0) {
2468 Result += "\t, (struct _objc_method_list *)"
2469 "&_OBJC_CATEGORY_CLASS_METHODS_";
2470 Result += FullCategoryName;
2471 Result += "\n";
2472 }
2473 else
2474 Result += "\t, 0\n";
2475
Fariborz Jahanianbac97d42007-11-13 22:09:49 +00002476 if (CDecl && CDecl->getNumReferencedProtocols() > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002477 Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";
2478 Result += FullCategoryName;
2479 Result += "\n";
2480 }
2481 else
2482 Result += "\t, 0\n";
2483 Result += "\t, sizeof(struct _objc_category), 0\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002484}
2485
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00002486/// SynthesizeIvarOffsetComputation - This rutine synthesizes computation of
2487/// ivar offset.
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002488void RewriteTest::SynthesizeIvarOffsetComputation(ObjCImplementationDecl *IDecl,
2489 ObjCIvarDecl *ivar,
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00002490 std::string &Result) {
Fariborz Jahanian909f02a2007-11-05 17:47:33 +00002491 Result += "offsetof(struct ";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00002492 Result += IDecl->getName();
2493 Result += ", ";
2494 Result += ivar->getName();
2495 Result += ")";
2496}
2497
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002498//===----------------------------------------------------------------------===//
2499// Meta Data Emission
2500//===----------------------------------------------------------------------===//
2501
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002502void RewriteTest::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002503 std::string &Result) {
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002504 ObjCInterfaceDecl *CDecl = IDecl->getClassInterface();
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002505
Fariborz Jahanianebe668f2007-11-26 20:59:57 +00002506 // Explictly declared @interface's are already synthesized.
2507 if (CDecl->ImplicitInterfaceDecl()) {
2508 // FIXME: Implementation of a class with no @interface (legacy) doese not
2509 // produce correct synthesis as yet.
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002510 SynthesizeObjCInternalStruct(CDecl, Result);
Fariborz Jahanianebe668f2007-11-26 20:59:57 +00002511 }
Fariborz Jahanian4d733d32007-10-26 23:09:28 +00002512
Chris Lattnerbe6df082007-12-12 07:56:42 +00002513 // Build _objc_ivar_list metadata for classes ivars if needed
2514 int NumIvars = IDecl->getImplDeclNumIvars() > 0
2515 ? IDecl->getImplDeclNumIvars()
2516 : (CDecl ? CDecl->getNumInstanceVariables() : 0);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002517 if (NumIvars > 0) {
2518 static bool objc_ivar = false;
2519 if (!objc_ivar) {
2520 /* struct _objc_ivar {
2521 char *ivar_name;
2522 char *ivar_type;
2523 int ivar_offset;
2524 };
2525 */
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002526 Result += "\nstruct _objc_ivar {\n";
2527 Result += "\tchar *ivar_name;\n";
2528 Result += "\tchar *ivar_type;\n";
2529 Result += "\tint ivar_offset;\n";
2530 Result += "};\n";
2531
2532 /* struct _objc_ivar_list {
2533 int ivar_count;
2534 struct _objc_ivar ivar_list[];
2535 };
2536 */
2537 Result += "\nstruct _objc_ivar_list {\n";
2538 Result += "\tint ivar_count;\n";
2539 Result += "\tstruct _objc_ivar ivar_list[];\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002540 objc_ivar = true;
2541 }
2542
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002543 Result += "\nstatic struct _objc_ivar_list _OBJC_INSTANCE_VARIABLES_";
2544 Result += IDecl->getName();
2545 Result += " __attribute__ ((section (\"__OBJC, __instance_vars\")))= "
2546 "{\n\t";
2547 Result += utostr(NumIvars);
2548 Result += "\n";
Chris Lattnerbe6df082007-12-12 07:56:42 +00002549
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002550 ObjCInterfaceDecl::ivar_iterator IVI, IVE;
Chris Lattnerbe6df082007-12-12 07:56:42 +00002551 if (IDecl->getImplDeclNumIvars() > 0) {
2552 IVI = IDecl->ivar_begin();
2553 IVE = IDecl->ivar_end();
2554 } else {
2555 IVI = CDecl->ivar_begin();
2556 IVE = CDecl->ivar_end();
2557 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002558 Result += "\t,{{\"";
Chris Lattnerbe6df082007-12-12 07:56:42 +00002559 Result += (*IVI)->getName();
Fariborz Jahanian160eb652007-10-29 17:16:25 +00002560 Result += "\", \"";
2561 std::string StrEncoding;
Fariborz Jahanian7d6b46d2008-01-22 22:44:46 +00002562 Context->getObjCEncodingForType((*IVI)->getType(), StrEncoding,
2563 EncodingRecordTypes);
Fariborz Jahanian160eb652007-10-29 17:16:25 +00002564 Result += StrEncoding;
2565 Result += "\", ";
Chris Lattnerbe6df082007-12-12 07:56:42 +00002566 SynthesizeIvarOffsetComputation(IDecl, *IVI, Result);
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00002567 Result += "}\n";
Chris Lattnerbe6df082007-12-12 07:56:42 +00002568 for (++IVI; IVI != IVE; ++IVI) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002569 Result += "\t ,{\"";
Chris Lattnerbe6df082007-12-12 07:56:42 +00002570 Result += (*IVI)->getName();
Fariborz Jahanian160eb652007-10-29 17:16:25 +00002571 Result += "\", \"";
2572 std::string StrEncoding;
Fariborz Jahanian7d6b46d2008-01-22 22:44:46 +00002573 Context->getObjCEncodingForType((*IVI)->getType(), StrEncoding,
2574 EncodingRecordTypes);
Fariborz Jahanian160eb652007-10-29 17:16:25 +00002575 Result += StrEncoding;
2576 Result += "\", ";
Chris Lattnerbe6df082007-12-12 07:56:42 +00002577 SynthesizeIvarOffsetComputation(IDecl, (*IVI), Result);
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00002578 Result += "}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002579 }
2580
2581 Result += "\t }\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002582 }
2583
2584 // Build _objc_method_list for class's instance methods if needed
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002585 RewriteObjCMethodsMetaData(IDecl->instmeth_begin(), IDecl->instmeth_end(),
Chris Lattnerab4c4d52007-12-12 07:46:12 +00002586 true, "", IDecl->getName(), Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002587
2588 // Build _objc_method_list for class's class methods if needed
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002589 RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
Chris Lattnerab4c4d52007-12-12 07:46:12 +00002590 false, "", IDecl->getName(), Result);
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002591
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002592 // Protocols referenced in class declaration?
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002593 RewriteObjCProtocolsMetaData(CDecl->getReferencedProtocols(),
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002594 CDecl->getNumIntfRefProtocols(),
Chris Lattnerab4c4d52007-12-12 07:46:12 +00002595 "CLASS", CDecl->getName(), Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002596
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00002597
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00002598 // Declaration of class/meta-class metadata
2599 /* struct _objc_class {
2600 struct _objc_class *isa; // or const char *root_class_name when metadata
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00002601 const char *super_class_name;
2602 char *name;
2603 long version;
2604 long info;
2605 long instance_size;
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00002606 struct _objc_ivar_list *ivars;
2607 struct _objc_method_list *methods;
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00002608 struct objc_cache *cache;
2609 struct objc_protocol_list *protocols;
2610 const char *ivar_layout;
2611 struct _objc_class_ext *ext;
2612 };
2613 */
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00002614 static bool objc_class = false;
2615 if (!objc_class) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002616 Result += "\nstruct _objc_class {\n";
2617 Result += "\tstruct _objc_class *isa;\n";
2618 Result += "\tconst char *super_class_name;\n";
2619 Result += "\tchar *name;\n";
2620 Result += "\tlong version;\n";
2621 Result += "\tlong info;\n";
2622 Result += "\tlong instance_size;\n";
2623 Result += "\tstruct _objc_ivar_list *ivars;\n";
2624 Result += "\tstruct _objc_method_list *methods;\n";
2625 Result += "\tstruct objc_cache *cache;\n";
2626 Result += "\tstruct _objc_protocol_list *protocols;\n";
2627 Result += "\tconst char *ivar_layout;\n";
2628 Result += "\tstruct _objc_class_ext *ext;\n";
2629 Result += "};\n";
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00002630 objc_class = true;
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00002631 }
2632
2633 // Meta-class metadata generation.
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002634 ObjCInterfaceDecl *RootClass = 0;
2635 ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass();
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00002636 while (SuperClass) {
2637 RootClass = SuperClass;
2638 SuperClass = SuperClass->getSuperClass();
2639 }
2640 SuperClass = CDecl->getSuperClass();
2641
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002642 Result += "\nstatic struct _objc_class _OBJC_METACLASS_";
2643 Result += CDecl->getName();
2644 Result += " __attribute__ ((section (\"__OBJC, __meta_class\")))= "
2645 "{\n\t(struct _objc_class *)\"";
2646 Result += (RootClass ? RootClass->getName() : CDecl->getName());
2647 Result += "\"";
2648
2649 if (SuperClass) {
2650 Result += ", \"";
2651 Result += SuperClass->getName();
2652 Result += "\", \"";
2653 Result += CDecl->getName();
2654 Result += "\"";
2655 }
2656 else {
2657 Result += ", 0, \"";
2658 Result += CDecl->getName();
2659 Result += "\"";
2660 }
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002661 // Set 'ivars' field for root class to 0. ObjC1 runtime does not use it.
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00002662 // 'info' field is initialized to CLS_META(2) for metaclass
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002663 Result += ", 0,2, sizeof(struct _objc_class), 0";
Steve Naroffb26d7132007-12-05 21:49:40 +00002664 if (IDecl->getNumClassMethods() > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002665 Result += "\n\t, &_OBJC_CLASS_METHODS_";
Steve Naroffb26d7132007-12-05 21:49:40 +00002666 Result += IDecl->getName();
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002667 Result += "\n";
2668 }
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00002669 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002670 Result += ", 0\n";
2671 if (CDecl->getNumIntfRefProtocols() > 0) {
2672 Result += "\t,0, &_OBJC_CLASS_PROTOCOLS_";
2673 Result += CDecl->getName();
2674 Result += ",0,0\n";
2675 }
Fariborz Jahanian454cb012007-10-24 20:54:23 +00002676 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002677 Result += "\t,0,0,0,0\n";
2678 Result += "};\n";
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00002679
2680 // class metadata generation.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002681 Result += "\nstatic struct _objc_class _OBJC_CLASS_";
2682 Result += CDecl->getName();
2683 Result += " __attribute__ ((section (\"__OBJC, __class\")))= "
2684 "{\n\t&_OBJC_METACLASS_";
2685 Result += CDecl->getName();
2686 if (SuperClass) {
2687 Result += ", \"";
2688 Result += SuperClass->getName();
2689 Result += "\", \"";
2690 Result += CDecl->getName();
2691 Result += "\"";
2692 }
2693 else {
2694 Result += ", 0, \"";
2695 Result += CDecl->getName();
2696 Result += "\"";
2697 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00002698 // 'info' field is initialized to CLS_CLASS(1) for class
Fariborz Jahanian4d733d32007-10-26 23:09:28 +00002699 Result += ", 0,1";
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002700 if (!ObjCSynthesizedStructs.count(CDecl))
Fariborz Jahanian4d733d32007-10-26 23:09:28 +00002701 Result += ",0";
2702 else {
2703 // class has size. Must synthesize its size.
Fariborz Jahanian909f02a2007-11-05 17:47:33 +00002704 Result += ",sizeof(struct ";
Fariborz Jahanian4d733d32007-10-26 23:09:28 +00002705 Result += CDecl->getName();
2706 Result += ")";
2707 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002708 if (NumIvars > 0) {
2709 Result += ", &_OBJC_INSTANCE_VARIABLES_";
2710 Result += CDecl->getName();
2711 Result += "\n\t";
2712 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00002713 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002714 Result += ",0";
2715 if (IDecl->getNumInstanceMethods() > 0) {
2716 Result += ", &_OBJC_INSTANCE_METHODS_";
2717 Result += CDecl->getName();
2718 Result += ", 0\n\t";
2719 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00002720 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002721 Result += ",0,0";
2722 if (CDecl->getNumIntfRefProtocols() > 0) {
2723 Result += ", &_OBJC_CLASS_PROTOCOLS_";
2724 Result += CDecl->getName();
2725 Result += ", 0,0\n";
2726 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00002727 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002728 Result += ",0,0,0\n";
2729 Result += "};\n";
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00002730}
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00002731
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +00002732/// RewriteImplementations - This routine rewrites all method implementations
2733/// and emits meta-data.
2734
2735void RewriteTest::RewriteImplementations(std::string &Result) {
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00002736 int ClsDefCount = ClassImplementation.size();
2737 int CatDefCount = CategoryImplementation.size();
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +00002738
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00002739 if (ClsDefCount == 0 && CatDefCount == 0)
2740 return;
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +00002741 // Rewrite implemented methods
2742 for (int i = 0; i < ClsDefCount; i++)
2743 RewriteImplementationDecl(ClassImplementation[i]);
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00002744
Fariborz Jahanian66d6b292007-11-13 20:04:28 +00002745 for (int i = 0; i < CatDefCount; i++)
2746 RewriteImplementationDecl(CategoryImplementation[i]);
2747
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00002748 // This is needed for use of offsetof
2749 Result += "#include <stddef.h>\n";
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +00002750
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002751 // For each implemented class, write out all its meta data.
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00002752 for (int i = 0; i < ClsDefCount; i++)
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002753 RewriteObjCClassMetaData(ClassImplementation[i], Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00002754
2755 // For each implemented category, write out all its meta data.
2756 for (int i = 0; i < CatDefCount; i++)
Ted Kremeneka526c5c2008-01-07 19:49:32 +00002757 RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result);
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00002758
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00002759 // Write objc_symtab metadata
2760 /*
2761 struct _objc_symtab
2762 {
2763 long sel_ref_cnt;
2764 SEL *refs;
2765 short cls_def_cnt;
2766 short cat_def_cnt;
2767 void *defs[cls_def_cnt + cat_def_cnt];
2768 };
2769 */
2770
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002771 Result += "\nstruct _objc_symtab {\n";
2772 Result += "\tlong sel_ref_cnt;\n";
2773 Result += "\tSEL *refs;\n";
2774 Result += "\tshort cls_def_cnt;\n";
2775 Result += "\tshort cat_def_cnt;\n";
2776 Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n";
2777 Result += "};\n\n";
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00002778
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002779 Result += "static struct _objc_symtab "
2780 "_OBJC_SYMBOLS __attribute__((section (\"__OBJC, __symbols\")))= {\n";
2781 Result += "\t0, 0, " + utostr(ClsDefCount)
2782 + ", " + utostr(CatDefCount) + "\n";
2783 for (int i = 0; i < ClsDefCount; i++) {
2784 Result += "\t,&_OBJC_CLASS_";
2785 Result += ClassImplementation[i]->getName();
2786 Result += "\n";
2787 }
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00002788
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002789 for (int i = 0; i < CatDefCount; i++) {
2790 Result += "\t,&_OBJC_CATEGORY_";
2791 Result += CategoryImplementation[i]->getClassInterface()->getName();
2792 Result += "_";
2793 Result += CategoryImplementation[i]->getName();
2794 Result += "\n";
2795 }
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00002796
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002797 Result += "};\n\n";
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00002798
2799 // Write objc_module metadata
2800
2801 /*
2802 struct _objc_module {
2803 long version;
2804 long size;
2805 const char *name;
2806 struct _objc_symtab *symtab;
2807 }
2808 */
2809
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002810 Result += "\nstruct _objc_module {\n";
2811 Result += "\tlong version;\n";
2812 Result += "\tlong size;\n";
2813 Result += "\tconst char *name;\n";
2814 Result += "\tstruct _objc_symtab *symtab;\n";
2815 Result += "};\n\n";
2816 Result += "static struct _objc_module "
2817 "_OBJC_MODULES __attribute__ ((section (\"__OBJC, __module_info\")))= {\n";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00002818 Result += "\t" + utostr(OBJC_ABI_VERSION) +
2819 ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00002820 Result += "};\n\n";
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +00002821
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00002822}
Chris Lattner311ff022007-10-16 22:36:42 +00002823