blob: 8063574750cd1cdc0ea2a34390fbb7ed7af98e4c [file] [log] [blame]
Chris Lattnerb429ae42007-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 Lattner569faa62007-10-11 18:38:32 +000015#include "clang/Rewrite/Rewriter.h"
Chris Lattnerb429ae42007-10-11 00:43:27 +000016#include "clang/AST/AST.h"
17#include "clang/AST/ASTConsumer.h"
Chris Lattner569faa62007-10-11 18:38:32 +000018#include "clang/Basic/SourceManager.h"
Steve Naroffe9780582007-10-23 23:50:29 +000019#include "clang/Basic/IdentifierTable.h"
Chris Lattnerc3aa5c42007-10-25 17:07:24 +000020#include "llvm/ADT/StringExtras.h"
Fariborz Jahanianf185aef2007-10-26 19:46:17 +000021#include "llvm/ADT/SmallPtrSet.h"
Chris Lattnerb429ae42007-10-11 00:43:27 +000022using namespace clang;
Chris Lattnerc3aa5c42007-10-25 17:07:24 +000023using llvm::utostr;
Chris Lattnerb429ae42007-10-11 00:43:27 +000024
Chris Lattnerb429ae42007-10-11 00:43:27 +000025namespace {
Chris Lattner569faa62007-10-11 18:38:32 +000026 class RewriteTest : public ASTConsumer {
Chris Lattner74db1682007-10-16 21:07:07 +000027 Rewriter Rewrite;
Chris Lattnerbf0bfa62007-10-17 22:35:30 +000028 ASTContext *Context;
Chris Lattnerb429ae42007-10-11 00:43:27 +000029 SourceManager *SM;
Chris Lattner569faa62007-10-11 18:38:32 +000030 unsigned MainFileID;
Chris Lattner74db1682007-10-16 21:07:07 +000031 SourceLocation LastIncLoc;
Fariborz Jahanian640a01f2007-10-18 19:23:00 +000032 llvm::SmallVector<ObjcImplementationDecl *, 8> ClassImplementation;
33 llvm::SmallVector<ObjcCategoryImplDecl *, 8> CategoryImplementation;
Fariborz Jahanianf185aef2007-10-26 19:46:17 +000034 llvm::SmallPtrSet<ObjcInterfaceDecl*, 8> ObjcSynthesizedStructs;
Steve Naroffe9780582007-10-23 23:50:29 +000035
36 FunctionDecl *MsgSendFunctionDecl;
37 FunctionDecl *GetClassFunctionDecl;
Steve Naroff71226032007-10-24 22:48:43 +000038 FunctionDecl *SelGetUidFunctionDecl;
Steve Naroffe9780582007-10-23 23:50:29 +000039
Fariborz Jahanian640a01f2007-10-18 19:23:00 +000040 static const int OBJC_ABI_VERSION =7 ;
Chris Lattnerb429ae42007-10-11 00:43:27 +000041 public:
Chris Lattnerbf0bfa62007-10-17 22:35:30 +000042 void Initialize(ASTContext &context, unsigned mainFileID) {
43 Context = &context;
44 SM = &Context->SourceMgr;
Chris Lattner569faa62007-10-11 18:38:32 +000045 MainFileID = mainFileID;
Steve Naroffe9780582007-10-23 23:50:29 +000046 MsgSendFunctionDecl = 0;
Steve Naroff95b28c12007-10-24 01:09:48 +000047 GetClassFunctionDecl = 0;
Steve Naroff71226032007-10-24 22:48:43 +000048 SelGetUidFunctionDecl = 0;
Chris Lattnerbf0bfa62007-10-17 22:35:30 +000049 Rewrite.setSourceMgr(Context->SourceMgr);
Chris Lattnerb429ae42007-10-11 00:43:27 +000050 }
Chris Lattner569faa62007-10-11 18:38:32 +000051
Chris Lattnerfce2c5a2007-10-24 17:06:59 +000052 // Top Level Driver code.
53 virtual void HandleTopLevelDecl(Decl *D);
Chris Lattner74db1682007-10-16 21:07:07 +000054 void HandleDeclInMainFile(Decl *D);
Chris Lattnerfce2c5a2007-10-24 17:06:59 +000055 ~RewriteTest();
56
57 // Syntactic Rewriting.
Chris Lattner74db1682007-10-16 21:07:07 +000058 void RewriteInclude(SourceLocation Loc);
Chris Lattnerfce2c5a2007-10-24 17:06:59 +000059 void RewriteTabs();
60 void RewriteForwardClassDecl(ObjcClassDecl *Dcl);
Steve Naroff3774dd92007-10-26 20:53:56 +000061 void RewriteInterfaceDecl(ObjcInterfaceDecl *Dcl);
Chris Lattner6fe8b272007-10-16 22:36:42 +000062
Chris Lattnerfce2c5a2007-10-24 17:06:59 +000063 // Expression Rewriting.
Chris Lattner0021f452007-10-24 16:57:36 +000064 Stmt *RewriteFunctionBody(Stmt *S);
65 Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
66 Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
Steve Naroff71226032007-10-24 22:48:43 +000067 CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD,
68 Expr **args, unsigned nargs);
Chris Lattnerfce2c5a2007-10-24 17:06:59 +000069 // Metadata emission.
Fariborz Jahanianf185aef2007-10-26 19:46:17 +000070 void HandleObjcMetaDataEmission();
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +000071 void RewriteObjcClassMetaData(ObjcImplementationDecl *IDecl,
72 std::string &Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +000073
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +000074 void RewriteObjcCategoryImplDecl(ObjcCategoryImplDecl *CDecl,
75 std::string &Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +000076
77 void RewriteObjcMethodsMetaData(ObjcMethodDecl **Methods,
78 int NumMethods,
Fariborz Jahaniana3986372007-10-25 00:14:44 +000079 bool IsInstanceMethod,
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +000080 const char *prefix,
Chris Lattnerc3aa5c42007-10-25 17:07:24 +000081 const char *ClassName,
82 std::string &Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +000083
84 void RewriteObjcProtocolsMetaData(ObjcProtocolDecl **Protocols,
85 int NumProtocols,
86 const char *prefix,
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +000087 const char *ClassName,
88 std::string &Result);
Fariborz Jahanianf185aef2007-10-26 19:46:17 +000089 void SynthesizeObjcInternalStruct(ObjcInterfaceDecl *CDecl,
90 std::string &Result);
Fariborz Jahanianf185aef2007-10-26 19:46:17 +000091 void SynthesizeIvarOffsetComputation(ObjcImplementationDecl *IDecl,
92 ObjcIvarDecl *ivar,
93 std::string &Result);
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +000094 void WriteObjcMetaData(std::string &Result);
Chris Lattnerb429ae42007-10-11 00:43:27 +000095 };
96}
97
Chris Lattner569faa62007-10-11 18:38:32 +000098ASTConsumer *clang::CreateCodeRewriterTest() { return new RewriteTest(); }
Chris Lattnerb429ae42007-10-11 00:43:27 +000099
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000100//===----------------------------------------------------------------------===//
101// Top Level Driver Code
102//===----------------------------------------------------------------------===//
103
Chris Lattner569faa62007-10-11 18:38:32 +0000104void RewriteTest::HandleTopLevelDecl(Decl *D) {
Chris Lattner74db1682007-10-16 21:07:07 +0000105 // Two cases: either the decl could be in the main file, or it could be in a
106 // #included file. If the former, rewrite it now. If the later, check to see
107 // if we rewrote the #include/#import.
108 SourceLocation Loc = D->getLocation();
109 Loc = SM->getLogicalLoc(Loc);
110
111 // If this is for a builtin, ignore it.
112 if (Loc.isInvalid()) return;
113
Steve Naroffe9780582007-10-23 23:50:29 +0000114 // Look for built-in declarations that we need to refer during the rewrite.
115 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Steve Naroff95b28c12007-10-24 01:09:48 +0000116 if (strcmp(FD->getName(), "objc_msgSend") == 0)
Steve Naroffe9780582007-10-23 23:50:29 +0000117 MsgSendFunctionDecl = FD;
Steve Naroff95b28c12007-10-24 01:09:48 +0000118 else if (strcmp(FD->getName(), "objc_getClass") == 0)
Steve Naroffe9780582007-10-23 23:50:29 +0000119 GetClassFunctionDecl = FD;
Steve Naroff71226032007-10-24 22:48:43 +0000120 else if (strcmp(FD->getName(), "sel_getUid") == 0)
121 SelGetUidFunctionDecl = FD;
Steve Naroff3774dd92007-10-26 20:53:56 +0000122 } else if (ObjcInterfaceDecl *MD = dyn_cast<ObjcInterfaceDecl>(D)) {
123 RewriteInterfaceDecl(MD);
Steve Naroffe9780582007-10-23 23:50:29 +0000124 }
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000125 // If we have a decl in the main file, see if we should rewrite it.
Chris Lattner74db1682007-10-16 21:07:07 +0000126 if (SM->getDecomposedFileLoc(Loc).first == MainFileID)
127 return HandleDeclInMainFile(D);
128
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000129 // Otherwise, see if there is a #import in the main file that should be
130 // rewritten.
Chris Lattner74db1682007-10-16 21:07:07 +0000131 RewriteInclude(Loc);
132}
133
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000134/// HandleDeclInMainFile - This is called for each top-level decl defined in the
135/// main file of the input.
136void RewriteTest::HandleDeclInMainFile(Decl *D) {
137 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
138 if (Stmt *Body = FD->getBody())
139 FD->setBody(RewriteFunctionBody(Body));
140
141 if (ObjcImplementationDecl *CI = dyn_cast<ObjcImplementationDecl>(D))
142 ClassImplementation.push_back(CI);
143 else if (ObjcCategoryImplDecl *CI = dyn_cast<ObjcCategoryImplDecl>(D))
144 CategoryImplementation.push_back(CI);
145 else if (ObjcClassDecl *CD = dyn_cast<ObjcClassDecl>(D))
146 RewriteForwardClassDecl(CD);
147 // Nothing yet.
148}
149
150RewriteTest::~RewriteTest() {
151 // Get the top-level buffer that this corresponds to.
152 RewriteTabs();
153
154 // Get the buffer corresponding to MainFileID. If we haven't changed it, then
155 // we are done.
156 if (const RewriteBuffer *RewriteBuf =
157 Rewrite.getRewriteBufferFor(MainFileID)) {
158 printf("Changed:\n");
159 std::string S(RewriteBuf->begin(), RewriteBuf->end());
160 printf("%s\n", S.c_str());
161 } else {
162 printf("No changes\n");
163 }
Fariborz Jahanianf185aef2007-10-26 19:46:17 +0000164
165}
166
167/// HandleObjcMetaDataEmission - main routine to generate objective-c's
168/// metadata.
169void RewriteTest::HandleObjcMetaDataEmission() {
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000170 // Rewrite Objective-c meta data*
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000171 std::string ResultStr;
172 WriteObjcMetaData(ResultStr);
173 // For now just print the string out.
174 printf("%s", ResultStr.c_str());
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000175}
176
177//===----------------------------------------------------------------------===//
178// Syntactic (non-AST) Rewriting Code
179//===----------------------------------------------------------------------===//
180
Chris Lattner74db1682007-10-16 21:07:07 +0000181void RewriteTest::RewriteInclude(SourceLocation Loc) {
182 // Rip up the #include stack to the main file.
183 SourceLocation IncLoc = Loc, NextLoc = Loc;
184 do {
185 IncLoc = Loc;
186 Loc = SM->getLogicalLoc(NextLoc);
187 NextLoc = SM->getIncludeLoc(Loc);
188 } while (!NextLoc.isInvalid());
189
190 // Loc is now the location of the #include filename "foo" or <foo/bar.h>.
191 // IncLoc indicates the header that was included if it is useful.
192 IncLoc = SM->getLogicalLoc(IncLoc);
193 if (SM->getDecomposedFileLoc(Loc).first != MainFileID ||
194 Loc == LastIncLoc)
195 return;
196 LastIncLoc = Loc;
197
198 unsigned IncCol = SM->getColumnNumber(Loc);
199 SourceLocation LineStartLoc = Loc.getFileLocWithOffset(-IncCol+1);
200
201 // Replace the #import with #include.
202 Rewrite.ReplaceText(LineStartLoc, IncCol-1, "#include ", strlen("#include "));
203}
204
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000205void RewriteTest::RewriteTabs() {
206 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
207 const char *MainBufStart = MainBuf.first;
208 const char *MainBufEnd = MainBuf.second;
Fariborz Jahanian640a01f2007-10-18 19:23:00 +0000209
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000210 // Loop over the whole file, looking for tabs.
211 for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) {
212 if (*BufPtr != '\t')
213 continue;
214
215 // Okay, we found a tab. This tab will turn into at least one character,
216 // but it depends on which 'virtual column' it is in. Compute that now.
217 unsigned VCol = 0;
218 while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' &&
219 BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r')
220 ++VCol;
221
222 // Okay, now that we know the virtual column, we know how many spaces to
223 // insert. We assume 8-character tab-stops.
224 unsigned Spaces = 8-(VCol & 7);
225
226 // Get the location of the tab.
227 SourceLocation TabLoc =
228 SourceLocation::getFileLoc(MainFileID, BufPtr-MainBufStart);
229
230 // Rewrite the single tab character into a sequence of spaces.
231 Rewrite.ReplaceText(TabLoc, 1, " ", Spaces);
232 }
Chris Lattner569faa62007-10-11 18:38:32 +0000233}
234
235
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000236void RewriteTest::RewriteForwardClassDecl(ObjcClassDecl *ClassDecl) {
237 int numDecls = ClassDecl->getNumForwardDecls();
238 ObjcInterfaceDecl **ForwardDecls = ClassDecl->getForwardDecls();
239
240 // Get the start location and compute the semi location.
241 SourceLocation startLoc = ClassDecl->getLocation();
242 const char *startBuf = SM->getCharacterData(startLoc);
243 const char *semiPtr = strchr(startBuf, ';');
244
245 // Translate to typedef's that forward reference structs with the same name
246 // as the class. As a convenience, we include the original declaration
247 // as a comment.
248 std::string typedefString;
249 typedefString += "// ";
Steve Naroff71226032007-10-24 22:48:43 +0000250 typedefString.append(startBuf, semiPtr-startBuf+1);
251 typedefString += "\n";
252 for (int i = 0; i < numDecls; i++) {
253 ObjcInterfaceDecl *ForwardDecl = ForwardDecls[i];
254 typedefString += "typedef struct ";
255 typedefString += ForwardDecl->getName();
256 typedefString += " ";
257 typedefString += ForwardDecl->getName();
258 typedefString += ";\n";
259 }
260
261 // Replace the @class with typedefs corresponding to the classes.
262 Rewrite.ReplaceText(startLoc, semiPtr-startBuf+1,
263 typedefString.c_str(), typedefString.size());
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000264}
265
Steve Naroff3774dd92007-10-26 20:53:56 +0000266void RewriteTest::RewriteInterfaceDecl(ObjcInterfaceDecl *ClassDecl) {
Steve Naroffef20ed32007-10-30 02:23:23 +0000267
268 SourceLocation LocStart = ClassDecl->getLocStart();
269 SourceLocation LocEnd = ClassDecl->getLocEnd();
270
271 const char *startBuf = SM->getCharacterData(LocStart);
272 const char *endBuf = SM->getCharacterData(LocEnd);
273
274 // FIXME: need to consider empty class decls (no vars, methods)...
275 // @interface NSConstantString : NSSimpleCString
276 // @end
277
278 if (*endBuf != '>' && *endBuf != '}')
279 // we have an identifier - scan ahead until the end of token.
280 endBuf = strchr(endBuf, ' '); // FIXME: implement correctly.
281
282 std::string ResultStr;
283 SynthesizeObjcInternalStruct(ClassDecl, ResultStr);
284
285 Rewrite.ReplaceText(LocStart, endBuf-startBuf+1,
286 ResultStr.c_str(), ResultStr.size());
287
Steve Naroff3774dd92007-10-26 20:53:56 +0000288 int nInstanceMethods = ClassDecl->getNumInstanceMethods();
289 ObjcMethodDecl **instanceMethods = ClassDecl->getInstanceMethods();
290
291 for (int i = 0; i < nInstanceMethods; i++) {
292 ObjcMethodDecl *instanceMethod = instanceMethods[i];
293 SourceLocation Loc = instanceMethod->getLocStart();
294
295 Rewrite.ReplaceText(Loc, 0, "// ", 3);
296
297 // FIXME: handle methods that are declared across multiple lines.
298 }
299 int nClassMethods = ClassDecl->getNumClassMethods();
300 ObjcMethodDecl **classMethods = ClassDecl->getClassMethods();
301
302 for (int i = 0; i < nClassMethods; i++) {
303 ObjcMethodDecl *classMethod = classMethods[i];
304 SourceLocation Loc = classMethod->getLocStart();
305
306 Rewrite.ReplaceText(Loc, 0, "// ", 3);
307
308 // FIXME: handle methods that are declared across multiple lines.
309 }
310}
311
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000312//===----------------------------------------------------------------------===//
313// Function Body / Expression rewriting
314//===----------------------------------------------------------------------===//
315
Chris Lattner0021f452007-10-24 16:57:36 +0000316Stmt *RewriteTest::RewriteFunctionBody(Stmt *S) {
Chris Lattner6fe8b272007-10-16 22:36:42 +0000317 // Otherwise, just rewrite all children.
318 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
319 CI != E; ++CI)
Chris Lattnere33506b2007-10-17 21:28:00 +0000320 if (*CI)
Chris Lattner0021f452007-10-24 16:57:36 +0000321 *CI = RewriteFunctionBody(*CI);
Steve Naroffe9780582007-10-23 23:50:29 +0000322
323 // Handle specific things.
324 if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
325 return RewriteAtEncode(AtEncode);
326
Steve Naroff71226032007-10-24 22:48:43 +0000327 if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {
328 // Before we rewrite it, put the original message expression in a comment.
329 SourceLocation startLoc = MessExpr->getLocStart();
330 SourceLocation endLoc = MessExpr->getLocEnd();
331
332 const char *startBuf = SM->getCharacterData(startLoc);
333 const char *endBuf = SM->getCharacterData(endLoc);
334
335 std::string messString;
336 messString += "// ";
337 messString.append(startBuf, endBuf-startBuf+1);
338 messString += "\n";
Steve Naroff3774dd92007-10-26 20:53:56 +0000339
Steve Naroff71226032007-10-24 22:48:43 +0000340 // FIXME: Missing definition of Rewrite.InsertText(clang::SourceLocation, char const*, unsigned int).
341 // Rewrite.InsertText(startLoc, messString.c_str(), messString.size());
342 // Tried this, but it didn't work either...
Steve Naroff3774dd92007-10-26 20:53:56 +0000343 Rewrite.ReplaceText(startLoc, 0, messString.c_str(), messString.size());
Steve Naroffe9780582007-10-23 23:50:29 +0000344 return RewriteMessageExpr(MessExpr);
Steve Naroff71226032007-10-24 22:48:43 +0000345 }
Chris Lattner0021f452007-10-24 16:57:36 +0000346 // Return this stmt unmodified.
347 return S;
Chris Lattner6fe8b272007-10-16 22:36:42 +0000348}
Fariborz Jahanian45d52f72007-10-18 22:09:03 +0000349
Chris Lattner0021f452007-10-24 16:57:36 +0000350Stmt *RewriteTest::RewriteAtEncode(ObjCEncodeExpr *Exp) {
Chris Lattnerbf0bfa62007-10-17 22:35:30 +0000351 // Create a new string expression.
352 QualType StrType = Context->getPointerType(Context->CharTy);
Anders Carlsson36f07d82007-10-29 05:01:08 +0000353 std::string StrEncoding;
354 Context->getObjcEncodingForType(Exp->getEncodedType(), StrEncoding);
355 Expr *Replacement = new StringLiteral(StrEncoding.c_str(),
356 StrEncoding.length(), false, StrType,
Chris Lattnerbf0bfa62007-10-17 22:35:30 +0000357 SourceLocation(), SourceLocation());
358 Rewrite.ReplaceStmt(Exp, Replacement);
Chris Lattner0021f452007-10-24 16:57:36 +0000359 delete Exp;
360 return Replacement;
Chris Lattner6fe8b272007-10-16 22:36:42 +0000361}
362
Steve Naroff71226032007-10-24 22:48:43 +0000363CallExpr *RewriteTest::SynthesizeCallToFunctionDecl(
364 FunctionDecl *FD, Expr **args, unsigned nargs) {
Steve Naroffe9780582007-10-23 23:50:29 +0000365 // Get the type, we will need to reference it in a couple spots.
Steve Naroff71226032007-10-24 22:48:43 +0000366 QualType msgSendType = FD->getType();
Steve Naroffe9780582007-10-23 23:50:29 +0000367
368 // Create a reference to the objc_msgSend() declaration.
Steve Naroff71226032007-10-24 22:48:43 +0000369 DeclRefExpr *DRE = new DeclRefExpr(FD, msgSendType, SourceLocation());
Steve Naroffe9780582007-10-23 23:50:29 +0000370
371 // Now, we cast the reference to a pointer to the objc_msgSend type.
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000372 QualType pToFunc = Context->getPointerType(msgSendType);
Steve Naroffe9780582007-10-23 23:50:29 +0000373 ImplicitCastExpr *ICE = new ImplicitCastExpr(pToFunc, DRE);
374
375 const FunctionType *FT = msgSendType->getAsFunctionType();
Chris Lattner0021f452007-10-24 16:57:36 +0000376
Steve Naroff71226032007-10-24 22:48:43 +0000377 return new CallExpr(ICE, args, nargs, FT->getResultType(), SourceLocation());
378}
379
380Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) {
381 assert(MsgSendFunctionDecl && "Can't find objc_msgSend() decl");
382 assert(SelGetUidFunctionDecl && "Can't find sel_getUid() decl");
383 assert(GetClassFunctionDecl && "Can't find objc_getClass() decl");
384
385 // Synthesize a call to objc_msgSend().
386 llvm::SmallVector<Expr*, 8> MsgExprs;
387 IdentifierInfo *clsName = Exp->getClassName();
388
389 // Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend().
390 if (clsName) { // class message.
391 llvm::SmallVector<Expr*, 8> ClsExprs;
392 QualType argType = Context->getPointerType(Context->CharTy);
393 ClsExprs.push_back(new StringLiteral(clsName->getName(),
394 clsName->getLength(),
395 false, argType, SourceLocation(),
396 SourceLocation()));
397 CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
398 &ClsExprs[0], ClsExprs.size());
399 MsgExprs.push_back(Cls);
400 } else // instance message.
401 MsgExprs.push_back(Exp->getReceiver());
402
403 // Create a call to sel_getUid("selName"), it will be the 2nd argument.
404 llvm::SmallVector<Expr*, 8> SelExprs;
405 QualType argType = Context->getPointerType(Context->CharTy);
406 SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
407 Exp->getSelector().getName().size(),
408 false, argType, SourceLocation(),
409 SourceLocation()));
410 CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
411 &SelExprs[0], SelExprs.size());
412 MsgExprs.push_back(SelExp);
413
414 // Now push any user supplied arguments.
415 for (unsigned i = 0; i < Exp->getNumArgs(); i++) {
416 MsgExprs.push_back(Exp->getArg(i));
417 // We've transferred the ownership to MsgExprs. Null out the argument in
418 // the original expression, since we will delete it below.
419 Exp->setArg(i, 0);
420 }
421 CallExpr *MessExp = SynthesizeCallToFunctionDecl(MsgSendFunctionDecl,
422 &MsgExprs[0], MsgExprs.size());
423 // Now do the actual rewrite.
424 Rewrite.ReplaceStmt(Exp, MessExp);
425
Chris Lattner0021f452007-10-24 16:57:36 +0000426 delete Exp;
Steve Naroff71226032007-10-24 22:48:43 +0000427 return MessExp;
Steve Naroffe9780582007-10-23 23:50:29 +0000428}
429
Fariborz Jahanianf185aef2007-10-26 19:46:17 +0000430/// SynthesizeObjcInternalStruct - Rewrite one internal struct corresponding to
431/// an objective-c class with ivars.
432void RewriteTest::SynthesizeObjcInternalStruct(ObjcInterfaceDecl *CDecl,
433 std::string &Result) {
434 assert(CDecl && "Class missing in SynthesizeObjcInternalStruct");
435 assert(CDecl->getName() && "Name missing in SynthesizeObjcInternalStruct");
436 ObjcInterfaceDecl *RCDecl = CDecl->getSuperClass();
437 if (RCDecl && !ObjcSynthesizedStructs.count(RCDecl)) {
438 // Do it for the root
439 SynthesizeObjcInternalStruct(RCDecl, Result);
440 }
441
442 int NumIvars = CDecl->getIntfDeclNumIvars();
443 if (NumIvars <= 0 && (!RCDecl || !ObjcSynthesizedStructs.count(RCDecl)))
444 return;
445
446 Result += "\nstruct _interface_";
447 Result += CDecl->getName();
448 Result += " {\n";
449 if (RCDecl && ObjcSynthesizedStructs.count(RCDecl)) {
450 Result += "\tstruct _interface_";
451 Result += RCDecl->getName();
452 Result += " _";
453 Result += RCDecl->getName();
454 Result += ";\n";
455 }
456
457 ObjcIvarDecl **Ivars = CDecl->getIntfDeclIvars();
458 for (int i = 0; i < NumIvars; i++) {
459 Result += "\t";
460 std::string Name = Ivars[i]->getName();
461 Ivars[i]->getType().getAsStringInternal(Name);
462 Result += Name;
463 Result += ";\n";
464 }
465 Result += "};\n";
466 // Mark this struct as having been generated.
467 if (!ObjcSynthesizedStructs.insert(CDecl))
468 assert(true && "struct already synthesize- SynthesizeObjcInternalStruct");
469}
470
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000471// RewriteObjcMethodsMetaData - Rewrite methods metadata for instance or
472/// class methods.
473void RewriteTest::RewriteObjcMethodsMetaData(ObjcMethodDecl **Methods,
474 int NumMethods,
Fariborz Jahaniana3986372007-10-25 00:14:44 +0000475 bool IsInstanceMethod,
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000476 const char *prefix,
Chris Lattnerc3aa5c42007-10-25 17:07:24 +0000477 const char *ClassName,
478 std::string &Result) {
Fariborz Jahanian04455192007-10-22 21:41:37 +0000479 static bool objc_impl_method = false;
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000480 if (NumMethods > 0 && !objc_impl_method) {
481 /* struct _objc_method {
Fariborz Jahanian04455192007-10-22 21:41:37 +0000482 SEL _cmd;
483 char *method_types;
484 void *_imp;
485 }
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000486 */
Chris Lattnerc3aa5c42007-10-25 17:07:24 +0000487 Result += "\nstruct _objc_method {\n";
488 Result += "\tSEL _cmd;\n";
489 Result += "\tchar *method_types;\n";
490 Result += "\tvoid *_imp;\n";
491 Result += "};\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000492
493 /* struct _objc_method_list {
494 struct _objc_method_list *next_method;
495 int method_count;
496 struct _objc_method method_list[];
497 }
498 */
499 Result += "\nstruct _objc_method_list {\n";
500 Result += "\tstruct _objc_method_list *next_method;\n";
501 Result += "\tint method_count;\n";
502 Result += "\tstruct _objc_method method_list[];\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000503 objc_impl_method = true;
Fariborz Jahanian96b55da2007-10-19 00:36:46 +0000504 }
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000505 // Build _objc_method_list for class's methods if needed
506 if (NumMethods > 0) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000507 Result += "\nstatic struct _objc_method_list _OBJC_";
Chris Lattnerc3aa5c42007-10-25 17:07:24 +0000508 Result += prefix;
509 Result += IsInstanceMethod ? "INSTANCE" : "CLASS";
510 Result += "_METHODS_";
511 Result += ClassName;
512 Result += " __attribute__ ((section (\"__OBJC, __";
513 Result += IsInstanceMethod ? "inst" : "cls";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000514 Result += "_meth\")))= ";
515 Result += "{\n\t0, " + utostr(NumMethods) + "\n";
516
517 Result += "\t,{{(SEL)\"";
518 Result += Methods[0]->getSelector().getName().c_str();
Fariborz Jahanianc81f3162007-10-29 22:57:28 +0000519 std::string MethodTypeString;
520 Context->getObjcEncodingForMethodDecl(Methods[0], MethodTypeString);
521 Result += "\", \"";
522 Result += MethodTypeString;
523 Result += "\", 0}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000524 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahanianc81f3162007-10-29 22:57:28 +0000525 // TODO: Need method address as 3rd initializer.
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000526 Result += "\t ,{(SEL)\"";
527 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanianc81f3162007-10-29 22:57:28 +0000528 std::string MethodTypeString;
529 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
530 Result += "\", \"";
531 Result += MethodTypeString;
532 Result += "\", 0}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000533 }
534 Result += "\t }\n};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +0000535 }
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000536}
537
538/// RewriteObjcProtocolsMetaData - Rewrite protocols meta-data.
539void RewriteTest::RewriteObjcProtocolsMetaData(ObjcProtocolDecl **Protocols,
540 int NumProtocols,
541 const char *prefix,
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000542 const char *ClassName,
543 std::string &Result) {
Fariborz Jahanian04455192007-10-22 21:41:37 +0000544 static bool objc_protocol_methods = false;
Fariborz Jahanian04455192007-10-22 21:41:37 +0000545 if (NumProtocols > 0) {
Fariborz Jahanian04455192007-10-22 21:41:37 +0000546 for (int i = 0; i < NumProtocols; i++) {
547 ObjcProtocolDecl *PDecl = Protocols[i];
548 // Output struct protocol_methods holder of method selector and type.
549 if (!objc_protocol_methods &&
550 (PDecl->getNumInstanceMethods() > 0
551 || PDecl->getNumClassMethods() > 0)) {
552 /* struct protocol_methods {
553 SEL _cmd;
554 char *method_types;
555 }
556 */
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000557 Result += "\nstruct protocol_methods {\n";
558 Result += "\tSEL _cmd;\n";
559 Result += "\tchar *method_types;\n";
560 Result += "};\n";
561
562 /* struct _objc_protocol_method_list {
563 int protocol_method_count;
564 struct protocol_methods protocols[];
565 }
566 */
567 Result += "\nstruct _objc_protocol_method_list {\n";
568 Result += "\tint protocol_method_count;\n";
569 Result += "\tstruct protocol_methods protocols[];\n};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +0000570 objc_protocol_methods = true;
571 }
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000572
Fariborz Jahanian04455192007-10-22 21:41:37 +0000573 // Output instance methods declared in this protocol.
Fariborz Jahanian04455192007-10-22 21:41:37 +0000574 int NumMethods = PDecl->getNumInstanceMethods();
575 if (NumMethods > 0) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000576 Result += "\nstatic struct _objc_protocol_method_list "
577 "_OBJC_PROTOCOL_INSTANCE_METHODS_";
578 Result += PDecl->getName();
579 Result += " __attribute__ ((section (\"__OBJC, __cat_inst_meth\")))= "
580 "{\n\t" + utostr(NumMethods) + "\n";
581
Fariborz Jahanian04455192007-10-22 21:41:37 +0000582 ObjcMethodDecl **Methods = PDecl->getInstanceMethods();
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000583 Result += "\t,{{(SEL)\"";
584 Result += Methods[0]->getSelector().getName().c_str();
585 Result += "\", \"\"}\n";
586
587 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000588 Result += "\t ,{(SEL)\"";
589 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanianc81f3162007-10-29 22:57:28 +0000590 std::string MethodTypeString;
591 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
592 Result += "\", \"";
593 Result += MethodTypeString;
594 Result += "\"}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000595 }
596 Result += "\t }\n};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +0000597 }
598
599 // Output class methods declared in this protocol.
600 NumMethods = PDecl->getNumClassMethods();
601 if (NumMethods > 0) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000602 Result += "\nstatic struct _objc_protocol_method_list "
603 "_OBJC_PROTOCOL_CLASS_METHODS_";
604 Result += PDecl->getName();
605 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
606 "{\n\t";
607 Result += utostr(NumMethods);
608 Result += "\n";
609
Fariborz Jahanian04455192007-10-22 21:41:37 +0000610 ObjcMethodDecl **Methods = PDecl->getClassMethods();
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000611 Result += "\t,{{(SEL)\"";
612 Result += Methods[0]->getSelector().getName().c_str();
613 Result += "\", \"\"}\n";
614
615 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000616 Result += "\t ,{(SEL)\"";
617 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanianc81f3162007-10-29 22:57:28 +0000618 std::string MethodTypeString;
619 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
620 Result += "\", \"";
621 Result += MethodTypeString;
622 Result += "\"}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000623 }
624 Result += "\t }\n};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +0000625 }
626 // Output:
627 /* struct _objc_protocol {
628 // Objective-C 1.0 extensions
629 struct _objc_protocol_extension *isa;
630 char *protocol_name;
631 struct _objc_protocol **protocol_list;
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000632 struct _objc_protocol_method_list *instance_methods;
633 struct _objc_protocol_method_list *class_methods;
Fariborz Jahanian04455192007-10-22 21:41:37 +0000634 };
635 */
636 static bool objc_protocol = false;
637 if (!objc_protocol) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000638 Result += "\nstruct _objc_protocol {\n";
639 Result += "\tstruct _objc_protocol_extension *isa;\n";
640 Result += "\tchar *protocol_name;\n";
641 Result += "\tstruct _objc_protocol **protocol_list;\n";
642 Result += "\tstruct _objc_protocol_method_list *instance_methods;\n";
643 Result += "\tstruct _objc_protocol_method_list *class_methods;\n";
644 Result += "};\n";
645
646 /* struct _objc_protocol_list {
647 struct _objc_protocol_list *next;
648 int protocol_count;
649 struct _objc_protocol *class_protocols[];
650 }
651 */
652 Result += "\nstruct _objc_protocol_list {\n";
653 Result += "\tstruct _objc_protocol_list *next;\n";
654 Result += "\tint protocol_count;\n";
655 Result += "\tstruct _objc_protocol *class_protocols[];\n";
656 Result += "};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +0000657 objc_protocol = true;
658 }
659
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000660 Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_";
661 Result += PDecl->getName();
662 Result += " __attribute__ ((section (\"__OBJC, __protocol\")))= "
663 "{\n\t0, \"";
664 Result += PDecl->getName();
665 Result += "\", 0, ";
666 if (PDecl->getInstanceMethods() > 0) {
667 Result += "&_OBJC_PROTOCOL_INSTANCE_METHODS_";
668 Result += PDecl->getName();
669 Result += ", ";
670 }
Fariborz Jahanian04455192007-10-22 21:41:37 +0000671 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000672 Result += "0, ";
673 if (PDecl->getClassMethods() > 0) {
674 Result += "&_OBJC_PROTOCOL_CLASS_METHODS_";
675 Result += PDecl->getName();
676 Result += "\n";
677 }
Fariborz Jahanian04455192007-10-22 21:41:37 +0000678 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000679 Result += "0\n";
680 Result += "};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +0000681 }
Fariborz Jahanian04455192007-10-22 21:41:37 +0000682 // Output the top lovel protocol meta-data for the class.
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000683 Result += "\nstatic struct _objc_protocol_list _OBJC_";
684 Result += prefix;
685 Result += "_PROTOCOLS_";
686 Result += ClassName;
687 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
688 "{\n\t0, ";
689 Result += utostr(NumProtocols);
690 Result += "\n";
691
692 Result += "\t,{&_OBJC_PROTOCOL_";
693 Result += Protocols[0]->getName();
694 Result += " \n";
695
696 for (int i = 1; i < NumProtocols; i++) {
Fariborz Jahanian04455192007-10-22 21:41:37 +0000697 ObjcProtocolDecl *PDecl = Protocols[i];
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000698 Result += "\t ,&_OBJC_PROTOCOL_";
699 Result += PDecl->getName();
700 Result += "\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +0000701 }
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000702 Result += "\t }\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000703 }
704}
705
706/// RewriteObjcCategoryImplDecl - Rewrite metadata for each category
707/// implementation.
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000708void RewriteTest::RewriteObjcCategoryImplDecl(ObjcCategoryImplDecl *IDecl,
709 std::string &Result) {
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000710 ObjcInterfaceDecl *ClassDecl = IDecl->getClassInterface();
711 // Find category declaration for this implementation.
712 ObjcCategoryDecl *CDecl;
713 for (CDecl = ClassDecl->getCategoryList(); CDecl;
714 CDecl = CDecl->getNextClassCategory())
715 if (CDecl->getIdentifier() == IDecl->getIdentifier())
716 break;
717 assert(CDecl && "RewriteObjcCategoryImplDecl - bad category");
718
719 char *FullCategoryName = (char*)alloca(
720 strlen(ClassDecl->getName()) + strlen(IDecl->getName()) + 2);
721 sprintf(FullCategoryName, "%s_%s", ClassDecl->getName(), IDecl->getName());
722
723 // Build _objc_method_list for class's instance methods if needed
724 RewriteObjcMethodsMetaData(IDecl->getInstanceMethods(),
725 IDecl->getNumInstanceMethods(),
Fariborz Jahaniana3986372007-10-25 00:14:44 +0000726 true,
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000727 "CATEGORY_", FullCategoryName, Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000728
729 // Build _objc_method_list for class's class methods if needed
730 RewriteObjcMethodsMetaData(IDecl->getClassMethods(),
731 IDecl->getNumClassMethods(),
Fariborz Jahaniana3986372007-10-25 00:14:44 +0000732 false,
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000733 "CATEGORY_", FullCategoryName, Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000734
735 // Protocols referenced in class declaration?
736 RewriteObjcProtocolsMetaData(CDecl->getReferencedProtocols(),
737 CDecl->getNumReferencedProtocols(),
738 "CATEGORY",
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000739 FullCategoryName, Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000740
741 /* struct _objc_category {
742 char *category_name;
743 char *class_name;
744 struct _objc_method_list *instance_methods;
745 struct _objc_method_list *class_methods;
746 struct _objc_protocol_list *protocols;
747 // Objective-C 1.0 extensions
748 uint32_t size; // sizeof (struct _objc_category)
749 struct _objc_property_list *instance_properties; // category's own
750 // @property decl.
751 };
752 */
753
754 static bool objc_category = false;
755 if (!objc_category) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000756 Result += "\nstruct _objc_category {\n";
757 Result += "\tchar *category_name;\n";
758 Result += "\tchar *class_name;\n";
759 Result += "\tstruct _objc_method_list *instance_methods;\n";
760 Result += "\tstruct _objc_method_list *class_methods;\n";
761 Result += "\tstruct _objc_protocol_list *protocols;\n";
762 Result += "\tunsigned int size;\n";
763 Result += "\tstruct _objc_property_list *instance_properties;\n";
764 Result += "};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000765 objc_category = true;
Fariborz Jahanian04455192007-10-22 21:41:37 +0000766 }
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000767 Result += "\nstatic struct _objc_category _OBJC_CATEGORY_";
768 Result += FullCategoryName;
769 Result += " __attribute__ ((section (\"__OBJC, __category\")))= {\n\t\"";
770 Result += IDecl->getName();
771 Result += "\"\n\t, \"";
772 Result += ClassDecl->getName();
773 Result += "\"\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000774
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000775 if (IDecl->getNumInstanceMethods() > 0) {
776 Result += "\t, (struct _objc_method_list *)"
777 "&_OBJC_CATEGORY_INSTANCE_METHODS_";
778 Result += FullCategoryName;
779 Result += "\n";
780 }
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000781 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000782 Result += "\t, 0\n";
783 if (IDecl->getNumClassMethods() > 0) {
784 Result += "\t, (struct _objc_method_list *)"
785 "&_OBJC_CATEGORY_CLASS_METHODS_";
786 Result += FullCategoryName;
787 Result += "\n";
788 }
789 else
790 Result += "\t, 0\n";
791
792 if (CDecl->getNumReferencedProtocols() > 0) {
793 Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";
794 Result += FullCategoryName;
795 Result += "\n";
796 }
797 else
798 Result += "\t, 0\n";
799 Result += "\t, sizeof(struct _objc_category), 0\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000800}
801
Fariborz Jahanianf185aef2007-10-26 19:46:17 +0000802/// SynthesizeIvarOffsetComputation - This rutine synthesizes computation of
803/// ivar offset.
804void RewriteTest::SynthesizeIvarOffsetComputation(ObjcImplementationDecl *IDecl,
805 ObjcIvarDecl *ivar,
806 std::string &Result) {
807 Result += "offsetof(struct _interface_";
808 Result += IDecl->getName();
809 Result += ", ";
810 Result += ivar->getName();
811 Result += ")";
812}
813
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000814//===----------------------------------------------------------------------===//
815// Meta Data Emission
816//===----------------------------------------------------------------------===//
817
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000818void RewriteTest::RewriteObjcClassMetaData(ObjcImplementationDecl *IDecl,
819 std::string &Result) {
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000820 ObjcInterfaceDecl *CDecl = IDecl->getClassInterface();
821
822 // Build _objc_ivar_list metadata for classes ivars if needed
823 int NumIvars = IDecl->getImplDeclNumIvars() > 0
824 ? IDecl->getImplDeclNumIvars()
825 : (CDecl ? CDecl->getIntfDeclNumIvars() : 0);
826
Fariborz Jahanianab3ec252007-10-26 23:09:28 +0000827 SynthesizeObjcInternalStruct(CDecl, Result);
828
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000829 if (NumIvars > 0) {
830 static bool objc_ivar = false;
831 if (!objc_ivar) {
832 /* struct _objc_ivar {
833 char *ivar_name;
834 char *ivar_type;
835 int ivar_offset;
836 };
837 */
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000838 Result += "\nstruct _objc_ivar {\n";
839 Result += "\tchar *ivar_name;\n";
840 Result += "\tchar *ivar_type;\n";
841 Result += "\tint ivar_offset;\n";
842 Result += "};\n";
843
844 /* struct _objc_ivar_list {
845 int ivar_count;
846 struct _objc_ivar ivar_list[];
847 };
848 */
849 Result += "\nstruct _objc_ivar_list {\n";
850 Result += "\tint ivar_count;\n";
851 Result += "\tstruct _objc_ivar ivar_list[];\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000852 objc_ivar = true;
853 }
854
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000855 Result += "\nstatic struct _objc_ivar_list _OBJC_INSTANCE_VARIABLES_";
856 Result += IDecl->getName();
857 Result += " __attribute__ ((section (\"__OBJC, __instance_vars\")))= "
858 "{\n\t";
859 Result += utostr(NumIvars);
860 Result += "\n";
861
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000862 ObjcIvarDecl **Ivars = IDecl->getImplDeclIVars()
863 ? IDecl->getImplDeclIVars()
864 : CDecl->getIntfDeclIvars();
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000865 Result += "\t,{{\"";
866 Result += Ivars[0]->getName();
Fariborz Jahaniand5ea4612007-10-29 17:16:25 +0000867 Result += "\", \"";
868 std::string StrEncoding;
869 Context->getObjcEncodingForType(Ivars[0]->getType(), StrEncoding);
870 Result += StrEncoding;
871 Result += "\", ";
Fariborz Jahanianf185aef2007-10-26 19:46:17 +0000872 SynthesizeIvarOffsetComputation(IDecl, Ivars[0], Result);
873 Result += "}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000874 for (int i = 1; i < NumIvars; i++) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000875 Result += "\t ,{\"";
876 Result += Ivars[i]->getName();
Fariborz Jahaniand5ea4612007-10-29 17:16:25 +0000877 Result += "\", \"";
878 std::string StrEncoding;
879 Context->getObjcEncodingForType(Ivars[i]->getType(), StrEncoding);
880 Result += StrEncoding;
881 Result += "\", ";
Fariborz Jahanianf185aef2007-10-26 19:46:17 +0000882 SynthesizeIvarOffsetComputation(IDecl, Ivars[i], Result);
883 Result += "}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000884 }
885
886 Result += "\t }\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000887 }
888
889 // Build _objc_method_list for class's instance methods if needed
890 RewriteObjcMethodsMetaData(IDecl->getInstanceMethods(),
891 IDecl->getNumInstanceMethods(),
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000892 true,
893 "", IDecl->getName(), Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000894
895 // Build _objc_method_list for class's class methods if needed
896 RewriteObjcMethodsMetaData(IDecl->getClassMethods(),
Fariborz Jahaniana3986372007-10-25 00:14:44 +0000897 IDecl->getNumClassMethods(),
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000898 false,
899 "", IDecl->getName(), Result);
900
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000901 // Protocols referenced in class declaration?
902 RewriteObjcProtocolsMetaData(CDecl->getReferencedProtocols(),
903 CDecl->getNumIntfRefProtocols(),
904 "CLASS",
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000905 CDecl->getName(), Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000906
Fariborz Jahanian0f013d12007-10-23 00:02:02 +0000907
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +0000908 // Declaration of class/meta-class metadata
909 /* struct _objc_class {
910 struct _objc_class *isa; // or const char *root_class_name when metadata
Fariborz Jahanian0f013d12007-10-23 00:02:02 +0000911 const char *super_class_name;
912 char *name;
913 long version;
914 long info;
915 long instance_size;
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +0000916 struct _objc_ivar_list *ivars;
917 struct _objc_method_list *methods;
Fariborz Jahanian0f013d12007-10-23 00:02:02 +0000918 struct objc_cache *cache;
919 struct objc_protocol_list *protocols;
920 const char *ivar_layout;
921 struct _objc_class_ext *ext;
922 };
923 */
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +0000924 static bool objc_class = false;
925 if (!objc_class) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000926 Result += "\nstruct _objc_class {\n";
927 Result += "\tstruct _objc_class *isa;\n";
928 Result += "\tconst char *super_class_name;\n";
929 Result += "\tchar *name;\n";
930 Result += "\tlong version;\n";
931 Result += "\tlong info;\n";
932 Result += "\tlong instance_size;\n";
933 Result += "\tstruct _objc_ivar_list *ivars;\n";
934 Result += "\tstruct _objc_method_list *methods;\n";
935 Result += "\tstruct objc_cache *cache;\n";
936 Result += "\tstruct _objc_protocol_list *protocols;\n";
937 Result += "\tconst char *ivar_layout;\n";
938 Result += "\tstruct _objc_class_ext *ext;\n";
939 Result += "};\n";
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +0000940 objc_class = true;
Fariborz Jahanian0f013d12007-10-23 00:02:02 +0000941 }
942
943 // Meta-class metadata generation.
944 ObjcInterfaceDecl *RootClass = 0;
945 ObjcInterfaceDecl *SuperClass = CDecl->getSuperClass();
946 while (SuperClass) {
947 RootClass = SuperClass;
948 SuperClass = SuperClass->getSuperClass();
949 }
950 SuperClass = CDecl->getSuperClass();
951
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000952 Result += "\nstatic struct _objc_class _OBJC_METACLASS_";
953 Result += CDecl->getName();
954 Result += " __attribute__ ((section (\"__OBJC, __meta_class\")))= "
955 "{\n\t(struct _objc_class *)\"";
956 Result += (RootClass ? RootClass->getName() : CDecl->getName());
957 Result += "\"";
958
959 if (SuperClass) {
960 Result += ", \"";
961 Result += SuperClass->getName();
962 Result += "\", \"";
963 Result += CDecl->getName();
964 Result += "\"";
965 }
966 else {
967 Result += ", 0, \"";
968 Result += CDecl->getName();
969 Result += "\"";
970 }
Fariborz Jahanian0f013d12007-10-23 00:02:02 +0000971 // TODO: 'ivars' field for root class is currently set to 0.
972 // 'info' field is initialized to CLS_META(2) for metaclass
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000973 Result += ", 0,2, sizeof(struct _objc_class), 0";
974 if (CDecl->getNumClassMethods() > 0) {
975 Result += "\n\t, &_OBJC_CLASS_METHODS_";
976 Result += CDecl->getName();
977 Result += "\n";
978 }
Fariborz Jahanian0f013d12007-10-23 00:02:02 +0000979 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000980 Result += ", 0\n";
981 if (CDecl->getNumIntfRefProtocols() > 0) {
982 Result += "\t,0, &_OBJC_CLASS_PROTOCOLS_";
983 Result += CDecl->getName();
984 Result += ",0,0\n";
985 }
Fariborz Jahanian0cb4d922007-10-24 20:54:23 +0000986 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000987 Result += "\t,0,0,0,0\n";
988 Result += "};\n";
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +0000989
990 // class metadata generation.
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000991 Result += "\nstatic struct _objc_class _OBJC_CLASS_";
992 Result += CDecl->getName();
993 Result += " __attribute__ ((section (\"__OBJC, __class\")))= "
994 "{\n\t&_OBJC_METACLASS_";
995 Result += CDecl->getName();
996 if (SuperClass) {
997 Result += ", \"";
998 Result += SuperClass->getName();
999 Result += "\", \"";
1000 Result += CDecl->getName();
1001 Result += "\"";
1002 }
1003 else {
1004 Result += ", 0, \"";
1005 Result += CDecl->getName();
1006 Result += "\"";
1007 }
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00001008 // 'info' field is initialized to CLS_CLASS(1) for class
Fariborz Jahanianab3ec252007-10-26 23:09:28 +00001009 Result += ", 0,1";
1010 if (!ObjcSynthesizedStructs.count(CDecl))
1011 Result += ",0";
1012 else {
1013 // class has size. Must synthesize its size.
1014 Result += ",sizeof(struct _interface_";
1015 Result += CDecl->getName();
1016 Result += ")";
1017 }
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001018 if (NumIvars > 0) {
1019 Result += ", &_OBJC_INSTANCE_VARIABLES_";
1020 Result += CDecl->getName();
1021 Result += "\n\t";
1022 }
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00001023 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001024 Result += ",0";
1025 if (IDecl->getNumInstanceMethods() > 0) {
1026 Result += ", &_OBJC_INSTANCE_METHODS_";
1027 Result += CDecl->getName();
1028 Result += ", 0\n\t";
1029 }
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00001030 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001031 Result += ",0,0";
1032 if (CDecl->getNumIntfRefProtocols() > 0) {
1033 Result += ", &_OBJC_CLASS_PROTOCOLS_";
1034 Result += CDecl->getName();
1035 Result += ", 0,0\n";
1036 }
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00001037 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001038 Result += ",0,0,0\n";
1039 Result += "};\n";
Fariborz Jahanian0f013d12007-10-23 00:02:02 +00001040}
Fariborz Jahanian45d52f72007-10-18 22:09:03 +00001041
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001042void RewriteTest::WriteObjcMetaData(std::string &Result) {
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00001043 int ClsDefCount = ClassImplementation.size();
1044 int CatDefCount = CategoryImplementation.size();
1045 if (ClsDefCount == 0 && CatDefCount == 0)
1046 return;
Fariborz Jahanian45d52f72007-10-18 22:09:03 +00001047
Fariborz Jahanian0cb4d922007-10-24 20:54:23 +00001048 // TODO: This is temporary until we decide how to access objc types in a
1049 // c program
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00001050 Result += "#include <Objc/objc.h>\n";
1051 // This is needed for use of offsetof
1052 Result += "#include <stddef.h>\n";
Fariborz Jahanian0cb4d922007-10-24 20:54:23 +00001053
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001054 // For each implemented class, write out all its meta data.
Fariborz Jahanian45d52f72007-10-18 22:09:03 +00001055 for (int i = 0; i < ClsDefCount; i++)
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001056 RewriteObjcClassMetaData(ClassImplementation[i], Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001057
1058 // For each implemented category, write out all its meta data.
1059 for (int i = 0; i < CatDefCount; i++)
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001060 RewriteObjcCategoryImplDecl(CategoryImplementation[i], Result);
Fariborz Jahanian45d52f72007-10-18 22:09:03 +00001061
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00001062 // Write objc_symtab metadata
1063 /*
1064 struct _objc_symtab
1065 {
1066 long sel_ref_cnt;
1067 SEL *refs;
1068 short cls_def_cnt;
1069 short cat_def_cnt;
1070 void *defs[cls_def_cnt + cat_def_cnt];
1071 };
1072 */
1073
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001074 Result += "\nstruct _objc_symtab {\n";
1075 Result += "\tlong sel_ref_cnt;\n";
1076 Result += "\tSEL *refs;\n";
1077 Result += "\tshort cls_def_cnt;\n";
1078 Result += "\tshort cat_def_cnt;\n";
1079 Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n";
1080 Result += "};\n\n";
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00001081
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001082 Result += "static struct _objc_symtab "
1083 "_OBJC_SYMBOLS __attribute__((section (\"__OBJC, __symbols\")))= {\n";
1084 Result += "\t0, 0, " + utostr(ClsDefCount)
1085 + ", " + utostr(CatDefCount) + "\n";
1086 for (int i = 0; i < ClsDefCount; i++) {
1087 Result += "\t,&_OBJC_CLASS_";
1088 Result += ClassImplementation[i]->getName();
1089 Result += "\n";
1090 }
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00001091
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001092 for (int i = 0; i < CatDefCount; i++) {
1093 Result += "\t,&_OBJC_CATEGORY_";
1094 Result += CategoryImplementation[i]->getClassInterface()->getName();
1095 Result += "_";
1096 Result += CategoryImplementation[i]->getName();
1097 Result += "\n";
1098 }
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00001099
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001100 Result += "};\n\n";
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00001101
1102 // Write objc_module metadata
1103
1104 /*
1105 struct _objc_module {
1106 long version;
1107 long size;
1108 const char *name;
1109 struct _objc_symtab *symtab;
1110 }
1111 */
1112
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001113 Result += "\nstruct _objc_module {\n";
1114 Result += "\tlong version;\n";
1115 Result += "\tlong size;\n";
1116 Result += "\tconst char *name;\n";
1117 Result += "\tstruct _objc_symtab *symtab;\n";
1118 Result += "};\n\n";
1119 Result += "static struct _objc_module "
1120 "_OBJC_MODULES __attribute__ ((section (\"__OBJC, __module_info\")))= {\n";
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00001121 Result += "\t" + utostr(OBJC_ABI_VERSION) +
1122 ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001123 Result += "};\n\n";
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00001124}
Chris Lattner6fe8b272007-10-16 22:36:42 +00001125