blob: 8904210aa53b6b1d5d25393b84f4d1a5cc4cbb41 [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"
Steve Naroff1ccf4632007-10-30 03:43:13 +000022#include "clang/Lex/Lexer.h"
Chris Lattnerb429ae42007-10-11 00:43:27 +000023using namespace clang;
Chris Lattnerc3aa5c42007-10-25 17:07:24 +000024using llvm::utostr;
Chris Lattnerb429ae42007-10-11 00:43:27 +000025
Chris Lattnerb429ae42007-10-11 00:43:27 +000026namespace {
Chris Lattner569faa62007-10-11 18:38:32 +000027 class RewriteTest : public ASTConsumer {
Chris Lattner74db1682007-10-16 21:07:07 +000028 Rewriter Rewrite;
Chris Lattnerbf0bfa62007-10-17 22:35:30 +000029 ASTContext *Context;
Chris Lattnerb429ae42007-10-11 00:43:27 +000030 SourceManager *SM;
Chris Lattner569faa62007-10-11 18:38:32 +000031 unsigned MainFileID;
Chris Lattner74db1682007-10-16 21:07:07 +000032 SourceLocation LastIncLoc;
Fariborz Jahanian640a01f2007-10-18 19:23:00 +000033 llvm::SmallVector<ObjcImplementationDecl *, 8> ClassImplementation;
34 llvm::SmallVector<ObjcCategoryImplDecl *, 8> CategoryImplementation;
Fariborz Jahanianf185aef2007-10-26 19:46:17 +000035 llvm::SmallPtrSet<ObjcInterfaceDecl*, 8> ObjcSynthesizedStructs;
Steve Naroffe9780582007-10-23 23:50:29 +000036
37 FunctionDecl *MsgSendFunctionDecl;
38 FunctionDecl *GetClassFunctionDecl;
Steve Naroff71226032007-10-24 22:48:43 +000039 FunctionDecl *SelGetUidFunctionDecl;
Steve Naroffe9780582007-10-23 23:50:29 +000040
Fariborz Jahanian640a01f2007-10-18 19:23:00 +000041 static const int OBJC_ABI_VERSION =7 ;
Chris Lattnerb429ae42007-10-11 00:43:27 +000042 public:
Chris Lattnerbf0bfa62007-10-17 22:35:30 +000043 void Initialize(ASTContext &context, unsigned mainFileID) {
44 Context = &context;
45 SM = &Context->SourceMgr;
Chris Lattner569faa62007-10-11 18:38:32 +000046 MainFileID = mainFileID;
Steve Naroffe9780582007-10-23 23:50:29 +000047 MsgSendFunctionDecl = 0;
Steve Naroff95b28c12007-10-24 01:09:48 +000048 GetClassFunctionDecl = 0;
Steve Naroff71226032007-10-24 22:48:43 +000049 SelGetUidFunctionDecl = 0;
Chris Lattnerbf0bfa62007-10-17 22:35:30 +000050 Rewrite.setSourceMgr(Context->SourceMgr);
Chris Lattnerb429ae42007-10-11 00:43:27 +000051 }
Chris Lattner569faa62007-10-11 18:38:32 +000052
Chris Lattnerfce2c5a2007-10-24 17:06:59 +000053 // Top Level Driver code.
54 virtual void HandleTopLevelDecl(Decl *D);
Chris Lattner74db1682007-10-16 21:07:07 +000055 void HandleDeclInMainFile(Decl *D);
Chris Lattnerfce2c5a2007-10-24 17:06:59 +000056 ~RewriteTest();
57
58 // Syntactic Rewriting.
Chris Lattner74db1682007-10-16 21:07:07 +000059 void RewriteInclude(SourceLocation Loc);
Chris Lattnerfce2c5a2007-10-24 17:06:59 +000060 void RewriteTabs();
61 void RewriteForwardClassDecl(ObjcClassDecl *Dcl);
Steve Naroff3774dd92007-10-26 20:53:56 +000062 void RewriteInterfaceDecl(ObjcInterfaceDecl *Dcl);
Steve Naroff667f1682007-10-30 13:30:57 +000063 void RewriteCategoryDecl(ObjcCategoryDecl *Dcl);
64 void RewriteMethods(int nMethods, ObjcMethodDecl **Methods);
Chris Lattner6fe8b272007-10-16 22:36:42 +000065
Chris Lattnerfce2c5a2007-10-24 17:06:59 +000066 // Expression Rewriting.
Chris Lattner0021f452007-10-24 16:57:36 +000067 Stmt *RewriteFunctionBody(Stmt *S);
68 Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
69 Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
Steve Naroff71226032007-10-24 22:48:43 +000070 CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD,
71 Expr **args, unsigned nargs);
Chris Lattnerfce2c5a2007-10-24 17:06:59 +000072 // Metadata emission.
Fariborz Jahanianf185aef2007-10-26 19:46:17 +000073 void HandleObjcMetaDataEmission();
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +000074 void RewriteObjcClassMetaData(ObjcImplementationDecl *IDecl,
75 std::string &Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +000076
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +000077 void RewriteObjcCategoryImplDecl(ObjcCategoryImplDecl *CDecl,
78 std::string &Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +000079
80 void RewriteObjcMethodsMetaData(ObjcMethodDecl **Methods,
81 int NumMethods,
Fariborz Jahaniana3986372007-10-25 00:14:44 +000082 bool IsInstanceMethod,
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +000083 const char *prefix,
Chris Lattnerc3aa5c42007-10-25 17:07:24 +000084 const char *ClassName,
85 std::string &Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +000086
87 void RewriteObjcProtocolsMetaData(ObjcProtocolDecl **Protocols,
88 int NumProtocols,
89 const char *prefix,
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +000090 const char *ClassName,
91 std::string &Result);
Fariborz Jahanianf185aef2007-10-26 19:46:17 +000092 void SynthesizeObjcInternalStruct(ObjcInterfaceDecl *CDecl,
93 std::string &Result);
Fariborz Jahanianf185aef2007-10-26 19:46:17 +000094 void SynthesizeIvarOffsetComputation(ObjcImplementationDecl *IDecl,
95 ObjcIvarDecl *ivar,
96 std::string &Result);
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +000097 void WriteObjcMetaData(std::string &Result);
Chris Lattnerb429ae42007-10-11 00:43:27 +000098 };
99}
100
Chris Lattner569faa62007-10-11 18:38:32 +0000101ASTConsumer *clang::CreateCodeRewriterTest() { return new RewriteTest(); }
Chris Lattnerb429ae42007-10-11 00:43:27 +0000102
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000103//===----------------------------------------------------------------------===//
104// Top Level Driver Code
105//===----------------------------------------------------------------------===//
106
Chris Lattner569faa62007-10-11 18:38:32 +0000107void RewriteTest::HandleTopLevelDecl(Decl *D) {
Chris Lattner74db1682007-10-16 21:07:07 +0000108 // Two cases: either the decl could be in the main file, or it could be in a
109 // #included file. If the former, rewrite it now. If the later, check to see
110 // if we rewrote the #include/#import.
111 SourceLocation Loc = D->getLocation();
112 Loc = SM->getLogicalLoc(Loc);
113
114 // If this is for a builtin, ignore it.
115 if (Loc.isInvalid()) return;
116
Steve Naroffe9780582007-10-23 23:50:29 +0000117 // Look for built-in declarations that we need to refer during the rewrite.
118 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Steve Naroff95b28c12007-10-24 01:09:48 +0000119 if (strcmp(FD->getName(), "objc_msgSend") == 0)
Steve Naroffe9780582007-10-23 23:50:29 +0000120 MsgSendFunctionDecl = FD;
Steve Naroff95b28c12007-10-24 01:09:48 +0000121 else if (strcmp(FD->getName(), "objc_getClass") == 0)
Steve Naroffe9780582007-10-23 23:50:29 +0000122 GetClassFunctionDecl = FD;
Steve Naroff71226032007-10-24 22:48:43 +0000123 else if (strcmp(FD->getName(), "sel_getUid") == 0)
124 SelGetUidFunctionDecl = FD;
Steve Naroff3774dd92007-10-26 20:53:56 +0000125 } else if (ObjcInterfaceDecl *MD = dyn_cast<ObjcInterfaceDecl>(D)) {
126 RewriteInterfaceDecl(MD);
Steve Naroff667f1682007-10-30 13:30:57 +0000127 } else if (ObjcCategoryDecl *CD = dyn_cast<ObjcCategoryDecl>(D)) {
128 RewriteCategoryDecl(CD);
Steve Naroffe9780582007-10-23 23:50:29 +0000129 }
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000130 // If we have a decl in the main file, see if we should rewrite it.
Chris Lattner74db1682007-10-16 21:07:07 +0000131 if (SM->getDecomposedFileLoc(Loc).first == MainFileID)
132 return HandleDeclInMainFile(D);
133
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000134 // Otherwise, see if there is a #import in the main file that should be
135 // rewritten.
Chris Lattner74db1682007-10-16 21:07:07 +0000136 RewriteInclude(Loc);
137}
138
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000139/// HandleDeclInMainFile - This is called for each top-level decl defined in the
140/// main file of the input.
141void RewriteTest::HandleDeclInMainFile(Decl *D) {
142 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
143 if (Stmt *Body = FD->getBody())
144 FD->setBody(RewriteFunctionBody(Body));
145
146 if (ObjcImplementationDecl *CI = dyn_cast<ObjcImplementationDecl>(D))
147 ClassImplementation.push_back(CI);
148 else if (ObjcCategoryImplDecl *CI = dyn_cast<ObjcCategoryImplDecl>(D))
149 CategoryImplementation.push_back(CI);
150 else if (ObjcClassDecl *CD = dyn_cast<ObjcClassDecl>(D))
151 RewriteForwardClassDecl(CD);
152 // Nothing yet.
153}
154
155RewriteTest::~RewriteTest() {
156 // Get the top-level buffer that this corresponds to.
157 RewriteTabs();
158
159 // Get the buffer corresponding to MainFileID. If we haven't changed it, then
160 // we are done.
161 if (const RewriteBuffer *RewriteBuf =
162 Rewrite.getRewriteBufferFor(MainFileID)) {
163 printf("Changed:\n");
164 std::string S(RewriteBuf->begin(), RewriteBuf->end());
165 printf("%s\n", S.c_str());
166 } else {
167 printf("No changes\n");
168 }
Fariborz Jahanianf185aef2007-10-26 19:46:17 +0000169
170}
171
172/// HandleObjcMetaDataEmission - main routine to generate objective-c's
173/// metadata.
174void RewriteTest::HandleObjcMetaDataEmission() {
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000175 // Rewrite Objective-c meta data*
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000176 std::string ResultStr;
177 WriteObjcMetaData(ResultStr);
178 // For now just print the string out.
179 printf("%s", ResultStr.c_str());
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000180}
181
182//===----------------------------------------------------------------------===//
183// Syntactic (non-AST) Rewriting Code
184//===----------------------------------------------------------------------===//
185
Chris Lattner74db1682007-10-16 21:07:07 +0000186void RewriteTest::RewriteInclude(SourceLocation Loc) {
187 // Rip up the #include stack to the main file.
188 SourceLocation IncLoc = Loc, NextLoc = Loc;
189 do {
190 IncLoc = Loc;
191 Loc = SM->getLogicalLoc(NextLoc);
192 NextLoc = SM->getIncludeLoc(Loc);
193 } while (!NextLoc.isInvalid());
194
195 // Loc is now the location of the #include filename "foo" or <foo/bar.h>.
196 // IncLoc indicates the header that was included if it is useful.
197 IncLoc = SM->getLogicalLoc(IncLoc);
198 if (SM->getDecomposedFileLoc(Loc).first != MainFileID ||
199 Loc == LastIncLoc)
200 return;
201 LastIncLoc = Loc;
202
203 unsigned IncCol = SM->getColumnNumber(Loc);
204 SourceLocation LineStartLoc = Loc.getFileLocWithOffset(-IncCol+1);
205
206 // Replace the #import with #include.
207 Rewrite.ReplaceText(LineStartLoc, IncCol-1, "#include ", strlen("#include "));
208}
209
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000210void RewriteTest::RewriteTabs() {
211 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
212 const char *MainBufStart = MainBuf.first;
213 const char *MainBufEnd = MainBuf.second;
Fariborz Jahanian640a01f2007-10-18 19:23:00 +0000214
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000215 // Loop over the whole file, looking for tabs.
216 for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) {
217 if (*BufPtr != '\t')
218 continue;
219
220 // Okay, we found a tab. This tab will turn into at least one character,
221 // but it depends on which 'virtual column' it is in. Compute that now.
222 unsigned VCol = 0;
223 while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' &&
224 BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r')
225 ++VCol;
226
227 // Okay, now that we know the virtual column, we know how many spaces to
228 // insert. We assume 8-character tab-stops.
229 unsigned Spaces = 8-(VCol & 7);
230
231 // Get the location of the tab.
232 SourceLocation TabLoc =
233 SourceLocation::getFileLoc(MainFileID, BufPtr-MainBufStart);
234
235 // Rewrite the single tab character into a sequence of spaces.
236 Rewrite.ReplaceText(TabLoc, 1, " ", Spaces);
237 }
Chris Lattner569faa62007-10-11 18:38:32 +0000238}
239
240
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000241void RewriteTest::RewriteForwardClassDecl(ObjcClassDecl *ClassDecl) {
242 int numDecls = ClassDecl->getNumForwardDecls();
243 ObjcInterfaceDecl **ForwardDecls = ClassDecl->getForwardDecls();
244
245 // Get the start location and compute the semi location.
246 SourceLocation startLoc = ClassDecl->getLocation();
247 const char *startBuf = SM->getCharacterData(startLoc);
248 const char *semiPtr = strchr(startBuf, ';');
249
250 // Translate to typedef's that forward reference structs with the same name
251 // as the class. As a convenience, we include the original declaration
252 // as a comment.
253 std::string typedefString;
254 typedefString += "// ";
Steve Naroff71226032007-10-24 22:48:43 +0000255 typedefString.append(startBuf, semiPtr-startBuf+1);
256 typedefString += "\n";
257 for (int i = 0; i < numDecls; i++) {
258 ObjcInterfaceDecl *ForwardDecl = ForwardDecls[i];
259 typedefString += "typedef struct ";
260 typedefString += ForwardDecl->getName();
261 typedefString += " ";
262 typedefString += ForwardDecl->getName();
263 typedefString += ";\n";
264 }
265
266 // Replace the @class with typedefs corresponding to the classes.
267 Rewrite.ReplaceText(startLoc, semiPtr-startBuf+1,
268 typedefString.c_str(), typedefString.size());
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000269}
270
Steve Naroff667f1682007-10-30 13:30:57 +0000271void RewriteTest::RewriteMethods(int nMethods, ObjcMethodDecl **Methods) {
272 for (int i = 0; i < nMethods; i++) {
273 ObjcMethodDecl *Method = Methods[i];
274 SourceLocation Loc = Method->getLocStart();
275
276 Rewrite.ReplaceText(Loc, 0, "// ", 3);
277
278 // FIXME: handle methods that are declared across multiple lines.
279 }
280}
281
282void RewriteTest::RewriteCategoryDecl(ObjcCategoryDecl *CatDecl) {
283 SourceLocation LocStart = CatDecl->getLocStart();
284
285 // FIXME: handle category headers that are declared across multiple lines.
286 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
287
288 RewriteMethods(CatDecl->getNumInstanceMethods(),
289 CatDecl->getInstanceMethods());
290 RewriteMethods(CatDecl->getNumClassMethods(),
291 CatDecl->getClassMethods());
292 // Lastly, comment out the @end.
293 Rewrite.ReplaceText(CatDecl->getAtEndLoc(), 0, "// ", 3);
294}
295
Steve Naroff3774dd92007-10-26 20:53:56 +0000296void RewriteTest::RewriteInterfaceDecl(ObjcInterfaceDecl *ClassDecl) {
Steve Naroffef20ed32007-10-30 02:23:23 +0000297
298 SourceLocation LocStart = ClassDecl->getLocStart();
299 SourceLocation LocEnd = ClassDecl->getLocEnd();
300
301 const char *startBuf = SM->getCharacterData(LocStart);
302 const char *endBuf = SM->getCharacterData(LocEnd);
303
Steve Naroff1ccf4632007-10-30 03:43:13 +0000304 endBuf += Lexer::MeasureTokenLength(LocEnd, *SM);
Steve Naroffef20ed32007-10-30 02:23:23 +0000305
306 std::string ResultStr;
307 SynthesizeObjcInternalStruct(ClassDecl, ResultStr);
308
Steve Naroff1ccf4632007-10-30 03:43:13 +0000309 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
Steve Naroffef20ed32007-10-30 02:23:23 +0000310 ResultStr.c_str(), ResultStr.size());
311
Steve Naroff667f1682007-10-30 13:30:57 +0000312 RewriteMethods(ClassDecl->getNumInstanceMethods(),
313 ClassDecl->getInstanceMethods());
314 RewriteMethods(ClassDecl->getNumClassMethods(),
315 ClassDecl->getClassMethods());
Steve Naroff3774dd92007-10-26 20:53:56 +0000316
Steve Naroff1ccf4632007-10-30 03:43:13 +0000317 // Lastly, comment out the @end.
318 Rewrite.ReplaceText(ClassDecl->getAtEndLoc(), 0, "// ", 3);
Steve Naroff3774dd92007-10-26 20:53:56 +0000319}
320
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000321//===----------------------------------------------------------------------===//
322// Function Body / Expression rewriting
323//===----------------------------------------------------------------------===//
324
Chris Lattner0021f452007-10-24 16:57:36 +0000325Stmt *RewriteTest::RewriteFunctionBody(Stmt *S) {
Chris Lattner6fe8b272007-10-16 22:36:42 +0000326 // Otherwise, just rewrite all children.
327 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
328 CI != E; ++CI)
Chris Lattnere33506b2007-10-17 21:28:00 +0000329 if (*CI)
Chris Lattner0021f452007-10-24 16:57:36 +0000330 *CI = RewriteFunctionBody(*CI);
Steve Naroffe9780582007-10-23 23:50:29 +0000331
332 // Handle specific things.
333 if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
334 return RewriteAtEncode(AtEncode);
335
Steve Naroff71226032007-10-24 22:48:43 +0000336 if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {
337 // Before we rewrite it, put the original message expression in a comment.
338 SourceLocation startLoc = MessExpr->getLocStart();
339 SourceLocation endLoc = MessExpr->getLocEnd();
340
341 const char *startBuf = SM->getCharacterData(startLoc);
342 const char *endBuf = SM->getCharacterData(endLoc);
343
344 std::string messString;
345 messString += "// ";
346 messString.append(startBuf, endBuf-startBuf+1);
347 messString += "\n";
Steve Naroff3774dd92007-10-26 20:53:56 +0000348
Steve Naroff71226032007-10-24 22:48:43 +0000349 // FIXME: Missing definition of Rewrite.InsertText(clang::SourceLocation, char const*, unsigned int).
350 // Rewrite.InsertText(startLoc, messString.c_str(), messString.size());
351 // Tried this, but it didn't work either...
Steve Naroff3774dd92007-10-26 20:53:56 +0000352 Rewrite.ReplaceText(startLoc, 0, messString.c_str(), messString.size());
Steve Naroffe9780582007-10-23 23:50:29 +0000353 return RewriteMessageExpr(MessExpr);
Steve Naroff71226032007-10-24 22:48:43 +0000354 }
Chris Lattner0021f452007-10-24 16:57:36 +0000355 // Return this stmt unmodified.
356 return S;
Chris Lattner6fe8b272007-10-16 22:36:42 +0000357}
Fariborz Jahanian45d52f72007-10-18 22:09:03 +0000358
Chris Lattner0021f452007-10-24 16:57:36 +0000359Stmt *RewriteTest::RewriteAtEncode(ObjCEncodeExpr *Exp) {
Chris Lattnerbf0bfa62007-10-17 22:35:30 +0000360 // Create a new string expression.
361 QualType StrType = Context->getPointerType(Context->CharTy);
Anders Carlsson36f07d82007-10-29 05:01:08 +0000362 std::string StrEncoding;
363 Context->getObjcEncodingForType(Exp->getEncodedType(), StrEncoding);
364 Expr *Replacement = new StringLiteral(StrEncoding.c_str(),
365 StrEncoding.length(), false, StrType,
Chris Lattnerbf0bfa62007-10-17 22:35:30 +0000366 SourceLocation(), SourceLocation());
367 Rewrite.ReplaceStmt(Exp, Replacement);
Chris Lattner0021f452007-10-24 16:57:36 +0000368 delete Exp;
369 return Replacement;
Chris Lattner6fe8b272007-10-16 22:36:42 +0000370}
371
Steve Naroff71226032007-10-24 22:48:43 +0000372CallExpr *RewriteTest::SynthesizeCallToFunctionDecl(
373 FunctionDecl *FD, Expr **args, unsigned nargs) {
Steve Naroffe9780582007-10-23 23:50:29 +0000374 // Get the type, we will need to reference it in a couple spots.
Steve Naroff71226032007-10-24 22:48:43 +0000375 QualType msgSendType = FD->getType();
Steve Naroffe9780582007-10-23 23:50:29 +0000376
377 // Create a reference to the objc_msgSend() declaration.
Steve Naroff71226032007-10-24 22:48:43 +0000378 DeclRefExpr *DRE = new DeclRefExpr(FD, msgSendType, SourceLocation());
Steve Naroffe9780582007-10-23 23:50:29 +0000379
380 // Now, we cast the reference to a pointer to the objc_msgSend type.
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000381 QualType pToFunc = Context->getPointerType(msgSendType);
Steve Naroffe9780582007-10-23 23:50:29 +0000382 ImplicitCastExpr *ICE = new ImplicitCastExpr(pToFunc, DRE);
383
384 const FunctionType *FT = msgSendType->getAsFunctionType();
Chris Lattner0021f452007-10-24 16:57:36 +0000385
Steve Naroff71226032007-10-24 22:48:43 +0000386 return new CallExpr(ICE, args, nargs, FT->getResultType(), SourceLocation());
387}
388
389Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) {
390 assert(MsgSendFunctionDecl && "Can't find objc_msgSend() decl");
391 assert(SelGetUidFunctionDecl && "Can't find sel_getUid() decl");
392 assert(GetClassFunctionDecl && "Can't find objc_getClass() decl");
393
394 // Synthesize a call to objc_msgSend().
395 llvm::SmallVector<Expr*, 8> MsgExprs;
396 IdentifierInfo *clsName = Exp->getClassName();
397
398 // Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend().
399 if (clsName) { // class message.
400 llvm::SmallVector<Expr*, 8> ClsExprs;
401 QualType argType = Context->getPointerType(Context->CharTy);
402 ClsExprs.push_back(new StringLiteral(clsName->getName(),
403 clsName->getLength(),
404 false, argType, SourceLocation(),
405 SourceLocation()));
406 CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
407 &ClsExprs[0], ClsExprs.size());
408 MsgExprs.push_back(Cls);
409 } else // instance message.
410 MsgExprs.push_back(Exp->getReceiver());
411
412 // Create a call to sel_getUid("selName"), it will be the 2nd argument.
413 llvm::SmallVector<Expr*, 8> SelExprs;
414 QualType argType = Context->getPointerType(Context->CharTy);
415 SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
416 Exp->getSelector().getName().size(),
417 false, argType, SourceLocation(),
418 SourceLocation()));
419 CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
420 &SelExprs[0], SelExprs.size());
421 MsgExprs.push_back(SelExp);
422
423 // Now push any user supplied arguments.
424 for (unsigned i = 0; i < Exp->getNumArgs(); i++) {
425 MsgExprs.push_back(Exp->getArg(i));
426 // We've transferred the ownership to MsgExprs. Null out the argument in
427 // the original expression, since we will delete it below.
428 Exp->setArg(i, 0);
429 }
430 CallExpr *MessExp = SynthesizeCallToFunctionDecl(MsgSendFunctionDecl,
431 &MsgExprs[0], MsgExprs.size());
432 // Now do the actual rewrite.
433 Rewrite.ReplaceStmt(Exp, MessExp);
434
Chris Lattner0021f452007-10-24 16:57:36 +0000435 delete Exp;
Steve Naroff71226032007-10-24 22:48:43 +0000436 return MessExp;
Steve Naroffe9780582007-10-23 23:50:29 +0000437}
438
Fariborz Jahanianf185aef2007-10-26 19:46:17 +0000439/// SynthesizeObjcInternalStruct - Rewrite one internal struct corresponding to
440/// an objective-c class with ivars.
441void RewriteTest::SynthesizeObjcInternalStruct(ObjcInterfaceDecl *CDecl,
442 std::string &Result) {
443 assert(CDecl && "Class missing in SynthesizeObjcInternalStruct");
444 assert(CDecl->getName() && "Name missing in SynthesizeObjcInternalStruct");
445 ObjcInterfaceDecl *RCDecl = CDecl->getSuperClass();
446 if (RCDecl && !ObjcSynthesizedStructs.count(RCDecl)) {
447 // Do it for the root
448 SynthesizeObjcInternalStruct(RCDecl, Result);
449 }
450
451 int NumIvars = CDecl->getIntfDeclNumIvars();
452 if (NumIvars <= 0 && (!RCDecl || !ObjcSynthesizedStructs.count(RCDecl)))
453 return;
454
455 Result += "\nstruct _interface_";
456 Result += CDecl->getName();
457 Result += " {\n";
458 if (RCDecl && ObjcSynthesizedStructs.count(RCDecl)) {
459 Result += "\tstruct _interface_";
460 Result += RCDecl->getName();
461 Result += " _";
462 Result += RCDecl->getName();
463 Result += ";\n";
464 }
465
466 ObjcIvarDecl **Ivars = CDecl->getIntfDeclIvars();
467 for (int i = 0; i < NumIvars; i++) {
468 Result += "\t";
469 std::string Name = Ivars[i]->getName();
470 Ivars[i]->getType().getAsStringInternal(Name);
471 Result += Name;
472 Result += ";\n";
473 }
474 Result += "};\n";
475 // Mark this struct as having been generated.
476 if (!ObjcSynthesizedStructs.insert(CDecl))
477 assert(true && "struct already synthesize- SynthesizeObjcInternalStruct");
478}
479
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000480// RewriteObjcMethodsMetaData - Rewrite methods metadata for instance or
481/// class methods.
482void RewriteTest::RewriteObjcMethodsMetaData(ObjcMethodDecl **Methods,
483 int NumMethods,
Fariborz Jahaniana3986372007-10-25 00:14:44 +0000484 bool IsInstanceMethod,
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000485 const char *prefix,
Chris Lattnerc3aa5c42007-10-25 17:07:24 +0000486 const char *ClassName,
487 std::string &Result) {
Fariborz Jahanian04455192007-10-22 21:41:37 +0000488 static bool objc_impl_method = false;
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000489 if (NumMethods > 0 && !objc_impl_method) {
490 /* struct _objc_method {
Fariborz Jahanian04455192007-10-22 21:41:37 +0000491 SEL _cmd;
492 char *method_types;
493 void *_imp;
494 }
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000495 */
Chris Lattnerc3aa5c42007-10-25 17:07:24 +0000496 Result += "\nstruct _objc_method {\n";
497 Result += "\tSEL _cmd;\n";
498 Result += "\tchar *method_types;\n";
499 Result += "\tvoid *_imp;\n";
500 Result += "};\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000501
502 /* struct _objc_method_list {
503 struct _objc_method_list *next_method;
504 int method_count;
505 struct _objc_method method_list[];
506 }
507 */
508 Result += "\nstruct _objc_method_list {\n";
509 Result += "\tstruct _objc_method_list *next_method;\n";
510 Result += "\tint method_count;\n";
511 Result += "\tstruct _objc_method method_list[];\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000512 objc_impl_method = true;
Fariborz Jahanian96b55da2007-10-19 00:36:46 +0000513 }
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000514 // Build _objc_method_list for class's methods if needed
515 if (NumMethods > 0) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000516 Result += "\nstatic struct _objc_method_list _OBJC_";
Chris Lattnerc3aa5c42007-10-25 17:07:24 +0000517 Result += prefix;
518 Result += IsInstanceMethod ? "INSTANCE" : "CLASS";
519 Result += "_METHODS_";
520 Result += ClassName;
521 Result += " __attribute__ ((section (\"__OBJC, __";
522 Result += IsInstanceMethod ? "inst" : "cls";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000523 Result += "_meth\")))= ";
524 Result += "{\n\t0, " + utostr(NumMethods) + "\n";
525
526 Result += "\t,{{(SEL)\"";
527 Result += Methods[0]->getSelector().getName().c_str();
Fariborz Jahanianc81f3162007-10-29 22:57:28 +0000528 std::string MethodTypeString;
529 Context->getObjcEncodingForMethodDecl(Methods[0], MethodTypeString);
530 Result += "\", \"";
531 Result += MethodTypeString;
532 Result += "\", 0}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000533 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahanianc81f3162007-10-29 22:57:28 +0000534 // TODO: Need method address as 3rd initializer.
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000535 Result += "\t ,{(SEL)\"";
536 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanianc81f3162007-10-29 22:57:28 +0000537 std::string MethodTypeString;
538 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
539 Result += "\", \"";
540 Result += MethodTypeString;
541 Result += "\", 0}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000542 }
543 Result += "\t }\n};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +0000544 }
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000545}
546
547/// RewriteObjcProtocolsMetaData - Rewrite protocols meta-data.
548void RewriteTest::RewriteObjcProtocolsMetaData(ObjcProtocolDecl **Protocols,
549 int NumProtocols,
550 const char *prefix,
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000551 const char *ClassName,
552 std::string &Result) {
Fariborz Jahanian04455192007-10-22 21:41:37 +0000553 static bool objc_protocol_methods = false;
Fariborz Jahanian04455192007-10-22 21:41:37 +0000554 if (NumProtocols > 0) {
Fariborz Jahanian04455192007-10-22 21:41:37 +0000555 for (int i = 0; i < NumProtocols; i++) {
556 ObjcProtocolDecl *PDecl = Protocols[i];
557 // Output struct protocol_methods holder of method selector and type.
558 if (!objc_protocol_methods &&
559 (PDecl->getNumInstanceMethods() > 0
560 || PDecl->getNumClassMethods() > 0)) {
561 /* struct protocol_methods {
562 SEL _cmd;
563 char *method_types;
564 }
565 */
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000566 Result += "\nstruct protocol_methods {\n";
567 Result += "\tSEL _cmd;\n";
568 Result += "\tchar *method_types;\n";
569 Result += "};\n";
570
571 /* struct _objc_protocol_method_list {
572 int protocol_method_count;
573 struct protocol_methods protocols[];
574 }
575 */
576 Result += "\nstruct _objc_protocol_method_list {\n";
577 Result += "\tint protocol_method_count;\n";
578 Result += "\tstruct protocol_methods protocols[];\n};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +0000579 objc_protocol_methods = true;
580 }
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000581
Fariborz Jahanian04455192007-10-22 21:41:37 +0000582 // Output instance methods declared in this protocol.
Fariborz Jahanian04455192007-10-22 21:41:37 +0000583 int NumMethods = PDecl->getNumInstanceMethods();
584 if (NumMethods > 0) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000585 Result += "\nstatic struct _objc_protocol_method_list "
586 "_OBJC_PROTOCOL_INSTANCE_METHODS_";
587 Result += PDecl->getName();
588 Result += " __attribute__ ((section (\"__OBJC, __cat_inst_meth\")))= "
589 "{\n\t" + utostr(NumMethods) + "\n";
590
Fariborz Jahanian04455192007-10-22 21:41:37 +0000591 ObjcMethodDecl **Methods = PDecl->getInstanceMethods();
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000592 Result += "\t,{{(SEL)\"";
593 Result += Methods[0]->getSelector().getName().c_str();
594 Result += "\", \"\"}\n";
595
596 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000597 Result += "\t ,{(SEL)\"";
598 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanianc81f3162007-10-29 22:57:28 +0000599 std::string MethodTypeString;
600 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
601 Result += "\", \"";
602 Result += MethodTypeString;
603 Result += "\"}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000604 }
605 Result += "\t }\n};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +0000606 }
607
608 // Output class methods declared in this protocol.
609 NumMethods = PDecl->getNumClassMethods();
610 if (NumMethods > 0) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000611 Result += "\nstatic struct _objc_protocol_method_list "
612 "_OBJC_PROTOCOL_CLASS_METHODS_";
613 Result += PDecl->getName();
614 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
615 "{\n\t";
616 Result += utostr(NumMethods);
617 Result += "\n";
618
Fariborz Jahanian04455192007-10-22 21:41:37 +0000619 ObjcMethodDecl **Methods = PDecl->getClassMethods();
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000620 Result += "\t,{{(SEL)\"";
621 Result += Methods[0]->getSelector().getName().c_str();
622 Result += "\", \"\"}\n";
623
624 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000625 Result += "\t ,{(SEL)\"";
626 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanianc81f3162007-10-29 22:57:28 +0000627 std::string MethodTypeString;
628 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
629 Result += "\", \"";
630 Result += MethodTypeString;
631 Result += "\"}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000632 }
633 Result += "\t }\n};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +0000634 }
635 // Output:
636 /* struct _objc_protocol {
637 // Objective-C 1.0 extensions
638 struct _objc_protocol_extension *isa;
639 char *protocol_name;
640 struct _objc_protocol **protocol_list;
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000641 struct _objc_protocol_method_list *instance_methods;
642 struct _objc_protocol_method_list *class_methods;
Fariborz Jahanian04455192007-10-22 21:41:37 +0000643 };
644 */
645 static bool objc_protocol = false;
646 if (!objc_protocol) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000647 Result += "\nstruct _objc_protocol {\n";
648 Result += "\tstruct _objc_protocol_extension *isa;\n";
649 Result += "\tchar *protocol_name;\n";
650 Result += "\tstruct _objc_protocol **protocol_list;\n";
651 Result += "\tstruct _objc_protocol_method_list *instance_methods;\n";
652 Result += "\tstruct _objc_protocol_method_list *class_methods;\n";
653 Result += "};\n";
654
655 /* struct _objc_protocol_list {
656 struct _objc_protocol_list *next;
657 int protocol_count;
658 struct _objc_protocol *class_protocols[];
659 }
660 */
661 Result += "\nstruct _objc_protocol_list {\n";
662 Result += "\tstruct _objc_protocol_list *next;\n";
663 Result += "\tint protocol_count;\n";
664 Result += "\tstruct _objc_protocol *class_protocols[];\n";
665 Result += "};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +0000666 objc_protocol = true;
667 }
668
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000669 Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_";
670 Result += PDecl->getName();
671 Result += " __attribute__ ((section (\"__OBJC, __protocol\")))= "
672 "{\n\t0, \"";
673 Result += PDecl->getName();
674 Result += "\", 0, ";
675 if (PDecl->getInstanceMethods() > 0) {
676 Result += "&_OBJC_PROTOCOL_INSTANCE_METHODS_";
677 Result += PDecl->getName();
678 Result += ", ";
679 }
Fariborz Jahanian04455192007-10-22 21:41:37 +0000680 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000681 Result += "0, ";
682 if (PDecl->getClassMethods() > 0) {
683 Result += "&_OBJC_PROTOCOL_CLASS_METHODS_";
684 Result += PDecl->getName();
685 Result += "\n";
686 }
Fariborz Jahanian04455192007-10-22 21:41:37 +0000687 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000688 Result += "0\n";
689 Result += "};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +0000690 }
Fariborz Jahanian04455192007-10-22 21:41:37 +0000691 // Output the top lovel protocol meta-data for the class.
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000692 Result += "\nstatic struct _objc_protocol_list _OBJC_";
693 Result += prefix;
694 Result += "_PROTOCOLS_";
695 Result += ClassName;
696 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
697 "{\n\t0, ";
698 Result += utostr(NumProtocols);
699 Result += "\n";
700
701 Result += "\t,{&_OBJC_PROTOCOL_";
702 Result += Protocols[0]->getName();
703 Result += " \n";
704
705 for (int i = 1; i < NumProtocols; i++) {
Fariborz Jahanian04455192007-10-22 21:41:37 +0000706 ObjcProtocolDecl *PDecl = Protocols[i];
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000707 Result += "\t ,&_OBJC_PROTOCOL_";
708 Result += PDecl->getName();
709 Result += "\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +0000710 }
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000711 Result += "\t }\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000712 }
713}
714
715/// RewriteObjcCategoryImplDecl - Rewrite metadata for each category
716/// implementation.
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000717void RewriteTest::RewriteObjcCategoryImplDecl(ObjcCategoryImplDecl *IDecl,
718 std::string &Result) {
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000719 ObjcInterfaceDecl *ClassDecl = IDecl->getClassInterface();
720 // Find category declaration for this implementation.
721 ObjcCategoryDecl *CDecl;
722 for (CDecl = ClassDecl->getCategoryList(); CDecl;
723 CDecl = CDecl->getNextClassCategory())
724 if (CDecl->getIdentifier() == IDecl->getIdentifier())
725 break;
726 assert(CDecl && "RewriteObjcCategoryImplDecl - bad category");
727
728 char *FullCategoryName = (char*)alloca(
729 strlen(ClassDecl->getName()) + strlen(IDecl->getName()) + 2);
730 sprintf(FullCategoryName, "%s_%s", ClassDecl->getName(), IDecl->getName());
731
732 // Build _objc_method_list for class's instance methods if needed
733 RewriteObjcMethodsMetaData(IDecl->getInstanceMethods(),
734 IDecl->getNumInstanceMethods(),
Fariborz Jahaniana3986372007-10-25 00:14:44 +0000735 true,
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000736 "CATEGORY_", FullCategoryName, Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000737
738 // Build _objc_method_list for class's class methods if needed
739 RewriteObjcMethodsMetaData(IDecl->getClassMethods(),
740 IDecl->getNumClassMethods(),
Fariborz Jahaniana3986372007-10-25 00:14:44 +0000741 false,
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000742 "CATEGORY_", FullCategoryName, Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000743
744 // Protocols referenced in class declaration?
745 RewriteObjcProtocolsMetaData(CDecl->getReferencedProtocols(),
746 CDecl->getNumReferencedProtocols(),
747 "CATEGORY",
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000748 FullCategoryName, Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000749
750 /* struct _objc_category {
751 char *category_name;
752 char *class_name;
753 struct _objc_method_list *instance_methods;
754 struct _objc_method_list *class_methods;
755 struct _objc_protocol_list *protocols;
756 // Objective-C 1.0 extensions
757 uint32_t size; // sizeof (struct _objc_category)
758 struct _objc_property_list *instance_properties; // category's own
759 // @property decl.
760 };
761 */
762
763 static bool objc_category = false;
764 if (!objc_category) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000765 Result += "\nstruct _objc_category {\n";
766 Result += "\tchar *category_name;\n";
767 Result += "\tchar *class_name;\n";
768 Result += "\tstruct _objc_method_list *instance_methods;\n";
769 Result += "\tstruct _objc_method_list *class_methods;\n";
770 Result += "\tstruct _objc_protocol_list *protocols;\n";
771 Result += "\tunsigned int size;\n";
772 Result += "\tstruct _objc_property_list *instance_properties;\n";
773 Result += "};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000774 objc_category = true;
Fariborz Jahanian04455192007-10-22 21:41:37 +0000775 }
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000776 Result += "\nstatic struct _objc_category _OBJC_CATEGORY_";
777 Result += FullCategoryName;
778 Result += " __attribute__ ((section (\"__OBJC, __category\")))= {\n\t\"";
779 Result += IDecl->getName();
780 Result += "\"\n\t, \"";
781 Result += ClassDecl->getName();
782 Result += "\"\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000783
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000784 if (IDecl->getNumInstanceMethods() > 0) {
785 Result += "\t, (struct _objc_method_list *)"
786 "&_OBJC_CATEGORY_INSTANCE_METHODS_";
787 Result += FullCategoryName;
788 Result += "\n";
789 }
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000790 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000791 Result += "\t, 0\n";
792 if (IDecl->getNumClassMethods() > 0) {
793 Result += "\t, (struct _objc_method_list *)"
794 "&_OBJC_CATEGORY_CLASS_METHODS_";
795 Result += FullCategoryName;
796 Result += "\n";
797 }
798 else
799 Result += "\t, 0\n";
800
801 if (CDecl->getNumReferencedProtocols() > 0) {
802 Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";
803 Result += FullCategoryName;
804 Result += "\n";
805 }
806 else
807 Result += "\t, 0\n";
808 Result += "\t, sizeof(struct _objc_category), 0\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000809}
810
Fariborz Jahanianf185aef2007-10-26 19:46:17 +0000811/// SynthesizeIvarOffsetComputation - This rutine synthesizes computation of
812/// ivar offset.
813void RewriteTest::SynthesizeIvarOffsetComputation(ObjcImplementationDecl *IDecl,
814 ObjcIvarDecl *ivar,
815 std::string &Result) {
816 Result += "offsetof(struct _interface_";
817 Result += IDecl->getName();
818 Result += ", ";
819 Result += ivar->getName();
820 Result += ")";
821}
822
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000823//===----------------------------------------------------------------------===//
824// Meta Data Emission
825//===----------------------------------------------------------------------===//
826
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000827void RewriteTest::RewriteObjcClassMetaData(ObjcImplementationDecl *IDecl,
828 std::string &Result) {
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000829 ObjcInterfaceDecl *CDecl = IDecl->getClassInterface();
830
831 // Build _objc_ivar_list metadata for classes ivars if needed
832 int NumIvars = IDecl->getImplDeclNumIvars() > 0
833 ? IDecl->getImplDeclNumIvars()
834 : (CDecl ? CDecl->getIntfDeclNumIvars() : 0);
835
Fariborz Jahanianab3ec252007-10-26 23:09:28 +0000836 SynthesizeObjcInternalStruct(CDecl, Result);
837
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000838 if (NumIvars > 0) {
839 static bool objc_ivar = false;
840 if (!objc_ivar) {
841 /* struct _objc_ivar {
842 char *ivar_name;
843 char *ivar_type;
844 int ivar_offset;
845 };
846 */
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000847 Result += "\nstruct _objc_ivar {\n";
848 Result += "\tchar *ivar_name;\n";
849 Result += "\tchar *ivar_type;\n";
850 Result += "\tint ivar_offset;\n";
851 Result += "};\n";
852
853 /* struct _objc_ivar_list {
854 int ivar_count;
855 struct _objc_ivar ivar_list[];
856 };
857 */
858 Result += "\nstruct _objc_ivar_list {\n";
859 Result += "\tint ivar_count;\n";
860 Result += "\tstruct _objc_ivar ivar_list[];\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000861 objc_ivar = true;
862 }
863
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000864 Result += "\nstatic struct _objc_ivar_list _OBJC_INSTANCE_VARIABLES_";
865 Result += IDecl->getName();
866 Result += " __attribute__ ((section (\"__OBJC, __instance_vars\")))= "
867 "{\n\t";
868 Result += utostr(NumIvars);
869 Result += "\n";
870
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000871 ObjcIvarDecl **Ivars = IDecl->getImplDeclIVars()
872 ? IDecl->getImplDeclIVars()
873 : CDecl->getIntfDeclIvars();
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000874 Result += "\t,{{\"";
875 Result += Ivars[0]->getName();
Fariborz Jahaniand5ea4612007-10-29 17:16:25 +0000876 Result += "\", \"";
877 std::string StrEncoding;
878 Context->getObjcEncodingForType(Ivars[0]->getType(), StrEncoding);
879 Result += StrEncoding;
880 Result += "\", ";
Fariborz Jahanianf185aef2007-10-26 19:46:17 +0000881 SynthesizeIvarOffsetComputation(IDecl, Ivars[0], Result);
882 Result += "}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000883 for (int i = 1; i < NumIvars; i++) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000884 Result += "\t ,{\"";
885 Result += Ivars[i]->getName();
Fariborz Jahaniand5ea4612007-10-29 17:16:25 +0000886 Result += "\", \"";
887 std::string StrEncoding;
888 Context->getObjcEncodingForType(Ivars[i]->getType(), StrEncoding);
889 Result += StrEncoding;
890 Result += "\", ";
Fariborz Jahanianf185aef2007-10-26 19:46:17 +0000891 SynthesizeIvarOffsetComputation(IDecl, Ivars[i], Result);
892 Result += "}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000893 }
894
895 Result += "\t }\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000896 }
897
898 // Build _objc_method_list for class's instance methods if needed
899 RewriteObjcMethodsMetaData(IDecl->getInstanceMethods(),
900 IDecl->getNumInstanceMethods(),
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000901 true,
902 "", IDecl->getName(), Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000903
904 // Build _objc_method_list for class's class methods if needed
905 RewriteObjcMethodsMetaData(IDecl->getClassMethods(),
Fariborz Jahaniana3986372007-10-25 00:14:44 +0000906 IDecl->getNumClassMethods(),
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000907 false,
908 "", IDecl->getName(), Result);
909
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000910 // Protocols referenced in class declaration?
911 RewriteObjcProtocolsMetaData(CDecl->getReferencedProtocols(),
912 CDecl->getNumIntfRefProtocols(),
913 "CLASS",
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000914 CDecl->getName(), Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000915
Fariborz Jahanian0f013d12007-10-23 00:02:02 +0000916
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +0000917 // Declaration of class/meta-class metadata
918 /* struct _objc_class {
919 struct _objc_class *isa; // or const char *root_class_name when metadata
Fariborz Jahanian0f013d12007-10-23 00:02:02 +0000920 const char *super_class_name;
921 char *name;
922 long version;
923 long info;
924 long instance_size;
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +0000925 struct _objc_ivar_list *ivars;
926 struct _objc_method_list *methods;
Fariborz Jahanian0f013d12007-10-23 00:02:02 +0000927 struct objc_cache *cache;
928 struct objc_protocol_list *protocols;
929 const char *ivar_layout;
930 struct _objc_class_ext *ext;
931 };
932 */
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +0000933 static bool objc_class = false;
934 if (!objc_class) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000935 Result += "\nstruct _objc_class {\n";
936 Result += "\tstruct _objc_class *isa;\n";
937 Result += "\tconst char *super_class_name;\n";
938 Result += "\tchar *name;\n";
939 Result += "\tlong version;\n";
940 Result += "\tlong info;\n";
941 Result += "\tlong instance_size;\n";
942 Result += "\tstruct _objc_ivar_list *ivars;\n";
943 Result += "\tstruct _objc_method_list *methods;\n";
944 Result += "\tstruct objc_cache *cache;\n";
945 Result += "\tstruct _objc_protocol_list *protocols;\n";
946 Result += "\tconst char *ivar_layout;\n";
947 Result += "\tstruct _objc_class_ext *ext;\n";
948 Result += "};\n";
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +0000949 objc_class = true;
Fariborz Jahanian0f013d12007-10-23 00:02:02 +0000950 }
951
952 // Meta-class metadata generation.
953 ObjcInterfaceDecl *RootClass = 0;
954 ObjcInterfaceDecl *SuperClass = CDecl->getSuperClass();
955 while (SuperClass) {
956 RootClass = SuperClass;
957 SuperClass = SuperClass->getSuperClass();
958 }
959 SuperClass = CDecl->getSuperClass();
960
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000961 Result += "\nstatic struct _objc_class _OBJC_METACLASS_";
962 Result += CDecl->getName();
963 Result += " __attribute__ ((section (\"__OBJC, __meta_class\")))= "
964 "{\n\t(struct _objc_class *)\"";
965 Result += (RootClass ? RootClass->getName() : CDecl->getName());
966 Result += "\"";
967
968 if (SuperClass) {
969 Result += ", \"";
970 Result += SuperClass->getName();
971 Result += "\", \"";
972 Result += CDecl->getName();
973 Result += "\"";
974 }
975 else {
976 Result += ", 0, \"";
977 Result += CDecl->getName();
978 Result += "\"";
979 }
Fariborz Jahanian0f013d12007-10-23 00:02:02 +0000980 // TODO: 'ivars' field for root class is currently set to 0.
981 // 'info' field is initialized to CLS_META(2) for metaclass
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000982 Result += ", 0,2, sizeof(struct _objc_class), 0";
983 if (CDecl->getNumClassMethods() > 0) {
984 Result += "\n\t, &_OBJC_CLASS_METHODS_";
985 Result += CDecl->getName();
986 Result += "\n";
987 }
Fariborz Jahanian0f013d12007-10-23 00:02:02 +0000988 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000989 Result += ", 0\n";
990 if (CDecl->getNumIntfRefProtocols() > 0) {
991 Result += "\t,0, &_OBJC_CLASS_PROTOCOLS_";
992 Result += CDecl->getName();
993 Result += ",0,0\n";
994 }
Fariborz Jahanian0cb4d922007-10-24 20:54:23 +0000995 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000996 Result += "\t,0,0,0,0\n";
997 Result += "};\n";
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +0000998
999 // class metadata generation.
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001000 Result += "\nstatic struct _objc_class _OBJC_CLASS_";
1001 Result += CDecl->getName();
1002 Result += " __attribute__ ((section (\"__OBJC, __class\")))= "
1003 "{\n\t&_OBJC_METACLASS_";
1004 Result += CDecl->getName();
1005 if (SuperClass) {
1006 Result += ", \"";
1007 Result += SuperClass->getName();
1008 Result += "\", \"";
1009 Result += CDecl->getName();
1010 Result += "\"";
1011 }
1012 else {
1013 Result += ", 0, \"";
1014 Result += CDecl->getName();
1015 Result += "\"";
1016 }
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00001017 // 'info' field is initialized to CLS_CLASS(1) for class
Fariborz Jahanianab3ec252007-10-26 23:09:28 +00001018 Result += ", 0,1";
1019 if (!ObjcSynthesizedStructs.count(CDecl))
1020 Result += ",0";
1021 else {
1022 // class has size. Must synthesize its size.
1023 Result += ",sizeof(struct _interface_";
1024 Result += CDecl->getName();
1025 Result += ")";
1026 }
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001027 if (NumIvars > 0) {
1028 Result += ", &_OBJC_INSTANCE_VARIABLES_";
1029 Result += CDecl->getName();
1030 Result += "\n\t";
1031 }
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00001032 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001033 Result += ",0";
1034 if (IDecl->getNumInstanceMethods() > 0) {
1035 Result += ", &_OBJC_INSTANCE_METHODS_";
1036 Result += CDecl->getName();
1037 Result += ", 0\n\t";
1038 }
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00001039 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001040 Result += ",0,0";
1041 if (CDecl->getNumIntfRefProtocols() > 0) {
1042 Result += ", &_OBJC_CLASS_PROTOCOLS_";
1043 Result += CDecl->getName();
1044 Result += ", 0,0\n";
1045 }
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00001046 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001047 Result += ",0,0,0\n";
1048 Result += "};\n";
Fariborz Jahanian0f013d12007-10-23 00:02:02 +00001049}
Fariborz Jahanian45d52f72007-10-18 22:09:03 +00001050
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001051void RewriteTest::WriteObjcMetaData(std::string &Result) {
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00001052 int ClsDefCount = ClassImplementation.size();
1053 int CatDefCount = CategoryImplementation.size();
1054 if (ClsDefCount == 0 && CatDefCount == 0)
1055 return;
Fariborz Jahanian45d52f72007-10-18 22:09:03 +00001056
Fariborz Jahanian0cb4d922007-10-24 20:54:23 +00001057 // TODO: This is temporary until we decide how to access objc types in a
1058 // c program
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00001059 Result += "#include <Objc/objc.h>\n";
1060 // This is needed for use of offsetof
1061 Result += "#include <stddef.h>\n";
Fariborz Jahanian0cb4d922007-10-24 20:54:23 +00001062
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001063 // For each implemented class, write out all its meta data.
Fariborz Jahanian45d52f72007-10-18 22:09:03 +00001064 for (int i = 0; i < ClsDefCount; i++)
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001065 RewriteObjcClassMetaData(ClassImplementation[i], Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001066
1067 // For each implemented category, write out all its meta data.
1068 for (int i = 0; i < CatDefCount; i++)
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001069 RewriteObjcCategoryImplDecl(CategoryImplementation[i], Result);
Fariborz Jahanian45d52f72007-10-18 22:09:03 +00001070
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00001071 // Write objc_symtab metadata
1072 /*
1073 struct _objc_symtab
1074 {
1075 long sel_ref_cnt;
1076 SEL *refs;
1077 short cls_def_cnt;
1078 short cat_def_cnt;
1079 void *defs[cls_def_cnt + cat_def_cnt];
1080 };
1081 */
1082
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001083 Result += "\nstruct _objc_symtab {\n";
1084 Result += "\tlong sel_ref_cnt;\n";
1085 Result += "\tSEL *refs;\n";
1086 Result += "\tshort cls_def_cnt;\n";
1087 Result += "\tshort cat_def_cnt;\n";
1088 Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n";
1089 Result += "};\n\n";
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00001090
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001091 Result += "static struct _objc_symtab "
1092 "_OBJC_SYMBOLS __attribute__((section (\"__OBJC, __symbols\")))= {\n";
1093 Result += "\t0, 0, " + utostr(ClsDefCount)
1094 + ", " + utostr(CatDefCount) + "\n";
1095 for (int i = 0; i < ClsDefCount; i++) {
1096 Result += "\t,&_OBJC_CLASS_";
1097 Result += ClassImplementation[i]->getName();
1098 Result += "\n";
1099 }
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00001100
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001101 for (int i = 0; i < CatDefCount; i++) {
1102 Result += "\t,&_OBJC_CATEGORY_";
1103 Result += CategoryImplementation[i]->getClassInterface()->getName();
1104 Result += "_";
1105 Result += CategoryImplementation[i]->getName();
1106 Result += "\n";
1107 }
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00001108
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001109 Result += "};\n\n";
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00001110
1111 // Write objc_module metadata
1112
1113 /*
1114 struct _objc_module {
1115 long version;
1116 long size;
1117 const char *name;
1118 struct _objc_symtab *symtab;
1119 }
1120 */
1121
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001122 Result += "\nstruct _objc_module {\n";
1123 Result += "\tlong version;\n";
1124 Result += "\tlong size;\n";
1125 Result += "\tconst char *name;\n";
1126 Result += "\tstruct _objc_symtab *symtab;\n";
1127 Result += "};\n\n";
1128 Result += "static struct _objc_module "
1129 "_OBJC_MODULES __attribute__ ((section (\"__OBJC, __module_info\")))= {\n";
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00001130 Result += "\t" + utostr(OBJC_ABI_VERSION) +
1131 ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001132 Result += "};\n\n";
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00001133}
Chris Lattner6fe8b272007-10-16 22:36:42 +00001134