blob: 885da014295634983342b7d75f7d009cd38d8809 [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//
5// This file was developed by Chris Lattner and is distributed under the
6// University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Hacks and fun related to the code rewriter.
11//
12//===----------------------------------------------------------------------===//
13
14#include "ASTConsumers.h"
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 Lattner158ecb92007-10-25 17:07:24 +000020#include "llvm/ADT/StringExtras.h"
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +000021#include "llvm/ADT/SmallPtrSet.h"
Steve Naroff2feac5e2007-10-30 03:43:13 +000022#include "clang/Lex/Lexer.h"
Chris Lattner77cd2a02007-10-11 00:43:27 +000023using namespace clang;
Chris Lattner158ecb92007-10-25 17:07:24 +000024using llvm::utostr;
Chris Lattner77cd2a02007-10-11 00:43:27 +000025
Chris Lattner77cd2a02007-10-11 00:43:27 +000026namespace {
Chris Lattner8a12c272007-10-11 18:38:32 +000027 class RewriteTest : public ASTConsumer {
Chris Lattner2c64b7b2007-10-16 21:07:07 +000028 Rewriter Rewrite;
Chris Lattner01c57482007-10-17 22:35:30 +000029 ASTContext *Context;
Chris Lattner77cd2a02007-10-11 00:43:27 +000030 SourceManager *SM;
Chris Lattner8a12c272007-10-11 18:38:32 +000031 unsigned MainFileID;
Chris Lattner2c64b7b2007-10-16 21:07:07 +000032 SourceLocation LastIncLoc;
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +000033 llvm::SmallVector<ObjcImplementationDecl *, 8> ClassImplementation;
34 llvm::SmallVector<ObjcCategoryImplDecl *, 8> CategoryImplementation;
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +000035 llvm::SmallPtrSet<ObjcInterfaceDecl*, 8> ObjcSynthesizedStructs;
Steve Naroff8749be52007-10-31 22:11:35 +000036 llvm::SmallPtrSet<ObjcInterfaceDecl*, 8> ObjcForwardDecls;
Steve Naroffebf2b562007-10-23 23:50:29 +000037
38 FunctionDecl *MsgSendFunctionDecl;
39 FunctionDecl *GetClassFunctionDecl;
Steve Naroff934f2762007-10-24 22:48:43 +000040 FunctionDecl *SelGetUidFunctionDecl;
Steve Naroff96984642007-11-08 14:30:50 +000041 FunctionDecl *CFStringFunctionDecl;
Steve Naroffebf2b562007-10-23 23:50:29 +000042
Steve Naroffbeaf2992007-11-03 11:27:19 +000043 // ObjC string constant support.
44 FileVarDecl *ConstantStringClassReference;
45 RecordDecl *NSStringRecord;
Steve Naroffab972d32007-11-04 22:37:50 +000046
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +000047 static const int OBJC_ABI_VERSION =7 ;
Chris Lattner77cd2a02007-10-11 00:43:27 +000048 public:
Chris Lattner01c57482007-10-17 22:35:30 +000049 void Initialize(ASTContext &context, unsigned mainFileID) {
50 Context = &context;
51 SM = &Context->SourceMgr;
Chris Lattner8a12c272007-10-11 18:38:32 +000052 MainFileID = mainFileID;
Steve Naroffebf2b562007-10-23 23:50:29 +000053 MsgSendFunctionDecl = 0;
Steve Naroffc0006092007-10-24 01:09:48 +000054 GetClassFunctionDecl = 0;
Steve Naroff934f2762007-10-24 22:48:43 +000055 SelGetUidFunctionDecl = 0;
Steve Naroff96984642007-11-08 14:30:50 +000056 CFStringFunctionDecl = 0;
Steve Naroffbeaf2992007-11-03 11:27:19 +000057 ConstantStringClassReference = 0;
58 NSStringRecord = 0;
Chris Lattner01c57482007-10-17 22:35:30 +000059 Rewrite.setSourceMgr(Context->SourceMgr);
Steve Naroffe3abbf52007-11-05 14:55:35 +000060 // declaring objc_selector outside the parameter list removes a silly
61 // scope related warning...
Steve Naroff21867b12007-11-07 18:43:40 +000062 const char *s = "struct objc_selector; struct objc_class;\n"
Steve Naroffe3abbf52007-11-05 14:55:35 +000063 "extern struct objc_object *objc_msgSend"
Steve Naroffab972d32007-11-04 22:37:50 +000064 "(struct objc_object *, struct objc_selector *, ...);\n"
65 "extern struct objc_object *objc_getClass"
Steve Naroff21867b12007-11-07 18:43:40 +000066 "(const char *);\n"
67 "extern void objc_exception_throw(struct objc_object *);\n"
68 "extern void objc_exception_try_enter(void *);\n"
69 "extern void objc_exception_try_exit(void *);\n"
70 "extern struct objc_object *objc_exception_extract(void *);\n"
71 "extern int objc_exception_match"
72 "(struct objc_class *, struct objc_object *, ...);\n";
73
Steve Naroffab972d32007-11-04 22:37:50 +000074 Rewrite.InsertText(SourceLocation::getFileLoc(mainFileID, 0),
75 s, strlen(s));
Chris Lattner77cd2a02007-10-11 00:43:27 +000076 }
Chris Lattner8a12c272007-10-11 18:38:32 +000077
Chris Lattnerf04da132007-10-24 17:06:59 +000078 // Top Level Driver code.
79 virtual void HandleTopLevelDecl(Decl *D);
Chris Lattner2c64b7b2007-10-16 21:07:07 +000080 void HandleDeclInMainFile(Decl *D);
Chris Lattnerf04da132007-10-24 17:06:59 +000081 ~RewriteTest();
82
83 // Syntactic Rewriting.
Steve Naroffab972d32007-11-04 22:37:50 +000084 void RewritePrologue(SourceLocation Loc);
Chris Lattner2c64b7b2007-10-16 21:07:07 +000085 void RewriteInclude(SourceLocation Loc);
Chris Lattnerf04da132007-10-24 17:06:59 +000086 void RewriteTabs();
87 void RewriteForwardClassDecl(ObjcClassDecl *Dcl);
Steve Naroffbef11852007-10-26 20:53:56 +000088 void RewriteInterfaceDecl(ObjcInterfaceDecl *Dcl);
Steve Naroff423cb562007-10-30 13:30:57 +000089 void RewriteCategoryDecl(ObjcCategoryDecl *Dcl);
Steve Naroff752d6ef2007-10-30 16:42:30 +000090 void RewriteProtocolDecl(ObjcProtocolDecl *Dcl);
Steve Naroff423cb562007-10-30 13:30:57 +000091 void RewriteMethods(int nMethods, ObjcMethodDecl **Methods);
Fariborz Jahanian957cf652007-11-07 00:09:37 +000092 void RewriteProperties(int nProperties, ObjcPropertyDecl **Properties);
Steve Naroff09b266e2007-10-30 23:14:51 +000093 void RewriteFunctionDecl(FunctionDecl *FD);
Steve Naroffd5255f52007-11-01 13:24:47 +000094 void RewriteObjcQualifiedInterfaceTypes(
95 const FunctionTypeProto *proto, FunctionDecl *FD);
96 bool needToScanForQualifiers(QualType T);
Chris Lattner311ff022007-10-16 22:36:42 +000097
Chris Lattnerf04da132007-10-24 17:06:59 +000098 // Expression Rewriting.
Chris Lattnere64b7772007-10-24 16:57:36 +000099 Stmt *RewriteFunctionBody(Stmt *S);
100 Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
Steve Naroffb42f8412007-11-05 14:50:49 +0000101 Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp);
Chris Lattnere64b7772007-10-24 16:57:36 +0000102 Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
Steve Naroffbeaf2992007-11-03 11:27:19 +0000103 Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp);
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000104 Stmt *RewriteObjcTryStmt(ObjcAtTryStmt *S);
105 Stmt *RewriteObjcCatchStmt(ObjcAtCatchStmt *S);
106 Stmt *RewriteObjcFinallyStmt(ObjcAtFinallyStmt *S);
Steve Naroff2bd03922007-11-07 15:32:26 +0000107 Stmt *RewriteObjcThrowStmt(ObjcAtThrowStmt *S);
Steve Naroff934f2762007-10-24 22:48:43 +0000108 CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD,
109 Expr **args, unsigned nargs);
Steve Naroff09b266e2007-10-30 23:14:51 +0000110 void SynthMsgSendFunctionDecl();
111 void SynthGetClassFunctionDecl();
Steve Naroff96984642007-11-08 14:30:50 +0000112 void SynthCFStringFunctionDecl();
113
Chris Lattnerf04da132007-10-24 17:06:59 +0000114 // Metadata emission.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000115 void RewriteObjcClassMetaData(ObjcImplementationDecl *IDecl,
116 std::string &Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000117
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000118 void RewriteObjcCategoryImplDecl(ObjcCategoryImplDecl *CDecl,
119 std::string &Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000120
121 void RewriteObjcMethodsMetaData(ObjcMethodDecl **Methods,
122 int NumMethods,
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +0000123 bool IsInstanceMethod,
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000124 const char *prefix,
Chris Lattner158ecb92007-10-25 17:07:24 +0000125 const char *ClassName,
126 std::string &Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000127
128 void RewriteObjcProtocolsMetaData(ObjcProtocolDecl **Protocols,
129 int NumProtocols,
130 const char *prefix,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000131 const char *ClassName,
132 std::string &Result);
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000133 void SynthesizeObjcInternalStruct(ObjcInterfaceDecl *CDecl,
134 std::string &Result);
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000135 void SynthesizeIvarOffsetComputation(ObjcImplementationDecl *IDecl,
136 ObjcIvarDecl *ivar,
137 std::string &Result);
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000138 void WriteObjcMetaData(std::string &Result);
Chris Lattner77cd2a02007-10-11 00:43:27 +0000139 };
140}
141
Chris Lattner8a12c272007-10-11 18:38:32 +0000142ASTConsumer *clang::CreateCodeRewriterTest() { return new RewriteTest(); }
Chris Lattner77cd2a02007-10-11 00:43:27 +0000143
Chris Lattnerf04da132007-10-24 17:06:59 +0000144//===----------------------------------------------------------------------===//
145// Top Level Driver Code
146//===----------------------------------------------------------------------===//
147
Chris Lattner8a12c272007-10-11 18:38:32 +0000148void RewriteTest::HandleTopLevelDecl(Decl *D) {
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000149 // Two cases: either the decl could be in the main file, or it could be in a
150 // #included file. If the former, rewrite it now. If the later, check to see
151 // if we rewrote the #include/#import.
152 SourceLocation Loc = D->getLocation();
153 Loc = SM->getLogicalLoc(Loc);
154
155 // If this is for a builtin, ignore it.
156 if (Loc.isInvalid()) return;
157
Steve Naroffebf2b562007-10-23 23:50:29 +0000158 // Look for built-in declarations that we need to refer during the rewrite.
159 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Steve Naroff09b266e2007-10-30 23:14:51 +0000160 RewriteFunctionDecl(FD);
Steve Naroffbeaf2992007-11-03 11:27:19 +0000161 } else if (FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
162 // declared in <Foundation/NSString.h>
163 if (strcmp(FVD->getName(), "_NSConstantStringClassReference") == 0) {
164 ConstantStringClassReference = FVD;
165 return;
166 }
Steve Naroffbef11852007-10-26 20:53:56 +0000167 } else if (ObjcInterfaceDecl *MD = dyn_cast<ObjcInterfaceDecl>(D)) {
168 RewriteInterfaceDecl(MD);
Steve Naroff423cb562007-10-30 13:30:57 +0000169 } else if (ObjcCategoryDecl *CD = dyn_cast<ObjcCategoryDecl>(D)) {
170 RewriteCategoryDecl(CD);
Steve Naroff752d6ef2007-10-30 16:42:30 +0000171 } else if (ObjcProtocolDecl *PD = dyn_cast<ObjcProtocolDecl>(D)) {
172 RewriteProtocolDecl(PD);
Steve Naroffebf2b562007-10-23 23:50:29 +0000173 }
Chris Lattnerf04da132007-10-24 17:06:59 +0000174 // If we have a decl in the main file, see if we should rewrite it.
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000175 if (SM->getDecomposedFileLoc(Loc).first == MainFileID)
176 return HandleDeclInMainFile(D);
177
Chris Lattnerf04da132007-10-24 17:06:59 +0000178 // Otherwise, see if there is a #import in the main file that should be
179 // rewritten.
Steve Naroff32174822007-11-09 12:50:28 +0000180 //RewriteInclude(Loc);
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000181}
182
Chris Lattnerf04da132007-10-24 17:06:59 +0000183/// HandleDeclInMainFile - This is called for each top-level decl defined in the
184/// main file of the input.
185void RewriteTest::HandleDeclInMainFile(Decl *D) {
186 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
187 if (Stmt *Body = FD->getBody())
188 FD->setBody(RewriteFunctionBody(Body));
189
190 if (ObjcImplementationDecl *CI = dyn_cast<ObjcImplementationDecl>(D))
191 ClassImplementation.push_back(CI);
192 else if (ObjcCategoryImplDecl *CI = dyn_cast<ObjcCategoryImplDecl>(D))
193 CategoryImplementation.push_back(CI);
194 else if (ObjcClassDecl *CD = dyn_cast<ObjcClassDecl>(D))
195 RewriteForwardClassDecl(CD);
196 // Nothing yet.
197}
198
199RewriteTest::~RewriteTest() {
200 // Get the top-level buffer that this corresponds to.
Chris Lattner74a0c772007-11-08 04:27:23 +0000201
202 // Rewrite tabs if we care.
203 //RewriteTabs();
Chris Lattnerf04da132007-10-24 17:06:59 +0000204
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000205 // Rewrite Objective-c meta data*
206 std::string ResultStr;
207 WriteObjcMetaData(ResultStr);
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000208
Chris Lattnerf04da132007-10-24 17:06:59 +0000209 // Get the buffer corresponding to MainFileID. If we haven't changed it, then
210 // we are done.
211 if (const RewriteBuffer *RewriteBuf =
212 Rewrite.getRewriteBufferFor(MainFileID)) {
Steve Naroffbeaf2992007-11-03 11:27:19 +0000213 //printf("Changed:\n");
Chris Lattnerf04da132007-10-24 17:06:59 +0000214 std::string S(RewriteBuf->begin(), RewriteBuf->end());
215 printf("%s\n", S.c_str());
216 } else {
217 printf("No changes\n");
218 }
Fariborz Jahanian4402d812007-11-07 18:40:28 +0000219 // Emit metadata.
220 printf("%s", ResultStr.c_str());
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000221}
222
Chris Lattnerf04da132007-10-24 17:06:59 +0000223//===----------------------------------------------------------------------===//
224// Syntactic (non-AST) Rewriting Code
225//===----------------------------------------------------------------------===//
226
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000227void RewriteTest::RewriteInclude(SourceLocation Loc) {
228 // Rip up the #include stack to the main file.
229 SourceLocation IncLoc = Loc, NextLoc = Loc;
230 do {
231 IncLoc = Loc;
232 Loc = SM->getLogicalLoc(NextLoc);
233 NextLoc = SM->getIncludeLoc(Loc);
234 } while (!NextLoc.isInvalid());
235
236 // Loc is now the location of the #include filename "foo" or <foo/bar.h>.
237 // IncLoc indicates the header that was included if it is useful.
238 IncLoc = SM->getLogicalLoc(IncLoc);
239 if (SM->getDecomposedFileLoc(Loc).first != MainFileID ||
240 Loc == LastIncLoc)
241 return;
242 LastIncLoc = Loc;
243
244 unsigned IncCol = SM->getColumnNumber(Loc);
245 SourceLocation LineStartLoc = Loc.getFileLocWithOffset(-IncCol+1);
246
247 // Replace the #import with #include.
248 Rewrite.ReplaceText(LineStartLoc, IncCol-1, "#include ", strlen("#include "));
249}
250
Chris Lattnerf04da132007-10-24 17:06:59 +0000251void RewriteTest::RewriteTabs() {
252 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
253 const char *MainBufStart = MainBuf.first;
254 const char *MainBufEnd = MainBuf.second;
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +0000255
Chris Lattnerf04da132007-10-24 17:06:59 +0000256 // Loop over the whole file, looking for tabs.
257 for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) {
258 if (*BufPtr != '\t')
259 continue;
260
261 // Okay, we found a tab. This tab will turn into at least one character,
262 // but it depends on which 'virtual column' it is in. Compute that now.
263 unsigned VCol = 0;
264 while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' &&
265 BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r')
266 ++VCol;
267
268 // Okay, now that we know the virtual column, we know how many spaces to
269 // insert. We assume 8-character tab-stops.
270 unsigned Spaces = 8-(VCol & 7);
271
272 // Get the location of the tab.
273 SourceLocation TabLoc =
274 SourceLocation::getFileLoc(MainFileID, BufPtr-MainBufStart);
275
276 // Rewrite the single tab character into a sequence of spaces.
277 Rewrite.ReplaceText(TabLoc, 1, " ", Spaces);
278 }
Chris Lattner8a12c272007-10-11 18:38:32 +0000279}
280
281
Chris Lattnerf04da132007-10-24 17:06:59 +0000282void RewriteTest::RewriteForwardClassDecl(ObjcClassDecl *ClassDecl) {
283 int numDecls = ClassDecl->getNumForwardDecls();
284 ObjcInterfaceDecl **ForwardDecls = ClassDecl->getForwardDecls();
285
286 // Get the start location and compute the semi location.
287 SourceLocation startLoc = ClassDecl->getLocation();
288 const char *startBuf = SM->getCharacterData(startLoc);
289 const char *semiPtr = strchr(startBuf, ';');
290
291 // Translate to typedef's that forward reference structs with the same name
292 // as the class. As a convenience, we include the original declaration
293 // as a comment.
294 std::string typedefString;
295 typedefString += "// ";
Steve Naroff934f2762007-10-24 22:48:43 +0000296 typedefString.append(startBuf, semiPtr-startBuf+1);
297 typedefString += "\n";
298 for (int i = 0; i < numDecls; i++) {
299 ObjcInterfaceDecl *ForwardDecl = ForwardDecls[i];
Steve Naroff8749be52007-10-31 22:11:35 +0000300 if (ObjcForwardDecls.count(ForwardDecl))
301 continue;
Steve Naroff32174822007-11-09 12:50:28 +0000302 typedefString += "#ifndef _REWRITER_typedef_";
303 typedefString += ForwardDecl->getName();
304 typedefString += "\n";
305 typedefString += "#define _REWRITER_typedef_";
306 typedefString += ForwardDecl->getName();
307 typedefString += "\n";
Steve Naroff352336b2007-11-05 14:36:37 +0000308 typedefString += "typedef struct objc_object ";
Steve Naroff934f2762007-10-24 22:48:43 +0000309 typedefString += ForwardDecl->getName();
Steve Naroff32174822007-11-09 12:50:28 +0000310 typedefString += ";\n#endif\n";
Steve Naroff8749be52007-10-31 22:11:35 +0000311 // Mark this typedef as having been generated.
312 if (!ObjcForwardDecls.insert(ForwardDecl))
Fariborz Jahanianaff56d02007-10-31 22:57:04 +0000313 assert(false && "typedef already output");
Steve Naroff934f2762007-10-24 22:48:43 +0000314 }
315
316 // Replace the @class with typedefs corresponding to the classes.
317 Rewrite.ReplaceText(startLoc, semiPtr-startBuf+1,
318 typedefString.c_str(), typedefString.size());
Chris Lattnerf04da132007-10-24 17:06:59 +0000319}
320
Steve Naroff423cb562007-10-30 13:30:57 +0000321void RewriteTest::RewriteMethods(int nMethods, ObjcMethodDecl **Methods) {
322 for (int i = 0; i < nMethods; i++) {
323 ObjcMethodDecl *Method = Methods[i];
324 SourceLocation Loc = Method->getLocStart();
325
Chris Lattner28d1fe82007-11-08 04:41:51 +0000326 Rewrite.InsertText(Loc, "// ", 3);
Steve Naroff423cb562007-10-30 13:30:57 +0000327
328 // FIXME: handle methods that are declared across multiple lines.
329 }
330}
331
Fariborz Jahanian957cf652007-11-07 00:09:37 +0000332void RewriteTest::RewriteProperties(int nProperties, ObjcPropertyDecl **Properties)
333{
334 for (int i = 0; i < nProperties; i++) {
335 ObjcPropertyDecl *Property = Properties[i];
336 SourceLocation Loc = Property->getLocation();
337
338 Rewrite.ReplaceText(Loc, 0, "// ", 3);
339
340 // FIXME: handle properties that are declared across multiple lines.
341 }
342}
343
Steve Naroff423cb562007-10-30 13:30:57 +0000344void RewriteTest::RewriteCategoryDecl(ObjcCategoryDecl *CatDecl) {
345 SourceLocation LocStart = CatDecl->getLocStart();
346
347 // FIXME: handle category headers that are declared across multiple lines.
348 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
349
350 RewriteMethods(CatDecl->getNumInstanceMethods(),
351 CatDecl->getInstanceMethods());
352 RewriteMethods(CatDecl->getNumClassMethods(),
353 CatDecl->getClassMethods());
354 // Lastly, comment out the @end.
355 Rewrite.ReplaceText(CatDecl->getAtEndLoc(), 0, "// ", 3);
356}
357
Steve Naroff752d6ef2007-10-30 16:42:30 +0000358void RewriteTest::RewriteProtocolDecl(ObjcProtocolDecl *PDecl) {
359 SourceLocation LocStart = PDecl->getLocStart();
360
361 // FIXME: handle protocol headers that are declared across multiple lines.
362 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
363
364 RewriteMethods(PDecl->getNumInstanceMethods(),
365 PDecl->getInstanceMethods());
366 RewriteMethods(PDecl->getNumClassMethods(),
367 PDecl->getClassMethods());
368 // Lastly, comment out the @end.
369 Rewrite.ReplaceText(PDecl->getAtEndLoc(), 0, "// ", 3);
370}
371
Steve Naroffbef11852007-10-26 20:53:56 +0000372void RewriteTest::RewriteInterfaceDecl(ObjcInterfaceDecl *ClassDecl) {
Steve Narofff908a872007-10-30 02:23:23 +0000373
374 SourceLocation LocStart = ClassDecl->getLocStart();
375 SourceLocation LocEnd = ClassDecl->getLocEnd();
376
377 const char *startBuf = SM->getCharacterData(LocStart);
378 const char *endBuf = SM->getCharacterData(LocEnd);
379
Steve Naroff2feac5e2007-10-30 03:43:13 +0000380 endBuf += Lexer::MeasureTokenLength(LocEnd, *SM);
Steve Narofff908a872007-10-30 02:23:23 +0000381
382 std::string ResultStr;
Steve Naroff6c6a2db2007-11-01 03:35:41 +0000383 if (!ObjcForwardDecls.count(ClassDecl)) {
384 // we haven't seen a forward decl - generate a typedef.
Steve Naroff32174822007-11-09 12:50:28 +0000385 ResultStr += "#ifndef _REWRITER_typedef_";
386 ResultStr += ClassDecl->getName();
387 ResultStr += "\n";
388 ResultStr += "#define _REWRITER_typedef_";
389 ResultStr += ClassDecl->getName();
390 ResultStr += "\n";
Steve Naroff352336b2007-11-05 14:36:37 +0000391 ResultStr += "typedef struct objc_object ";
Steve Naroff6c6a2db2007-11-01 03:35:41 +0000392 ResultStr += ClassDecl->getName();
Steve Naroff32174822007-11-09 12:50:28 +0000393 ResultStr += ";\n#endif\n";
Steve Naroff6c6a2db2007-11-01 03:35:41 +0000394
395 // Mark this typedef as having been generated.
396 ObjcForwardDecls.insert(ClassDecl);
397 }
Steve Narofff908a872007-10-30 02:23:23 +0000398 SynthesizeObjcInternalStruct(ClassDecl, ResultStr);
399
Steve Naroff2feac5e2007-10-30 03:43:13 +0000400 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
Steve Narofff908a872007-10-30 02:23:23 +0000401 ResultStr.c_str(), ResultStr.size());
Fariborz Jahanian957cf652007-11-07 00:09:37 +0000402 RewriteProperties(ClassDecl->getNumPropertyDecl(),
403 ClassDecl->getPropertyDecl());
Steve Naroff423cb562007-10-30 13:30:57 +0000404 RewriteMethods(ClassDecl->getNumInstanceMethods(),
405 ClassDecl->getInstanceMethods());
406 RewriteMethods(ClassDecl->getNumClassMethods(),
407 ClassDecl->getClassMethods());
Steve Naroffbef11852007-10-26 20:53:56 +0000408
Steve Naroff2feac5e2007-10-30 03:43:13 +0000409 // Lastly, comment out the @end.
410 Rewrite.ReplaceText(ClassDecl->getAtEndLoc(), 0, "// ", 3);
Steve Naroffbef11852007-10-26 20:53:56 +0000411}
412
Chris Lattnerf04da132007-10-24 17:06:59 +0000413//===----------------------------------------------------------------------===//
414// Function Body / Expression rewriting
415//===----------------------------------------------------------------------===//
416
Chris Lattnere64b7772007-10-24 16:57:36 +0000417Stmt *RewriteTest::RewriteFunctionBody(Stmt *S) {
Chris Lattner311ff022007-10-16 22:36:42 +0000418 // Otherwise, just rewrite all children.
419 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
420 CI != E; ++CI)
Steve Naroff75730982007-11-07 04:08:17 +0000421 if (*CI) {
422 Stmt *newStmt = RewriteFunctionBody(*CI);
423 if (newStmt)
424 *CI = newStmt;
425 }
Steve Naroffebf2b562007-10-23 23:50:29 +0000426
427 // Handle specific things.
428 if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
429 return RewriteAtEncode(AtEncode);
Steve Naroffb42f8412007-11-05 14:50:49 +0000430
431 if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S))
432 return RewriteAtSelector(AtSelector);
Steve Naroffbeaf2992007-11-03 11:27:19 +0000433
434 if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S))
435 return RewriteObjCStringLiteral(AtString);
Steve Naroffebf2b562007-10-23 23:50:29 +0000436
Steve Naroff934f2762007-10-24 22:48:43 +0000437 if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {
438 // Before we rewrite it, put the original message expression in a comment.
439 SourceLocation startLoc = MessExpr->getLocStart();
440 SourceLocation endLoc = MessExpr->getLocEnd();
441
442 const char *startBuf = SM->getCharacterData(startLoc);
443 const char *endBuf = SM->getCharacterData(endLoc);
444
445 std::string messString;
446 messString += "// ";
447 messString.append(startBuf, endBuf-startBuf+1);
448 messString += "\n";
Steve Naroffbef11852007-10-26 20:53:56 +0000449
Steve Naroff934f2762007-10-24 22:48:43 +0000450 // FIXME: Missing definition of Rewrite.InsertText(clang::SourceLocation, char const*, unsigned int).
451 // Rewrite.InsertText(startLoc, messString.c_str(), messString.size());
452 // Tried this, but it didn't work either...
Steve Naroff752d6ef2007-10-30 16:42:30 +0000453 // Rewrite.ReplaceText(startLoc, 0, messString.c_str(), messString.size());
Steve Naroffebf2b562007-10-23 23:50:29 +0000454 return RewriteMessageExpr(MessExpr);
Steve Naroff934f2762007-10-24 22:48:43 +0000455 }
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000456
457 if (ObjcAtTryStmt *StmtTry = dyn_cast<ObjcAtTryStmt>(S))
458 return RewriteObjcTryStmt(StmtTry);
Steve Naroff2bd03922007-11-07 15:32:26 +0000459
460 if (ObjcAtThrowStmt *StmtThrow = dyn_cast<ObjcAtThrowStmt>(S))
461 return RewriteObjcThrowStmt(StmtThrow);
462
Chris Lattnere64b7772007-10-24 16:57:36 +0000463 // Return this stmt unmodified.
464 return S;
Chris Lattner311ff022007-10-16 22:36:42 +0000465}
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +0000466
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000467Stmt *RewriteTest::RewriteObjcTryStmt(ObjcAtTryStmt *S) {
Steve Naroff75730982007-11-07 04:08:17 +0000468 // Get the start location and compute the semi location.
469 SourceLocation startLoc = S->getLocStart();
470 const char *startBuf = SM->getCharacterData(startLoc);
471
472 assert((*startBuf == '@') && "bogus @try location");
473
474 std::string buf;
475 // declare a new scope with two variables, _stack and _rethrow.
476 buf = "/* @try scope begin */ { struct _objc_exception_data {\n";
477 buf += "int buf[18/*32-bit i386*/];\n";
478 buf += "char *pointers[4];} _stack;\n";
479 buf += "id volatile _rethrow = 0;\n";
480 buf += "objc_exception_try_enter(&_stack);\n";
Steve Naroff21867b12007-11-07 18:43:40 +0000481 buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";
Steve Naroff75730982007-11-07 04:08:17 +0000482
483 Rewrite.ReplaceText(startLoc, 4, buf.c_str(), buf.size());
484
485 startLoc = S->getTryBody()->getLocEnd();
486 startBuf = SM->getCharacterData(startLoc);
487
488 assert((*startBuf == '}') && "bogus @try block");
489
490 SourceLocation lastCurlyLoc = startLoc;
491
492 startLoc = startLoc.getFileLocWithOffset(1);
493 buf = " /* @catch begin */ else {\n";
494 buf += " id _caught = objc_exception_extract(&_stack);\n";
495 buf += " objc_exception_try_enter (&_stack);\n";
Steve Naroff21867b12007-11-07 18:43:40 +0000496 buf += " if (_setjmp(_stack.buf))\n";
Steve Naroff75730982007-11-07 04:08:17 +0000497 buf += " _rethrow = objc_exception_extract(&_stack);\n";
498 buf += " else { /* @catch continue */";
499
Chris Lattner28d1fe82007-11-08 04:41:51 +0000500 Rewrite.InsertText(startLoc, buf.c_str(), buf.size());
Steve Naroff75730982007-11-07 04:08:17 +0000501
502 bool sawIdTypedCatch = false;
503 Stmt *lastCatchBody = 0;
504 ObjcAtCatchStmt *catchList = S->getCatchStmts();
505 while (catchList) {
506 Stmt *catchStmt = catchList->getCatchParamStmt();
507
508 if (catchList == S->getCatchStmts())
509 buf = "if ("; // we are generating code for the first catch clause
510 else
511 buf = "else if (";
512 startLoc = catchList->getLocStart();
513 startBuf = SM->getCharacterData(startLoc);
514
515 assert((*startBuf == '@') && "bogus @catch location");
516
517 const char *lParenLoc = strchr(startBuf, '(');
518
519 if (DeclStmt *declStmt = dyn_cast<DeclStmt>(catchStmt)) {
520 QualType t = dyn_cast<ValueDecl>(declStmt->getDecl())->getType();
521 if (t == Context->getObjcIdType()) {
522 buf += "1) { ";
523 Rewrite.ReplaceText(startLoc, lParenLoc-startBuf+1,
524 buf.c_str(), buf.size());
525 sawIdTypedCatch = true;
526 } else if (const PointerType *pType = t->getAsPointerType()) {
527 ObjcInterfaceType *cls; // Should be a pointer to a class.
528
529 cls = dyn_cast<ObjcInterfaceType>(pType->getPointeeType().getTypePtr());
530 if (cls) {
Steve Naroff21867b12007-11-07 18:43:40 +0000531 buf += "objc_exception_match((struct objc_class *)objc_getClass(\"";
Steve Naroff75730982007-11-07 04:08:17 +0000532 buf += cls->getDecl()->getName();
Steve Naroff21867b12007-11-07 18:43:40 +0000533 buf += "\"), (struct objc_object *)_caught)) { ";
Steve Naroff75730982007-11-07 04:08:17 +0000534 Rewrite.ReplaceText(startLoc, lParenLoc-startBuf+1,
535 buf.c_str(), buf.size());
536 }
537 }
538 // Now rewrite the body...
539 lastCatchBody = catchList->getCatchBody();
540 SourceLocation rParenLoc = catchList->getRParenLoc();
541 SourceLocation bodyLoc = lastCatchBody->getLocStart();
542 const char *bodyBuf = SM->getCharacterData(bodyLoc);
543 const char *rParenBuf = SM->getCharacterData(rParenLoc);
544 assert((*rParenBuf == ')') && "bogus @catch paren location");
545 assert((*bodyBuf == '{') && "bogus @catch body location");
546
547 buf = " = _caught;";
548 // Here we replace ") {" with "= _caught;" (which initializes and
549 // declares the @catch parameter).
550 Rewrite.ReplaceText(rParenLoc, bodyBuf-rParenBuf+1,
551 buf.c_str(), buf.size());
Steve Naroff2bd03922007-11-07 15:32:26 +0000552 } else if (!isa<NullStmt>(catchStmt)) {
Steve Naroff75730982007-11-07 04:08:17 +0000553 assert(false && "@catch rewrite bug");
Steve Naroff2bd03922007-11-07 15:32:26 +0000554 }
Steve Naroff75730982007-11-07 04:08:17 +0000555 catchList = catchList->getNextCatchStmt();
556 }
557 // Complete the catch list...
558 if (lastCatchBody) {
559 SourceLocation bodyLoc = lastCatchBody->getLocEnd();
560 const char *bodyBuf = SM->getCharacterData(bodyLoc);
561 assert((*bodyBuf == '}') && "bogus @catch body location");
562 bodyLoc = bodyLoc.getFileLocWithOffset(1);
563 buf = " } } /* @catch end */\n";
564
Chris Lattner28d1fe82007-11-08 04:41:51 +0000565 Rewrite.InsertText(bodyLoc, buf.c_str(), buf.size());
Steve Naroff75730982007-11-07 04:08:17 +0000566
567 // Set lastCurlyLoc
568 lastCurlyLoc = lastCatchBody->getLocEnd();
569 }
570 if (ObjcAtFinallyStmt *finalStmt = S->getFinallyStmt()) {
571 startLoc = finalStmt->getLocStart();
572 startBuf = SM->getCharacterData(startLoc);
573 assert((*startBuf == '@') && "bogus @finally start");
574
575 buf = "/* @finally */";
576 Rewrite.ReplaceText(startLoc, 8, buf.c_str(), buf.size());
577
578 Stmt *body = finalStmt->getFinallyBody();
579 SourceLocation startLoc = body->getLocStart();
580 SourceLocation endLoc = body->getLocEnd();
581 const char *startBuf = SM->getCharacterData(startLoc);
582 const char *endBuf = SM->getCharacterData(endLoc);
583 assert((*startBuf == '{') && "bogus @finally body location");
584 assert((*endBuf == '}') && "bogus @finally body location");
585
586 startLoc = startLoc.getFileLocWithOffset(1);
587 buf = " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
Chris Lattner28d1fe82007-11-08 04:41:51 +0000588 Rewrite.InsertText(startLoc, buf.c_str(), buf.size());
Steve Naroff75730982007-11-07 04:08:17 +0000589 endLoc = endLoc.getFileLocWithOffset(-1);
590 buf = " if (_rethrow) objc_exception_throw(_rethrow);\n";
Chris Lattner28d1fe82007-11-08 04:41:51 +0000591 Rewrite.InsertText(endLoc, buf.c_str(), buf.size());
Steve Naroff75730982007-11-07 04:08:17 +0000592
593 // Set lastCurlyLoc
594 lastCurlyLoc = body->getLocEnd();
595 }
596 // Now emit the final closing curly brace...
597 lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1);
598 buf = " } /* @try scope end */\n";
Chris Lattner28d1fe82007-11-08 04:41:51 +0000599 Rewrite.InsertText(lastCurlyLoc, buf.c_str(), buf.size());
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000600 return 0;
601}
602
603Stmt *RewriteTest::RewriteObjcCatchStmt(ObjcAtCatchStmt *S) {
604 return 0;
605}
606
607Stmt *RewriteTest::RewriteObjcFinallyStmt(ObjcAtFinallyStmt *S) {
608 return 0;
609}
610
Steve Naroff2bd03922007-11-07 15:32:26 +0000611// This can't be done with Rewrite.ReplaceStmt(S, ThrowExpr), since
612// the throw expression is typically a message expression that's already
613// been rewritten! (which implies the SourceLocation's are invalid).
614Stmt *RewriteTest::RewriteObjcThrowStmt(ObjcAtThrowStmt *S) {
615 // Get the start location and compute the semi location.
616 SourceLocation startLoc = S->getLocStart();
617 const char *startBuf = SM->getCharacterData(startLoc);
618
619 assert((*startBuf == '@') && "bogus @throw location");
620
621 std::string buf;
622 /* void objc_exception_throw(id) __attribute__((noreturn)); */
623 buf = "objc_exception_throw(";
624 Rewrite.ReplaceText(startLoc, 6, buf.c_str(), buf.size());
625 const char *semiBuf = strchr(startBuf, ';');
626 assert((*semiBuf == ';') && "@throw: can't find ';'");
627 SourceLocation semiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf);
628 buf = ");";
629 Rewrite.ReplaceText(semiLoc, 1, buf.c_str(), buf.size());
630 return 0;
631}
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000632
Chris Lattnere64b7772007-10-24 16:57:36 +0000633Stmt *RewriteTest::RewriteAtEncode(ObjCEncodeExpr *Exp) {
Chris Lattner01c57482007-10-17 22:35:30 +0000634 // Create a new string expression.
635 QualType StrType = Context->getPointerType(Context->CharTy);
Anders Carlsson85f9bce2007-10-29 05:01:08 +0000636 std::string StrEncoding;
637 Context->getObjcEncodingForType(Exp->getEncodedType(), StrEncoding);
638 Expr *Replacement = new StringLiteral(StrEncoding.c_str(),
639 StrEncoding.length(), false, StrType,
Chris Lattner01c57482007-10-17 22:35:30 +0000640 SourceLocation(), SourceLocation());
641 Rewrite.ReplaceStmt(Exp, Replacement);
Chris Lattnere64b7772007-10-24 16:57:36 +0000642 delete Exp;
643 return Replacement;
Chris Lattner311ff022007-10-16 22:36:42 +0000644}
645
Steve Naroffb42f8412007-11-05 14:50:49 +0000646Stmt *RewriteTest::RewriteAtSelector(ObjCSelectorExpr *Exp) {
647 assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");
648 // Create a call to sel_registerName("selName").
649 llvm::SmallVector<Expr*, 8> SelExprs;
650 QualType argType = Context->getPointerType(Context->CharTy);
651 SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
652 Exp->getSelector().getName().size(),
653 false, argType, SourceLocation(),
654 SourceLocation()));
655 CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
656 &SelExprs[0], SelExprs.size());
657 Rewrite.ReplaceStmt(Exp, SelExp);
658 delete Exp;
659 return SelExp;
660}
661
Steve Naroff934f2762007-10-24 22:48:43 +0000662CallExpr *RewriteTest::SynthesizeCallToFunctionDecl(
663 FunctionDecl *FD, Expr **args, unsigned nargs) {
Steve Naroffebf2b562007-10-23 23:50:29 +0000664 // Get the type, we will need to reference it in a couple spots.
Steve Naroff934f2762007-10-24 22:48:43 +0000665 QualType msgSendType = FD->getType();
Steve Naroffebf2b562007-10-23 23:50:29 +0000666
667 // Create a reference to the objc_msgSend() declaration.
Steve Naroff934f2762007-10-24 22:48:43 +0000668 DeclRefExpr *DRE = new DeclRefExpr(FD, msgSendType, SourceLocation());
Steve Naroffebf2b562007-10-23 23:50:29 +0000669
670 // Now, we cast the reference to a pointer to the objc_msgSend type.
Chris Lattnerf04da132007-10-24 17:06:59 +0000671 QualType pToFunc = Context->getPointerType(msgSendType);
Steve Naroffebf2b562007-10-23 23:50:29 +0000672 ImplicitCastExpr *ICE = new ImplicitCastExpr(pToFunc, DRE);
673
674 const FunctionType *FT = msgSendType->getAsFunctionType();
Chris Lattnere64b7772007-10-24 16:57:36 +0000675
Steve Naroff934f2762007-10-24 22:48:43 +0000676 return new CallExpr(ICE, args, nargs, FT->getResultType(), SourceLocation());
677}
678
Steve Naroffd5255f52007-11-01 13:24:47 +0000679static bool scanForProtocolRefs(const char *startBuf, const char *endBuf,
680 const char *&startRef, const char *&endRef) {
681 while (startBuf < endBuf) {
682 if (*startBuf == '<')
683 startRef = startBuf; // mark the start.
684 if (*startBuf == '>') {
Steve Naroff32174822007-11-09 12:50:28 +0000685 if (startRef && *startRef == '<') {
686 endRef = startBuf; // mark the end.
687 return true;
688 }
689 return false;
Steve Naroffd5255f52007-11-01 13:24:47 +0000690 }
691 startBuf++;
692 }
693 return false;
694}
695
696bool RewriteTest::needToScanForQualifiers(QualType T) {
697 // FIXME: we don't currently represent "id <Protocol>" in the type system.
698 if (T == Context->getObjcIdType())
699 return true;
700
701 if (const PointerType *pType = T->getAsPointerType()) {
Steve Naroff9165ad32007-10-31 04:38:33 +0000702 Type *pointeeType = pType->getPointeeType().getTypePtr();
703 if (isa<ObjcQualifiedInterfaceType>(pointeeType))
704 return true; // we have "Class <Protocol> *".
705 }
Steve Naroffd5255f52007-11-01 13:24:47 +0000706 return false;
707}
708
709void RewriteTest::RewriteObjcQualifiedInterfaceTypes(
710 const FunctionTypeProto *proto, FunctionDecl *FD) {
711
712 if (needToScanForQualifiers(proto->getResultType())) {
713 // Since types are unique, we need to scan the buffer.
714 SourceLocation Loc = FD->getLocation();
715
716 const char *endBuf = SM->getCharacterData(Loc);
717 const char *startBuf = endBuf;
718 while (*startBuf != ';')
719 startBuf--; // scan backward (from the decl location) for return type.
720 const char *startRef = 0, *endRef = 0;
721 if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
722 // Get the locations of the startRef, endRef.
723 SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-endBuf);
724 SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-endBuf+1);
725 // Comment out the protocol references.
Chris Lattner28d1fe82007-11-08 04:41:51 +0000726 Rewrite.InsertText(LessLoc, "/*", 2);
727 Rewrite.InsertText(GreaterLoc, "*/", 2);
Steve Naroff9165ad32007-10-31 04:38:33 +0000728 }
729 }
Steve Naroffd5255f52007-11-01 13:24:47 +0000730 // Now check arguments.
731 for (unsigned i = 0; i < proto->getNumArgs(); i++) {
732 if (needToScanForQualifiers(proto->getArgType(i))) {
733 // Since types are unique, we need to scan the buffer.
734 SourceLocation Loc = FD->getLocation();
735
736 const char *startBuf = SM->getCharacterData(Loc);
737 const char *endBuf = startBuf;
738 while (*endBuf != ';')
739 endBuf++; // scan forward (from the decl location) for argument types.
740 const char *startRef = 0, *endRef = 0;
741 if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
742 // Get the locations of the startRef, endRef.
743 SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-startBuf);
744 SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-startBuf+1);
745 // Comment out the protocol references.
Chris Lattner28d1fe82007-11-08 04:41:51 +0000746 Rewrite.InsertText(LessLoc, "/*", 2);
747 Rewrite.InsertText(GreaterLoc, "*/", 2);
Steve Naroffd5255f52007-11-01 13:24:47 +0000748 }
749 }
750 }
Steve Naroff9165ad32007-10-31 04:38:33 +0000751}
752
Steve Naroff09b266e2007-10-30 23:14:51 +0000753void RewriteTest::RewriteFunctionDecl(FunctionDecl *FD) {
754 // declared in <objc/objc.h>
Steve Naroffbeaf2992007-11-03 11:27:19 +0000755 if (strcmp(FD->getName(), "sel_registerName") == 0) {
Steve Naroff09b266e2007-10-30 23:14:51 +0000756 SelGetUidFunctionDecl = FD;
Steve Naroff9165ad32007-10-31 04:38:33 +0000757 return;
758 }
759 // Check for ObjC 'id' and class types that have been adorned with protocol
760 // information (id<p>, C<p>*). The protocol references need to be rewritten!
761 const FunctionType *funcType = FD->getType()->getAsFunctionType();
762 assert(funcType && "missing function type");
Steve Naroffd5255f52007-11-01 13:24:47 +0000763 if (const FunctionTypeProto *proto = dyn_cast<FunctionTypeProto>(funcType))
764 RewriteObjcQualifiedInterfaceTypes(proto, FD);
Steve Naroff09b266e2007-10-30 23:14:51 +0000765}
766
767// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
768void RewriteTest::SynthMsgSendFunctionDecl() {
769 IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend");
770 llvm::SmallVector<QualType, 16> ArgTys;
771 QualType argT = Context->getObjcIdType();
772 assert(!argT.isNull() && "Can't find 'id' type");
773 ArgTys.push_back(argT);
774 argT = Context->getObjcSelType();
775 assert(!argT.isNull() && "Can't find 'SEL' type");
776 ArgTys.push_back(argT);
777 QualType msgSendType = Context->getFunctionType(Context->getObjcIdType(),
778 &ArgTys[0], ArgTys.size(),
779 true /*isVariadic*/);
780 MsgSendFunctionDecl = new FunctionDecl(SourceLocation(),
781 msgSendIdent, msgSendType,
782 FunctionDecl::Extern, false, 0);
783}
784
785// SynthGetClassFunctionDecl - id objc_getClass(const char *name);
786void RewriteTest::SynthGetClassFunctionDecl() {
787 IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass");
788 llvm::SmallVector<QualType, 16> ArgTys;
789 ArgTys.push_back(Context->getPointerType(
790 Context->CharTy.getQualifiedType(QualType::Const)));
791 QualType getClassType = Context->getFunctionType(Context->getObjcIdType(),
792 &ArgTys[0], ArgTys.size(),
793 false /*isVariadic*/);
794 GetClassFunctionDecl = new FunctionDecl(SourceLocation(),
795 getClassIdent, getClassType,
796 FunctionDecl::Extern, false, 0);
797}
798
Steve Naroff96984642007-11-08 14:30:50 +0000799// SynthCFStringFunctionDecl - id __builtin___CFStringMakeConstantString(const char *name);
800void RewriteTest::SynthCFStringFunctionDecl() {
801 IdentifierInfo *getClassIdent = &Context->Idents.get("__builtin___CFStringMakeConstantString");
802 llvm::SmallVector<QualType, 16> ArgTys;
803 ArgTys.push_back(Context->getPointerType(
804 Context->CharTy.getQualifiedType(QualType::Const)));
805 QualType getClassType = Context->getFunctionType(Context->getObjcIdType(),
806 &ArgTys[0], ArgTys.size(),
807 false /*isVariadic*/);
808 CFStringFunctionDecl = new FunctionDecl(SourceLocation(),
809 getClassIdent, getClassType,
810 FunctionDecl::Extern, false, 0);
811}
812
Steve Naroffbeaf2992007-11-03 11:27:19 +0000813Stmt *RewriteTest::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
Steve Naroff96984642007-11-08 14:30:50 +0000814#if 1
815 // This rewrite is specific to GCC, which has builtin support for CFString.
816 if (!CFStringFunctionDecl)
817 SynthCFStringFunctionDecl();
818 // Create a call to __builtin___CFStringMakeConstantString("cstr").
819 llvm::SmallVector<Expr*, 8> StrExpr;
820 StrExpr.push_back(Exp->getString());
821 CallExpr *call = SynthesizeCallToFunctionDecl(CFStringFunctionDecl,
822 &StrExpr[0], StrExpr.size());
823 // cast to NSConstantString *
824 CastExpr *cast = new CastExpr(Exp->getType(), call, SourceLocation());
825 Rewrite.ReplaceStmt(Exp, cast);
826 delete Exp;
827 return cast;
828#else
Steve Naroffbeaf2992007-11-03 11:27:19 +0000829 assert(ConstantStringClassReference && "Can't find constant string reference");
830 llvm::SmallVector<Expr*, 4> InitExprs;
831
832 // Synthesize "(Class)&_NSConstantStringClassReference"
833 DeclRefExpr *ClsRef = new DeclRefExpr(ConstantStringClassReference,
834 ConstantStringClassReference->getType(),
835 SourceLocation());
836 QualType expType = Context->getPointerType(ClsRef->getType());
837 UnaryOperator *Unop = new UnaryOperator(ClsRef, UnaryOperator::AddrOf,
838 expType, SourceLocation());
839 CastExpr *cast = new CastExpr(Context->getObjcClassType(), Unop,
840 SourceLocation());
841 InitExprs.push_back(cast); // set the 'isa'.
842 InitExprs.push_back(Exp->getString()); // set "char *bytes".
843 unsigned IntSize = static_cast<unsigned>(
844 Context->getTypeSize(Context->IntTy, Exp->getLocStart()));
845 llvm::APInt IntVal(IntSize, Exp->getString()->getByteLength());
846 IntegerLiteral *len = new IntegerLiteral(IntVal, Context->IntTy,
847 Exp->getLocStart());
848 InitExprs.push_back(len); // set "int numBytes".
849
850 // struct NSConstantString
851 QualType CFConstantStrType = Context->getCFConstantStringType();
852 // (struct NSConstantString) { <exprs from above> }
853 InitListExpr *ILE = new InitListExpr(SourceLocation(),
854 &InitExprs[0], InitExprs.size(),
855 SourceLocation());
856 CompoundLiteralExpr *StrRep = new CompoundLiteralExpr(CFConstantStrType, ILE);
857 // struct NSConstantString *
858 expType = Context->getPointerType(StrRep->getType());
859 Unop = new UnaryOperator(StrRep, UnaryOperator::AddrOf, expType,
860 SourceLocation());
Steve Naroff352336b2007-11-05 14:36:37 +0000861 // cast to NSConstantString *
862 cast = new CastExpr(Exp->getType(), Unop, SourceLocation());
Steve Naroffbeaf2992007-11-03 11:27:19 +0000863 Rewrite.ReplaceStmt(Exp, cast);
864 delete Exp;
Steve Naroff352336b2007-11-05 14:36:37 +0000865 return cast;
Steve Naroff96984642007-11-08 14:30:50 +0000866#endif
Steve Naroffbeaf2992007-11-03 11:27:19 +0000867}
868
Steve Naroff934f2762007-10-24 22:48:43 +0000869Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) {
Steve Naroffbeaf2992007-11-03 11:27:19 +0000870 assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");
Steve Naroff09b266e2007-10-30 23:14:51 +0000871 if (!MsgSendFunctionDecl)
872 SynthMsgSendFunctionDecl();
873 if (!GetClassFunctionDecl)
874 SynthGetClassFunctionDecl();
Steve Naroff934f2762007-10-24 22:48:43 +0000875
876 // Synthesize a call to objc_msgSend().
877 llvm::SmallVector<Expr*, 8> MsgExprs;
878 IdentifierInfo *clsName = Exp->getClassName();
879
880 // Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend().
881 if (clsName) { // class message.
882 llvm::SmallVector<Expr*, 8> ClsExprs;
883 QualType argType = Context->getPointerType(Context->CharTy);
884 ClsExprs.push_back(new StringLiteral(clsName->getName(),
885 clsName->getLength(),
886 false, argType, SourceLocation(),
887 SourceLocation()));
888 CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
889 &ClsExprs[0], ClsExprs.size());
890 MsgExprs.push_back(Cls);
891 } else // instance message.
892 MsgExprs.push_back(Exp->getReceiver());
893
Steve Naroffbeaf2992007-11-03 11:27:19 +0000894 // Create a call to sel_registerName("selName"), it will be the 2nd argument.
Steve Naroff934f2762007-10-24 22:48:43 +0000895 llvm::SmallVector<Expr*, 8> SelExprs;
896 QualType argType = Context->getPointerType(Context->CharTy);
897 SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
898 Exp->getSelector().getName().size(),
899 false, argType, SourceLocation(),
900 SourceLocation()));
901 CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
902 &SelExprs[0], SelExprs.size());
903 MsgExprs.push_back(SelExp);
904
905 // Now push any user supplied arguments.
906 for (unsigned i = 0; i < Exp->getNumArgs(); i++) {
907 MsgExprs.push_back(Exp->getArg(i));
908 // We've transferred the ownership to MsgExprs. Null out the argument in
909 // the original expression, since we will delete it below.
910 Exp->setArg(i, 0);
911 }
Steve Naroffab972d32007-11-04 22:37:50 +0000912 // Generate the funky cast.
913 CastExpr *cast;
914 llvm::SmallVector<QualType, 8> ArgTypes;
915 QualType returnType;
916
917 // Push 'id' and 'SEL', the 2 implicit arguments.
918 ArgTypes.push_back(Context->getObjcIdType());
919 ArgTypes.push_back(Context->getObjcSelType());
920 if (ObjcMethodDecl *mDecl = Exp->getMethodDecl()) {
921 // Push any user argument types.
Steve Naroff352336b2007-11-05 14:36:37 +0000922 for (int i = 0; i < mDecl->getNumParams(); i++) {
923 QualType t = mDecl->getParamDecl(i)->getType();
924 if (t == Context->getObjcClassType())
925 t = Context->getObjcIdType(); // Convert "Class"->"id"
926 ArgTypes.push_back(t);
927 }
Steve Naroffab972d32007-11-04 22:37:50 +0000928 returnType = mDecl->getResultType();
929 } else {
930 returnType = Context->getObjcIdType();
931 }
932 // Get the type, we will need to reference it in a couple spots.
933 QualType msgSendType = MsgSendFunctionDecl->getType();
934
935 // Create a reference to the objc_msgSend() declaration.
936 DeclRefExpr *DRE = new DeclRefExpr(MsgSendFunctionDecl, msgSendType, SourceLocation());
937
938 // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid).
939 // If we don't do this cast, we get the following bizarre warning/note:
940 // xx.m:13: warning: function called through a non-compatible type
941 // xx.m:13: note: if this code is reached, the program will abort
942 cast = new CastExpr(Context->getPointerType(Context->VoidTy), DRE,
943 SourceLocation());
944
945 // Now do the "normal" pointer to function cast.
946 QualType castType = Context->getFunctionType(returnType,
947 &ArgTypes[0], ArgTypes.size(),
948 false/*FIXME:variadic*/);
949 castType = Context->getPointerType(castType);
950 cast = new CastExpr(castType, cast, SourceLocation());
951
952 // Don't forget the parens to enforce the proper binding.
953 ParenExpr *PE = new ParenExpr(SourceLocation(), SourceLocation(), cast);
954
955 const FunctionType *FT = msgSendType->getAsFunctionType();
956 CallExpr *CE = new CallExpr(PE, &MsgExprs[0], MsgExprs.size(),
957 FT->getResultType(), SourceLocation());
Steve Naroff934f2762007-10-24 22:48:43 +0000958 // Now do the actual rewrite.
Steve Naroffab972d32007-11-04 22:37:50 +0000959 Rewrite.ReplaceStmt(Exp, CE);
Steve Naroff934f2762007-10-24 22:48:43 +0000960
Chris Lattnere64b7772007-10-24 16:57:36 +0000961 delete Exp;
Steve Naroffab972d32007-11-04 22:37:50 +0000962 return CE;
Steve Naroffebf2b562007-10-23 23:50:29 +0000963}
964
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000965/// SynthesizeObjcInternalStruct - Rewrite one internal struct corresponding to
966/// an objective-c class with ivars.
967void RewriteTest::SynthesizeObjcInternalStruct(ObjcInterfaceDecl *CDecl,
968 std::string &Result) {
969 assert(CDecl && "Class missing in SynthesizeObjcInternalStruct");
970 assert(CDecl->getName() && "Name missing in SynthesizeObjcInternalStruct");
Fariborz Jahanian212b7682007-10-31 23:08:24 +0000971 // Do not synthesize more than once.
972 if (ObjcSynthesizedStructs.count(CDecl))
973 return;
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000974 ObjcInterfaceDecl *RCDecl = CDecl->getSuperClass();
975 if (RCDecl && !ObjcSynthesizedStructs.count(RCDecl)) {
976 // Do it for the root
977 SynthesizeObjcInternalStruct(RCDecl, Result);
978 }
979
980 int NumIvars = CDecl->getIntfDeclNumIvars();
Fariborz Jahanianaff56d02007-10-31 22:57:04 +0000981 // If no ivars and no root or if its root, directly or indirectly,
Fariborz Jahanianf1de0ca2007-10-31 23:53:01 +0000982 // have no ivars (thus not synthesized) then no need to synthesize this class.
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000983 if (NumIvars <= 0 && (!RCDecl || !ObjcSynthesizedStructs.count(RCDecl)))
984 return;
985
Steve Naroff04960052007-11-01 17:12:31 +0000986 Result += "\nstruct ";
987 Result += CDecl->getName();
988 if (RCDecl && ObjcSynthesizedStructs.count(RCDecl)) {
989 Result += " {\n struct ";
990 Result += RCDecl->getName();
991 Result += " _";
992 Result += RCDecl->getName();
993 Result += ";\n";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000994 }
Fariborz Jahanianfdc08a02007-10-31 17:29:28 +0000995 else
996 Result += " {";
Steve Naroff8749be52007-10-31 22:11:35 +0000997
Fariborz Jahanianfdc08a02007-10-31 17:29:28 +0000998 if (NumIvars > 0) {
999 SourceLocation LocStart = CDecl->getLocStart();
1000 SourceLocation LocEnd = CDecl->getLocEnd();
1001
1002 const char *startBuf = SM->getCharacterData(LocStart);
1003 const char *endBuf = SM->getCharacterData(LocEnd);
1004 startBuf = strchr(startBuf, '{');
1005 assert((startBuf && endBuf)
1006 && "SynthesizeObjcInternalStruct - malformed @interface");
1007 startBuf++; // past '{'
1008 while (startBuf < endBuf) {
1009 if (*startBuf == '@') {
1010 startBuf = strchr(startBuf, 'p');
1011 // FIXME: presence of @public, etc. inside comment results in
1012 // this transformation as well, which is still correct c-code.
1013 if (!strncmp(startBuf, "public", strlen("public"))) {
1014 startBuf += strlen("public");
1015 Result += "/* @public */";
1016 }
1017 else if (!strncmp(startBuf, "private", strlen("private"))) {
1018 startBuf += strlen("private");
1019 Result += "/* @private */";
1020 }
1021 else if (!strncmp(startBuf, "protected", strlen("protected"))) {
1022 startBuf += strlen("protected");
1023 Result += "/* @protected */";
1024 }
1025 }
1026 Result += *startBuf++;
1027 }
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001028 }
Fariborz Jahanianfdc08a02007-10-31 17:29:28 +00001029
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001030 Result += "};\n";
1031 // Mark this struct as having been generated.
1032 if (!ObjcSynthesizedStructs.insert(CDecl))
Fariborz Jahanianaff56d02007-10-31 22:57:04 +00001033 assert(false && "struct already synthesize- SynthesizeObjcInternalStruct");
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001034}
1035
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001036// RewriteObjcMethodsMetaData - Rewrite methods metadata for instance or
1037/// class methods.
1038void RewriteTest::RewriteObjcMethodsMetaData(ObjcMethodDecl **Methods,
1039 int NumMethods,
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +00001040 bool IsInstanceMethod,
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001041 const char *prefix,
Chris Lattner158ecb92007-10-25 17:07:24 +00001042 const char *ClassName,
1043 std::string &Result) {
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001044 static bool objc_impl_method = false;
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001045 if (NumMethods > 0 && !objc_impl_method) {
1046 /* struct _objc_method {
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001047 SEL _cmd;
1048 char *method_types;
1049 void *_imp;
1050 }
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001051 */
Chris Lattner158ecb92007-10-25 17:07:24 +00001052 Result += "\nstruct _objc_method {\n";
1053 Result += "\tSEL _cmd;\n";
1054 Result += "\tchar *method_types;\n";
1055 Result += "\tvoid *_imp;\n";
1056 Result += "};\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001057
1058 /* struct _objc_method_list {
1059 struct _objc_method_list *next_method;
1060 int method_count;
1061 struct _objc_method method_list[];
1062 }
1063 */
1064 Result += "\nstruct _objc_method_list {\n";
1065 Result += "\tstruct _objc_method_list *next_method;\n";
1066 Result += "\tint method_count;\n";
1067 Result += "\tstruct _objc_method method_list[];\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001068 objc_impl_method = true;
Fariborz Jahanian776d6ff2007-10-19 00:36:46 +00001069 }
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001070 // Build _objc_method_list for class's methods if needed
1071 if (NumMethods > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001072 Result += "\nstatic struct _objc_method_list _OBJC_";
Chris Lattner158ecb92007-10-25 17:07:24 +00001073 Result += prefix;
1074 Result += IsInstanceMethod ? "INSTANCE" : "CLASS";
1075 Result += "_METHODS_";
1076 Result += ClassName;
1077 Result += " __attribute__ ((section (\"__OBJC, __";
1078 Result += IsInstanceMethod ? "inst" : "cls";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001079 Result += "_meth\")))= ";
1080 Result += "{\n\t0, " + utostr(NumMethods) + "\n";
1081
1082 Result += "\t,{{(SEL)\"";
1083 Result += Methods[0]->getSelector().getName().c_str();
Fariborz Jahanian33e1d642007-10-29 22:57:28 +00001084 std::string MethodTypeString;
1085 Context->getObjcEncodingForMethodDecl(Methods[0], MethodTypeString);
1086 Result += "\", \"";
1087 Result += MethodTypeString;
1088 Result += "\", 0}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001089 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahanian33e1d642007-10-29 22:57:28 +00001090 // TODO: Need method address as 3rd initializer.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001091 Result += "\t ,{(SEL)\"";
1092 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanian33e1d642007-10-29 22:57:28 +00001093 std::string MethodTypeString;
1094 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
1095 Result += "\", \"";
1096 Result += MethodTypeString;
1097 Result += "\", 0}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001098 }
1099 Result += "\t }\n};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001100 }
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001101}
1102
1103/// RewriteObjcProtocolsMetaData - Rewrite protocols meta-data.
1104void RewriteTest::RewriteObjcProtocolsMetaData(ObjcProtocolDecl **Protocols,
1105 int NumProtocols,
1106 const char *prefix,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001107 const char *ClassName,
1108 std::string &Result) {
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001109 static bool objc_protocol_methods = false;
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001110 if (NumProtocols > 0) {
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001111 for (int i = 0; i < NumProtocols; i++) {
1112 ObjcProtocolDecl *PDecl = Protocols[i];
1113 // Output struct protocol_methods holder of method selector and type.
1114 if (!objc_protocol_methods &&
1115 (PDecl->getNumInstanceMethods() > 0
1116 || PDecl->getNumClassMethods() > 0)) {
1117 /* struct protocol_methods {
1118 SEL _cmd;
1119 char *method_types;
1120 }
1121 */
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001122 Result += "\nstruct protocol_methods {\n";
1123 Result += "\tSEL _cmd;\n";
1124 Result += "\tchar *method_types;\n";
1125 Result += "};\n";
1126
1127 /* struct _objc_protocol_method_list {
1128 int protocol_method_count;
1129 struct protocol_methods protocols[];
1130 }
1131 */
1132 Result += "\nstruct _objc_protocol_method_list {\n";
1133 Result += "\tint protocol_method_count;\n";
1134 Result += "\tstruct protocol_methods protocols[];\n};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001135 objc_protocol_methods = true;
1136 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001137
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001138 // Output instance methods declared in this protocol.
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001139 int NumMethods = PDecl->getNumInstanceMethods();
1140 if (NumMethods > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001141 Result += "\nstatic struct _objc_protocol_method_list "
1142 "_OBJC_PROTOCOL_INSTANCE_METHODS_";
1143 Result += PDecl->getName();
1144 Result += " __attribute__ ((section (\"__OBJC, __cat_inst_meth\")))= "
1145 "{\n\t" + utostr(NumMethods) + "\n";
1146
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001147 ObjcMethodDecl **Methods = PDecl->getInstanceMethods();
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001148 Result += "\t,{{(SEL)\"";
1149 Result += Methods[0]->getSelector().getName().c_str();
1150 Result += "\", \"\"}\n";
1151
1152 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001153 Result += "\t ,{(SEL)\"";
1154 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanian33e1d642007-10-29 22:57:28 +00001155 std::string MethodTypeString;
1156 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
1157 Result += "\", \"";
1158 Result += MethodTypeString;
1159 Result += "\"}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001160 }
1161 Result += "\t }\n};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001162 }
1163
1164 // Output class methods declared in this protocol.
1165 NumMethods = PDecl->getNumClassMethods();
1166 if (NumMethods > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001167 Result += "\nstatic struct _objc_protocol_method_list "
1168 "_OBJC_PROTOCOL_CLASS_METHODS_";
1169 Result += PDecl->getName();
1170 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
1171 "{\n\t";
1172 Result += utostr(NumMethods);
1173 Result += "\n";
1174
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001175 ObjcMethodDecl **Methods = PDecl->getClassMethods();
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001176 Result += "\t,{{(SEL)\"";
1177 Result += Methods[0]->getSelector().getName().c_str();
1178 Result += "\", \"\"}\n";
1179
1180 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001181 Result += "\t ,{(SEL)\"";
1182 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanian33e1d642007-10-29 22:57:28 +00001183 std::string MethodTypeString;
1184 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
1185 Result += "\", \"";
1186 Result += MethodTypeString;
1187 Result += "\"}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001188 }
1189 Result += "\t }\n};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001190 }
1191 // Output:
1192 /* struct _objc_protocol {
1193 // Objective-C 1.0 extensions
1194 struct _objc_protocol_extension *isa;
1195 char *protocol_name;
1196 struct _objc_protocol **protocol_list;
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001197 struct _objc_protocol_method_list *instance_methods;
1198 struct _objc_protocol_method_list *class_methods;
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001199 };
1200 */
1201 static bool objc_protocol = false;
1202 if (!objc_protocol) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001203 Result += "\nstruct _objc_protocol {\n";
1204 Result += "\tstruct _objc_protocol_extension *isa;\n";
1205 Result += "\tchar *protocol_name;\n";
1206 Result += "\tstruct _objc_protocol **protocol_list;\n";
1207 Result += "\tstruct _objc_protocol_method_list *instance_methods;\n";
1208 Result += "\tstruct _objc_protocol_method_list *class_methods;\n";
1209 Result += "};\n";
1210
1211 /* struct _objc_protocol_list {
1212 struct _objc_protocol_list *next;
1213 int protocol_count;
1214 struct _objc_protocol *class_protocols[];
1215 }
1216 */
1217 Result += "\nstruct _objc_protocol_list {\n";
1218 Result += "\tstruct _objc_protocol_list *next;\n";
1219 Result += "\tint protocol_count;\n";
1220 Result += "\tstruct _objc_protocol *class_protocols[];\n";
1221 Result += "};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001222 objc_protocol = true;
1223 }
1224
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001225 Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_";
1226 Result += PDecl->getName();
1227 Result += " __attribute__ ((section (\"__OBJC, __protocol\")))= "
1228 "{\n\t0, \"";
1229 Result += PDecl->getName();
1230 Result += "\", 0, ";
1231 if (PDecl->getInstanceMethods() > 0) {
1232 Result += "&_OBJC_PROTOCOL_INSTANCE_METHODS_";
1233 Result += PDecl->getName();
1234 Result += ", ";
1235 }
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001236 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001237 Result += "0, ";
1238 if (PDecl->getClassMethods() > 0) {
1239 Result += "&_OBJC_PROTOCOL_CLASS_METHODS_";
1240 Result += PDecl->getName();
1241 Result += "\n";
1242 }
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001243 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001244 Result += "0\n";
1245 Result += "};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001246 }
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001247 // Output the top lovel protocol meta-data for the class.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001248 Result += "\nstatic struct _objc_protocol_list _OBJC_";
1249 Result += prefix;
1250 Result += "_PROTOCOLS_";
1251 Result += ClassName;
1252 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
1253 "{\n\t0, ";
1254 Result += utostr(NumProtocols);
1255 Result += "\n";
1256
1257 Result += "\t,{&_OBJC_PROTOCOL_";
1258 Result += Protocols[0]->getName();
1259 Result += " \n";
1260
1261 for (int i = 1; i < NumProtocols; i++) {
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001262 ObjcProtocolDecl *PDecl = Protocols[i];
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001263 Result += "\t ,&_OBJC_PROTOCOL_";
1264 Result += PDecl->getName();
1265 Result += "\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001266 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001267 Result += "\t }\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001268 }
1269}
1270
1271/// RewriteObjcCategoryImplDecl - Rewrite metadata for each category
1272/// implementation.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001273void RewriteTest::RewriteObjcCategoryImplDecl(ObjcCategoryImplDecl *IDecl,
1274 std::string &Result) {
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001275 ObjcInterfaceDecl *ClassDecl = IDecl->getClassInterface();
1276 // Find category declaration for this implementation.
1277 ObjcCategoryDecl *CDecl;
1278 for (CDecl = ClassDecl->getCategoryList(); CDecl;
1279 CDecl = CDecl->getNextClassCategory())
1280 if (CDecl->getIdentifier() == IDecl->getIdentifier())
1281 break;
1282 assert(CDecl && "RewriteObjcCategoryImplDecl - bad category");
1283
1284 char *FullCategoryName = (char*)alloca(
1285 strlen(ClassDecl->getName()) + strlen(IDecl->getName()) + 2);
1286 sprintf(FullCategoryName, "%s_%s", ClassDecl->getName(), IDecl->getName());
1287
1288 // Build _objc_method_list for class's instance methods if needed
1289 RewriteObjcMethodsMetaData(IDecl->getInstanceMethods(),
1290 IDecl->getNumInstanceMethods(),
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +00001291 true,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001292 "CATEGORY_", FullCategoryName, Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001293
1294 // Build _objc_method_list for class's class methods if needed
1295 RewriteObjcMethodsMetaData(IDecl->getClassMethods(),
1296 IDecl->getNumClassMethods(),
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +00001297 false,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001298 "CATEGORY_", FullCategoryName, Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001299
1300 // Protocols referenced in class declaration?
1301 RewriteObjcProtocolsMetaData(CDecl->getReferencedProtocols(),
1302 CDecl->getNumReferencedProtocols(),
1303 "CATEGORY",
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001304 FullCategoryName, Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001305
1306 /* struct _objc_category {
1307 char *category_name;
1308 char *class_name;
1309 struct _objc_method_list *instance_methods;
1310 struct _objc_method_list *class_methods;
1311 struct _objc_protocol_list *protocols;
1312 // Objective-C 1.0 extensions
1313 uint32_t size; // sizeof (struct _objc_category)
1314 struct _objc_property_list *instance_properties; // category's own
1315 // @property decl.
1316 };
1317 */
1318
1319 static bool objc_category = false;
1320 if (!objc_category) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001321 Result += "\nstruct _objc_category {\n";
1322 Result += "\tchar *category_name;\n";
1323 Result += "\tchar *class_name;\n";
1324 Result += "\tstruct _objc_method_list *instance_methods;\n";
1325 Result += "\tstruct _objc_method_list *class_methods;\n";
1326 Result += "\tstruct _objc_protocol_list *protocols;\n";
1327 Result += "\tunsigned int size;\n";
1328 Result += "\tstruct _objc_property_list *instance_properties;\n";
1329 Result += "};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001330 objc_category = true;
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001331 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001332 Result += "\nstatic struct _objc_category _OBJC_CATEGORY_";
1333 Result += FullCategoryName;
1334 Result += " __attribute__ ((section (\"__OBJC, __category\")))= {\n\t\"";
1335 Result += IDecl->getName();
1336 Result += "\"\n\t, \"";
1337 Result += ClassDecl->getName();
1338 Result += "\"\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001339
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001340 if (IDecl->getNumInstanceMethods() > 0) {
1341 Result += "\t, (struct _objc_method_list *)"
1342 "&_OBJC_CATEGORY_INSTANCE_METHODS_";
1343 Result += FullCategoryName;
1344 Result += "\n";
1345 }
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001346 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001347 Result += "\t, 0\n";
1348 if (IDecl->getNumClassMethods() > 0) {
1349 Result += "\t, (struct _objc_method_list *)"
1350 "&_OBJC_CATEGORY_CLASS_METHODS_";
1351 Result += FullCategoryName;
1352 Result += "\n";
1353 }
1354 else
1355 Result += "\t, 0\n";
1356
1357 if (CDecl->getNumReferencedProtocols() > 0) {
1358 Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";
1359 Result += FullCategoryName;
1360 Result += "\n";
1361 }
1362 else
1363 Result += "\t, 0\n";
1364 Result += "\t, sizeof(struct _objc_category), 0\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001365}
1366
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001367/// SynthesizeIvarOffsetComputation - This rutine synthesizes computation of
1368/// ivar offset.
1369void RewriteTest::SynthesizeIvarOffsetComputation(ObjcImplementationDecl *IDecl,
1370 ObjcIvarDecl *ivar,
1371 std::string &Result) {
Fariborz Jahanian909f02a2007-11-05 17:47:33 +00001372 Result += "offsetof(struct ";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001373 Result += IDecl->getName();
1374 Result += ", ";
1375 Result += ivar->getName();
1376 Result += ")";
1377}
1378
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001379//===----------------------------------------------------------------------===//
1380// Meta Data Emission
1381//===----------------------------------------------------------------------===//
1382
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001383void RewriteTest::RewriteObjcClassMetaData(ObjcImplementationDecl *IDecl,
1384 std::string &Result) {
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001385 ObjcInterfaceDecl *CDecl = IDecl->getClassInterface();
1386
1387 // Build _objc_ivar_list metadata for classes ivars if needed
1388 int NumIvars = IDecl->getImplDeclNumIvars() > 0
1389 ? IDecl->getImplDeclNumIvars()
1390 : (CDecl ? CDecl->getIntfDeclNumIvars() : 0);
1391
Fariborz Jahanian4d733d32007-10-26 23:09:28 +00001392 SynthesizeObjcInternalStruct(CDecl, Result);
1393
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001394 if (NumIvars > 0) {
1395 static bool objc_ivar = false;
1396 if (!objc_ivar) {
1397 /* struct _objc_ivar {
1398 char *ivar_name;
1399 char *ivar_type;
1400 int ivar_offset;
1401 };
1402 */
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001403 Result += "\nstruct _objc_ivar {\n";
1404 Result += "\tchar *ivar_name;\n";
1405 Result += "\tchar *ivar_type;\n";
1406 Result += "\tint ivar_offset;\n";
1407 Result += "};\n";
1408
1409 /* struct _objc_ivar_list {
1410 int ivar_count;
1411 struct _objc_ivar ivar_list[];
1412 };
1413 */
1414 Result += "\nstruct _objc_ivar_list {\n";
1415 Result += "\tint ivar_count;\n";
1416 Result += "\tstruct _objc_ivar ivar_list[];\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001417 objc_ivar = true;
1418 }
1419
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001420 Result += "\nstatic struct _objc_ivar_list _OBJC_INSTANCE_VARIABLES_";
1421 Result += IDecl->getName();
1422 Result += " __attribute__ ((section (\"__OBJC, __instance_vars\")))= "
1423 "{\n\t";
1424 Result += utostr(NumIvars);
1425 Result += "\n";
1426
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001427 ObjcIvarDecl **Ivars = IDecl->getImplDeclIVars()
1428 ? IDecl->getImplDeclIVars()
1429 : CDecl->getIntfDeclIvars();
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001430 Result += "\t,{{\"";
1431 Result += Ivars[0]->getName();
Fariborz Jahanian160eb652007-10-29 17:16:25 +00001432 Result += "\", \"";
1433 std::string StrEncoding;
1434 Context->getObjcEncodingForType(Ivars[0]->getType(), StrEncoding);
1435 Result += StrEncoding;
1436 Result += "\", ";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001437 SynthesizeIvarOffsetComputation(IDecl, Ivars[0], Result);
1438 Result += "}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001439 for (int i = 1; i < NumIvars; i++) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001440 Result += "\t ,{\"";
1441 Result += Ivars[i]->getName();
Fariborz Jahanian160eb652007-10-29 17:16:25 +00001442 Result += "\", \"";
1443 std::string StrEncoding;
1444 Context->getObjcEncodingForType(Ivars[i]->getType(), StrEncoding);
1445 Result += StrEncoding;
1446 Result += "\", ";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001447 SynthesizeIvarOffsetComputation(IDecl, Ivars[i], Result);
1448 Result += "}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001449 }
1450
1451 Result += "\t }\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001452 }
1453
1454 // Build _objc_method_list for class's instance methods if needed
1455 RewriteObjcMethodsMetaData(IDecl->getInstanceMethods(),
1456 IDecl->getNumInstanceMethods(),
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001457 true,
1458 "", IDecl->getName(), Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001459
1460 // Build _objc_method_list for class's class methods if needed
1461 RewriteObjcMethodsMetaData(IDecl->getClassMethods(),
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +00001462 IDecl->getNumClassMethods(),
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001463 false,
1464 "", IDecl->getName(), Result);
1465
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001466 // Protocols referenced in class declaration?
1467 RewriteObjcProtocolsMetaData(CDecl->getReferencedProtocols(),
1468 CDecl->getNumIntfRefProtocols(),
1469 "CLASS",
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001470 CDecl->getName(), Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001471
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001472
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001473 // Declaration of class/meta-class metadata
1474 /* struct _objc_class {
1475 struct _objc_class *isa; // or const char *root_class_name when metadata
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001476 const char *super_class_name;
1477 char *name;
1478 long version;
1479 long info;
1480 long instance_size;
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001481 struct _objc_ivar_list *ivars;
1482 struct _objc_method_list *methods;
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001483 struct objc_cache *cache;
1484 struct objc_protocol_list *protocols;
1485 const char *ivar_layout;
1486 struct _objc_class_ext *ext;
1487 };
1488 */
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001489 static bool objc_class = false;
1490 if (!objc_class) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001491 Result += "\nstruct _objc_class {\n";
1492 Result += "\tstruct _objc_class *isa;\n";
1493 Result += "\tconst char *super_class_name;\n";
1494 Result += "\tchar *name;\n";
1495 Result += "\tlong version;\n";
1496 Result += "\tlong info;\n";
1497 Result += "\tlong instance_size;\n";
1498 Result += "\tstruct _objc_ivar_list *ivars;\n";
1499 Result += "\tstruct _objc_method_list *methods;\n";
1500 Result += "\tstruct objc_cache *cache;\n";
1501 Result += "\tstruct _objc_protocol_list *protocols;\n";
1502 Result += "\tconst char *ivar_layout;\n";
1503 Result += "\tstruct _objc_class_ext *ext;\n";
1504 Result += "};\n";
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001505 objc_class = true;
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001506 }
1507
1508 // Meta-class metadata generation.
1509 ObjcInterfaceDecl *RootClass = 0;
1510 ObjcInterfaceDecl *SuperClass = CDecl->getSuperClass();
1511 while (SuperClass) {
1512 RootClass = SuperClass;
1513 SuperClass = SuperClass->getSuperClass();
1514 }
1515 SuperClass = CDecl->getSuperClass();
1516
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001517 Result += "\nstatic struct _objc_class _OBJC_METACLASS_";
1518 Result += CDecl->getName();
1519 Result += " __attribute__ ((section (\"__OBJC, __meta_class\")))= "
1520 "{\n\t(struct _objc_class *)\"";
1521 Result += (RootClass ? RootClass->getName() : CDecl->getName());
1522 Result += "\"";
1523
1524 if (SuperClass) {
1525 Result += ", \"";
1526 Result += SuperClass->getName();
1527 Result += "\", \"";
1528 Result += CDecl->getName();
1529 Result += "\"";
1530 }
1531 else {
1532 Result += ", 0, \"";
1533 Result += CDecl->getName();
1534 Result += "\"";
1535 }
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001536 // TODO: 'ivars' field for root class is currently set to 0.
1537 // 'info' field is initialized to CLS_META(2) for metaclass
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001538 Result += ", 0,2, sizeof(struct _objc_class), 0";
1539 if (CDecl->getNumClassMethods() > 0) {
1540 Result += "\n\t, &_OBJC_CLASS_METHODS_";
1541 Result += CDecl->getName();
1542 Result += "\n";
1543 }
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001544 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001545 Result += ", 0\n";
1546 if (CDecl->getNumIntfRefProtocols() > 0) {
1547 Result += "\t,0, &_OBJC_CLASS_PROTOCOLS_";
1548 Result += CDecl->getName();
1549 Result += ",0,0\n";
1550 }
Fariborz Jahanian454cb012007-10-24 20:54:23 +00001551 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001552 Result += "\t,0,0,0,0\n";
1553 Result += "};\n";
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001554
1555 // class metadata generation.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001556 Result += "\nstatic struct _objc_class _OBJC_CLASS_";
1557 Result += CDecl->getName();
1558 Result += " __attribute__ ((section (\"__OBJC, __class\")))= "
1559 "{\n\t&_OBJC_METACLASS_";
1560 Result += CDecl->getName();
1561 if (SuperClass) {
1562 Result += ", \"";
1563 Result += SuperClass->getName();
1564 Result += "\", \"";
1565 Result += CDecl->getName();
1566 Result += "\"";
1567 }
1568 else {
1569 Result += ", 0, \"";
1570 Result += CDecl->getName();
1571 Result += "\"";
1572 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001573 // 'info' field is initialized to CLS_CLASS(1) for class
Fariborz Jahanian4d733d32007-10-26 23:09:28 +00001574 Result += ", 0,1";
1575 if (!ObjcSynthesizedStructs.count(CDecl))
1576 Result += ",0";
1577 else {
1578 // class has size. Must synthesize its size.
Fariborz Jahanian909f02a2007-11-05 17:47:33 +00001579 Result += ",sizeof(struct ";
Fariborz Jahanian4d733d32007-10-26 23:09:28 +00001580 Result += CDecl->getName();
1581 Result += ")";
1582 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001583 if (NumIvars > 0) {
1584 Result += ", &_OBJC_INSTANCE_VARIABLES_";
1585 Result += CDecl->getName();
1586 Result += "\n\t";
1587 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001588 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001589 Result += ",0";
1590 if (IDecl->getNumInstanceMethods() > 0) {
1591 Result += ", &_OBJC_INSTANCE_METHODS_";
1592 Result += CDecl->getName();
1593 Result += ", 0\n\t";
1594 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001595 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001596 Result += ",0,0";
1597 if (CDecl->getNumIntfRefProtocols() > 0) {
1598 Result += ", &_OBJC_CLASS_PROTOCOLS_";
1599 Result += CDecl->getName();
1600 Result += ", 0,0\n";
1601 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001602 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001603 Result += ",0,0,0\n";
1604 Result += "};\n";
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001605}
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00001606
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001607void RewriteTest::WriteObjcMetaData(std::string &Result) {
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001608 int ClsDefCount = ClassImplementation.size();
1609 int CatDefCount = CategoryImplementation.size();
1610 if (ClsDefCount == 0 && CatDefCount == 0)
1611 return;
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00001612
Fariborz Jahanian454cb012007-10-24 20:54:23 +00001613 // TODO: This is temporary until we decide how to access objc types in a
1614 // c program
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001615 Result += "#include <Objc/objc.h>\n";
1616 // This is needed for use of offsetof
1617 Result += "#include <stddef.h>\n";
Fariborz Jahanian454cb012007-10-24 20:54:23 +00001618
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001619 // For each implemented class, write out all its meta data.
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00001620 for (int i = 0; i < ClsDefCount; i++)
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001621 RewriteObjcClassMetaData(ClassImplementation[i], Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001622
1623 // For each implemented category, write out all its meta data.
1624 for (int i = 0; i < CatDefCount; i++)
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001625 RewriteObjcCategoryImplDecl(CategoryImplementation[i], Result);
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00001626
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001627 // Write objc_symtab metadata
1628 /*
1629 struct _objc_symtab
1630 {
1631 long sel_ref_cnt;
1632 SEL *refs;
1633 short cls_def_cnt;
1634 short cat_def_cnt;
1635 void *defs[cls_def_cnt + cat_def_cnt];
1636 };
1637 */
1638
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001639 Result += "\nstruct _objc_symtab {\n";
1640 Result += "\tlong sel_ref_cnt;\n";
1641 Result += "\tSEL *refs;\n";
1642 Result += "\tshort cls_def_cnt;\n";
1643 Result += "\tshort cat_def_cnt;\n";
1644 Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n";
1645 Result += "};\n\n";
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001646
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001647 Result += "static struct _objc_symtab "
1648 "_OBJC_SYMBOLS __attribute__((section (\"__OBJC, __symbols\")))= {\n";
1649 Result += "\t0, 0, " + utostr(ClsDefCount)
1650 + ", " + utostr(CatDefCount) + "\n";
1651 for (int i = 0; i < ClsDefCount; i++) {
1652 Result += "\t,&_OBJC_CLASS_";
1653 Result += ClassImplementation[i]->getName();
1654 Result += "\n";
1655 }
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001656
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001657 for (int i = 0; i < CatDefCount; i++) {
1658 Result += "\t,&_OBJC_CATEGORY_";
1659 Result += CategoryImplementation[i]->getClassInterface()->getName();
1660 Result += "_";
1661 Result += CategoryImplementation[i]->getName();
1662 Result += "\n";
1663 }
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001664
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001665 Result += "};\n\n";
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001666
1667 // Write objc_module metadata
1668
1669 /*
1670 struct _objc_module {
1671 long version;
1672 long size;
1673 const char *name;
1674 struct _objc_symtab *symtab;
1675 }
1676 */
1677
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001678 Result += "\nstruct _objc_module {\n";
1679 Result += "\tlong version;\n";
1680 Result += "\tlong size;\n";
1681 Result += "\tconst char *name;\n";
1682 Result += "\tstruct _objc_symtab *symtab;\n";
1683 Result += "};\n\n";
1684 Result += "static struct _objc_module "
1685 "_OBJC_MODULES __attribute__ ((section (\"__OBJC, __module_info\")))= {\n";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001686 Result += "\t" + utostr(OBJC_ABI_VERSION) +
1687 ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001688 Result += "};\n\n";
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001689}
Chris Lattner311ff022007-10-16 22:36:42 +00001690