blob: 8f3b754195c63ff92acbc0798da7730ce4da8e84 [file] [log] [blame]
Chris Lattner77cd2a02007-10-11 00:43:27 +00001//===--- RewriteTest.cpp - Playground for the code rewriter ---------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Chris Lattner and is distributed under the
6// University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Hacks and fun related to the code rewriter.
11//
12//===----------------------------------------------------------------------===//
13
14#include "ASTConsumers.h"
Chris Lattner8a12c272007-10-11 18:38:32 +000015#include "clang/Rewrite/Rewriter.h"
Chris Lattner77cd2a02007-10-11 00:43:27 +000016#include "clang/AST/AST.h"
17#include "clang/AST/ASTConsumer.h"
Chris Lattner8a12c272007-10-11 18:38:32 +000018#include "clang/Basic/SourceManager.h"
Steve Naroffebf2b562007-10-23 23:50:29 +000019#include "clang/Basic/IdentifierTable.h"
Chris Lattner158ecb92007-10-25 17:07:24 +000020#include "llvm/ADT/StringExtras.h"
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +000021#include "llvm/ADT/SmallPtrSet.h"
Steve Naroff2feac5e2007-10-30 03:43:13 +000022#include "clang/Lex/Lexer.h"
Chris Lattner77cd2a02007-10-11 00:43:27 +000023using namespace clang;
Chris Lattner158ecb92007-10-25 17:07:24 +000024using llvm::utostr;
Chris Lattner77cd2a02007-10-11 00:43:27 +000025
Chris Lattner77cd2a02007-10-11 00:43:27 +000026namespace {
Chris Lattner8a12c272007-10-11 18:38:32 +000027 class RewriteTest : public ASTConsumer {
Chris Lattner2c64b7b2007-10-16 21:07:07 +000028 Rewriter Rewrite;
Chris Lattner01c57482007-10-17 22:35:30 +000029 ASTContext *Context;
Chris Lattner77cd2a02007-10-11 00:43:27 +000030 SourceManager *SM;
Chris Lattner8a12c272007-10-11 18:38:32 +000031 unsigned MainFileID;
Chris Lattner2c64b7b2007-10-16 21:07:07 +000032 SourceLocation LastIncLoc;
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +000033 llvm::SmallVector<ObjcImplementationDecl *, 8> ClassImplementation;
34 llvm::SmallVector<ObjcCategoryImplDecl *, 8> CategoryImplementation;
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +000035 llvm::SmallPtrSet<ObjcInterfaceDecl*, 8> ObjcSynthesizedStructs;
Steve Naroffebf2b562007-10-23 23:50:29 +000036
37 FunctionDecl *MsgSendFunctionDecl;
38 FunctionDecl *GetClassFunctionDecl;
Steve Naroff934f2762007-10-24 22:48:43 +000039 FunctionDecl *SelGetUidFunctionDecl;
Steve Naroffebf2b562007-10-23 23:50:29 +000040
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +000041 static const int OBJC_ABI_VERSION =7 ;
Chris Lattner77cd2a02007-10-11 00:43:27 +000042 public:
Chris Lattner01c57482007-10-17 22:35:30 +000043 void Initialize(ASTContext &context, unsigned mainFileID) {
44 Context = &context;
45 SM = &Context->SourceMgr;
Chris Lattner8a12c272007-10-11 18:38:32 +000046 MainFileID = mainFileID;
Steve Naroffebf2b562007-10-23 23:50:29 +000047 MsgSendFunctionDecl = 0;
Steve Naroffc0006092007-10-24 01:09:48 +000048 GetClassFunctionDecl = 0;
Steve Naroff934f2762007-10-24 22:48:43 +000049 SelGetUidFunctionDecl = 0;
Chris Lattner01c57482007-10-17 22:35:30 +000050 Rewrite.setSourceMgr(Context->SourceMgr);
Chris Lattner77cd2a02007-10-11 00:43:27 +000051 }
Chris Lattner8a12c272007-10-11 18:38:32 +000052
Chris Lattnerf04da132007-10-24 17:06:59 +000053 // Top Level Driver code.
54 virtual void HandleTopLevelDecl(Decl *D);
Chris Lattner2c64b7b2007-10-16 21:07:07 +000055 void HandleDeclInMainFile(Decl *D);
Chris Lattnerf04da132007-10-24 17:06:59 +000056 ~RewriteTest();
57
58 // Syntactic Rewriting.
Chris Lattner2c64b7b2007-10-16 21:07:07 +000059 void RewriteInclude(SourceLocation Loc);
Chris Lattnerf04da132007-10-24 17:06:59 +000060 void RewriteTabs();
61 void RewriteForwardClassDecl(ObjcClassDecl *Dcl);
Steve Naroffbef11852007-10-26 20:53:56 +000062 void RewriteInterfaceDecl(ObjcInterfaceDecl *Dcl);
Steve Naroff423cb562007-10-30 13:30:57 +000063 void RewriteCategoryDecl(ObjcCategoryDecl *Dcl);
Steve Naroff752d6ef2007-10-30 16:42:30 +000064 void RewriteProtocolDecl(ObjcProtocolDecl *Dcl);
Steve Naroff423cb562007-10-30 13:30:57 +000065 void RewriteMethods(int nMethods, ObjcMethodDecl **Methods);
Steve Naroff09b266e2007-10-30 23:14:51 +000066 void RewriteFunctionDecl(FunctionDecl *FD);
Chris Lattner311ff022007-10-16 22:36:42 +000067
Chris Lattnerf04da132007-10-24 17:06:59 +000068 // Expression Rewriting.
Chris Lattnere64b7772007-10-24 16:57:36 +000069 Stmt *RewriteFunctionBody(Stmt *S);
70 Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
71 Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
Steve Naroff934f2762007-10-24 22:48:43 +000072 CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD,
73 Expr **args, unsigned nargs);
Steve Naroff09b266e2007-10-30 23:14:51 +000074 void SynthMsgSendFunctionDecl();
75 void SynthGetClassFunctionDecl();
76
Chris Lattnerf04da132007-10-24 17:06:59 +000077 // Metadata emission.
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +000078 void HandleObjcMetaDataEmission();
Fariborz Jahanianccd87b02007-10-25 20:55:25 +000079 void RewriteObjcClassMetaData(ObjcImplementationDecl *IDecl,
80 std::string &Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +000081
Fariborz Jahanianccd87b02007-10-25 20:55:25 +000082 void RewriteObjcCategoryImplDecl(ObjcCategoryImplDecl *CDecl,
83 std::string &Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +000084
85 void RewriteObjcMethodsMetaData(ObjcMethodDecl **Methods,
86 int NumMethods,
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +000087 bool IsInstanceMethod,
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +000088 const char *prefix,
Chris Lattner158ecb92007-10-25 17:07:24 +000089 const char *ClassName,
90 std::string &Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +000091
92 void RewriteObjcProtocolsMetaData(ObjcProtocolDecl **Protocols,
93 int NumProtocols,
94 const char *prefix,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +000095 const char *ClassName,
96 std::string &Result);
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +000097 void SynthesizeObjcInternalStruct(ObjcInterfaceDecl *CDecl,
98 std::string &Result);
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +000099 void SynthesizeIvarOffsetComputation(ObjcImplementationDecl *IDecl,
100 ObjcIvarDecl *ivar,
101 std::string &Result);
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000102 void WriteObjcMetaData(std::string &Result);
Chris Lattner77cd2a02007-10-11 00:43:27 +0000103 };
104}
105
Chris Lattner8a12c272007-10-11 18:38:32 +0000106ASTConsumer *clang::CreateCodeRewriterTest() { return new RewriteTest(); }
Chris Lattner77cd2a02007-10-11 00:43:27 +0000107
Chris Lattnerf04da132007-10-24 17:06:59 +0000108//===----------------------------------------------------------------------===//
109// Top Level Driver Code
110//===----------------------------------------------------------------------===//
111
Chris Lattner8a12c272007-10-11 18:38:32 +0000112void RewriteTest::HandleTopLevelDecl(Decl *D) {
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000113 // Two cases: either the decl could be in the main file, or it could be in a
114 // #included file. If the former, rewrite it now. If the later, check to see
115 // if we rewrote the #include/#import.
116 SourceLocation Loc = D->getLocation();
117 Loc = SM->getLogicalLoc(Loc);
118
119 // If this is for a builtin, ignore it.
120 if (Loc.isInvalid()) return;
121
Steve Naroffebf2b562007-10-23 23:50:29 +0000122 // Look for built-in declarations that we need to refer during the rewrite.
123 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Steve Naroff09b266e2007-10-30 23:14:51 +0000124 RewriteFunctionDecl(FD);
Steve Naroffbef11852007-10-26 20:53:56 +0000125 } else if (ObjcInterfaceDecl *MD = dyn_cast<ObjcInterfaceDecl>(D)) {
126 RewriteInterfaceDecl(MD);
Steve Naroff423cb562007-10-30 13:30:57 +0000127 } else if (ObjcCategoryDecl *CD = dyn_cast<ObjcCategoryDecl>(D)) {
128 RewriteCategoryDecl(CD);
Steve Naroff752d6ef2007-10-30 16:42:30 +0000129 } else if (ObjcProtocolDecl *PD = dyn_cast<ObjcProtocolDecl>(D)) {
130 RewriteProtocolDecl(PD);
Steve Naroffebf2b562007-10-23 23:50:29 +0000131 }
Chris Lattnerf04da132007-10-24 17:06:59 +0000132 // If we have a decl in the main file, see if we should rewrite it.
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000133 if (SM->getDecomposedFileLoc(Loc).first == MainFileID)
134 return HandleDeclInMainFile(D);
135
Chris Lattnerf04da132007-10-24 17:06:59 +0000136 // Otherwise, see if there is a #import in the main file that should be
137 // rewritten.
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000138 RewriteInclude(Loc);
139}
140
Chris Lattnerf04da132007-10-24 17:06:59 +0000141/// HandleDeclInMainFile - This is called for each top-level decl defined in the
142/// main file of the input.
143void RewriteTest::HandleDeclInMainFile(Decl *D) {
144 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
145 if (Stmt *Body = FD->getBody())
146 FD->setBody(RewriteFunctionBody(Body));
147
148 if (ObjcImplementationDecl *CI = dyn_cast<ObjcImplementationDecl>(D))
149 ClassImplementation.push_back(CI);
150 else if (ObjcCategoryImplDecl *CI = dyn_cast<ObjcCategoryImplDecl>(D))
151 CategoryImplementation.push_back(CI);
152 else if (ObjcClassDecl *CD = dyn_cast<ObjcClassDecl>(D))
153 RewriteForwardClassDecl(CD);
154 // Nothing yet.
155}
156
157RewriteTest::~RewriteTest() {
158 // Get the top-level buffer that this corresponds to.
159 RewriteTabs();
160
161 // Get the buffer corresponding to MainFileID. If we haven't changed it, then
162 // we are done.
163 if (const RewriteBuffer *RewriteBuf =
164 Rewrite.getRewriteBufferFor(MainFileID)) {
165 printf("Changed:\n");
166 std::string S(RewriteBuf->begin(), RewriteBuf->end());
167 printf("%s\n", S.c_str());
168 } else {
169 printf("No changes\n");
170 }
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000171
172}
173
174/// HandleObjcMetaDataEmission - main routine to generate objective-c's
175/// metadata.
176void RewriteTest::HandleObjcMetaDataEmission() {
Chris Lattnerf04da132007-10-24 17:06:59 +0000177 // Rewrite Objective-c meta data*
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000178 std::string ResultStr;
179 WriteObjcMetaData(ResultStr);
180 // For now just print the string out.
181 printf("%s", ResultStr.c_str());
Chris Lattnerf04da132007-10-24 17:06:59 +0000182}
183
184//===----------------------------------------------------------------------===//
185// Syntactic (non-AST) Rewriting Code
186//===----------------------------------------------------------------------===//
187
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000188void RewriteTest::RewriteInclude(SourceLocation Loc) {
189 // Rip up the #include stack to the main file.
190 SourceLocation IncLoc = Loc, NextLoc = Loc;
191 do {
192 IncLoc = Loc;
193 Loc = SM->getLogicalLoc(NextLoc);
194 NextLoc = SM->getIncludeLoc(Loc);
195 } while (!NextLoc.isInvalid());
196
197 // Loc is now the location of the #include filename "foo" or <foo/bar.h>.
198 // IncLoc indicates the header that was included if it is useful.
199 IncLoc = SM->getLogicalLoc(IncLoc);
200 if (SM->getDecomposedFileLoc(Loc).first != MainFileID ||
201 Loc == LastIncLoc)
202 return;
203 LastIncLoc = Loc;
204
205 unsigned IncCol = SM->getColumnNumber(Loc);
206 SourceLocation LineStartLoc = Loc.getFileLocWithOffset(-IncCol+1);
207
208 // Replace the #import with #include.
209 Rewrite.ReplaceText(LineStartLoc, IncCol-1, "#include ", strlen("#include "));
210}
211
Chris Lattnerf04da132007-10-24 17:06:59 +0000212void RewriteTest::RewriteTabs() {
213 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
214 const char *MainBufStart = MainBuf.first;
215 const char *MainBufEnd = MainBuf.second;
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +0000216
Chris Lattnerf04da132007-10-24 17:06:59 +0000217 // Loop over the whole file, looking for tabs.
218 for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) {
219 if (*BufPtr != '\t')
220 continue;
221
222 // Okay, we found a tab. This tab will turn into at least one character,
223 // but it depends on which 'virtual column' it is in. Compute that now.
224 unsigned VCol = 0;
225 while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' &&
226 BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r')
227 ++VCol;
228
229 // Okay, now that we know the virtual column, we know how many spaces to
230 // insert. We assume 8-character tab-stops.
231 unsigned Spaces = 8-(VCol & 7);
232
233 // Get the location of the tab.
234 SourceLocation TabLoc =
235 SourceLocation::getFileLoc(MainFileID, BufPtr-MainBufStart);
236
237 // Rewrite the single tab character into a sequence of spaces.
238 Rewrite.ReplaceText(TabLoc, 1, " ", Spaces);
239 }
Chris Lattner8a12c272007-10-11 18:38:32 +0000240}
241
242
Chris Lattnerf04da132007-10-24 17:06:59 +0000243void RewriteTest::RewriteForwardClassDecl(ObjcClassDecl *ClassDecl) {
244 int numDecls = ClassDecl->getNumForwardDecls();
245 ObjcInterfaceDecl **ForwardDecls = ClassDecl->getForwardDecls();
246
247 // Get the start location and compute the semi location.
248 SourceLocation startLoc = ClassDecl->getLocation();
249 const char *startBuf = SM->getCharacterData(startLoc);
250 const char *semiPtr = strchr(startBuf, ';');
251
252 // Translate to typedef's that forward reference structs with the same name
253 // as the class. As a convenience, we include the original declaration
254 // as a comment.
255 std::string typedefString;
256 typedefString += "// ";
Steve Naroff934f2762007-10-24 22:48:43 +0000257 typedefString.append(startBuf, semiPtr-startBuf+1);
258 typedefString += "\n";
259 for (int i = 0; i < numDecls; i++) {
260 ObjcInterfaceDecl *ForwardDecl = ForwardDecls[i];
261 typedefString += "typedef struct ";
262 typedefString += ForwardDecl->getName();
263 typedefString += " ";
264 typedefString += ForwardDecl->getName();
265 typedefString += ";\n";
266 }
267
268 // Replace the @class with typedefs corresponding to the classes.
269 Rewrite.ReplaceText(startLoc, semiPtr-startBuf+1,
270 typedefString.c_str(), typedefString.size());
Chris Lattnerf04da132007-10-24 17:06:59 +0000271}
272
Steve Naroff423cb562007-10-30 13:30:57 +0000273void RewriteTest::RewriteMethods(int nMethods, ObjcMethodDecl **Methods) {
274 for (int i = 0; i < nMethods; i++) {
275 ObjcMethodDecl *Method = Methods[i];
276 SourceLocation Loc = Method->getLocStart();
277
278 Rewrite.ReplaceText(Loc, 0, "// ", 3);
279
280 // FIXME: handle methods that are declared across multiple lines.
281 }
282}
283
284void RewriteTest::RewriteCategoryDecl(ObjcCategoryDecl *CatDecl) {
285 SourceLocation LocStart = CatDecl->getLocStart();
286
287 // FIXME: handle category headers that are declared across multiple lines.
288 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
289
290 RewriteMethods(CatDecl->getNumInstanceMethods(),
291 CatDecl->getInstanceMethods());
292 RewriteMethods(CatDecl->getNumClassMethods(),
293 CatDecl->getClassMethods());
294 // Lastly, comment out the @end.
295 Rewrite.ReplaceText(CatDecl->getAtEndLoc(), 0, "// ", 3);
296}
297
Steve Naroff752d6ef2007-10-30 16:42:30 +0000298void RewriteTest::RewriteProtocolDecl(ObjcProtocolDecl *PDecl) {
299 SourceLocation LocStart = PDecl->getLocStart();
300
301 // FIXME: handle protocol headers that are declared across multiple lines.
302 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
303
304 RewriteMethods(PDecl->getNumInstanceMethods(),
305 PDecl->getInstanceMethods());
306 RewriteMethods(PDecl->getNumClassMethods(),
307 PDecl->getClassMethods());
308 // Lastly, comment out the @end.
309 Rewrite.ReplaceText(PDecl->getAtEndLoc(), 0, "// ", 3);
310}
311
Steve Naroffbef11852007-10-26 20:53:56 +0000312void RewriteTest::RewriteInterfaceDecl(ObjcInterfaceDecl *ClassDecl) {
Steve Narofff908a872007-10-30 02:23:23 +0000313
314 SourceLocation LocStart = ClassDecl->getLocStart();
315 SourceLocation LocEnd = ClassDecl->getLocEnd();
316
317 const char *startBuf = SM->getCharacterData(LocStart);
318 const char *endBuf = SM->getCharacterData(LocEnd);
319
Steve Naroff2feac5e2007-10-30 03:43:13 +0000320 endBuf += Lexer::MeasureTokenLength(LocEnd, *SM);
Steve Narofff908a872007-10-30 02:23:23 +0000321
322 std::string ResultStr;
323 SynthesizeObjcInternalStruct(ClassDecl, ResultStr);
324
Steve Naroff2feac5e2007-10-30 03:43:13 +0000325 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
Steve Narofff908a872007-10-30 02:23:23 +0000326 ResultStr.c_str(), ResultStr.size());
327
Steve Naroff423cb562007-10-30 13:30:57 +0000328 RewriteMethods(ClassDecl->getNumInstanceMethods(),
329 ClassDecl->getInstanceMethods());
330 RewriteMethods(ClassDecl->getNumClassMethods(),
331 ClassDecl->getClassMethods());
Steve Naroffbef11852007-10-26 20:53:56 +0000332
Steve Naroff2feac5e2007-10-30 03:43:13 +0000333 // Lastly, comment out the @end.
334 Rewrite.ReplaceText(ClassDecl->getAtEndLoc(), 0, "// ", 3);
Steve Naroffbef11852007-10-26 20:53:56 +0000335}
336
Chris Lattnerf04da132007-10-24 17:06:59 +0000337//===----------------------------------------------------------------------===//
338// Function Body / Expression rewriting
339//===----------------------------------------------------------------------===//
340
Chris Lattnere64b7772007-10-24 16:57:36 +0000341Stmt *RewriteTest::RewriteFunctionBody(Stmt *S) {
Chris Lattner311ff022007-10-16 22:36:42 +0000342 // Otherwise, just rewrite all children.
343 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
344 CI != E; ++CI)
Chris Lattner50754772007-10-17 21:28:00 +0000345 if (*CI)
Chris Lattnere64b7772007-10-24 16:57:36 +0000346 *CI = RewriteFunctionBody(*CI);
Steve Naroffebf2b562007-10-23 23:50:29 +0000347
348 // Handle specific things.
349 if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
350 return RewriteAtEncode(AtEncode);
351
Steve Naroff934f2762007-10-24 22:48:43 +0000352 if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {
353 // Before we rewrite it, put the original message expression in a comment.
354 SourceLocation startLoc = MessExpr->getLocStart();
355 SourceLocation endLoc = MessExpr->getLocEnd();
356
357 const char *startBuf = SM->getCharacterData(startLoc);
358 const char *endBuf = SM->getCharacterData(endLoc);
359
360 std::string messString;
361 messString += "// ";
362 messString.append(startBuf, endBuf-startBuf+1);
363 messString += "\n";
Steve Naroffbef11852007-10-26 20:53:56 +0000364
Steve Naroff934f2762007-10-24 22:48:43 +0000365 // FIXME: Missing definition of Rewrite.InsertText(clang::SourceLocation, char const*, unsigned int).
366 // Rewrite.InsertText(startLoc, messString.c_str(), messString.size());
367 // Tried this, but it didn't work either...
Steve Naroff752d6ef2007-10-30 16:42:30 +0000368 // Rewrite.ReplaceText(startLoc, 0, messString.c_str(), messString.size());
Steve Naroffebf2b562007-10-23 23:50:29 +0000369 return RewriteMessageExpr(MessExpr);
Steve Naroff934f2762007-10-24 22:48:43 +0000370 }
Chris Lattnere64b7772007-10-24 16:57:36 +0000371 // Return this stmt unmodified.
372 return S;
Chris Lattner311ff022007-10-16 22:36:42 +0000373}
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +0000374
Chris Lattnere64b7772007-10-24 16:57:36 +0000375Stmt *RewriteTest::RewriteAtEncode(ObjCEncodeExpr *Exp) {
Chris Lattner01c57482007-10-17 22:35:30 +0000376 // Create a new string expression.
377 QualType StrType = Context->getPointerType(Context->CharTy);
Anders Carlsson85f9bce2007-10-29 05:01:08 +0000378 std::string StrEncoding;
379 Context->getObjcEncodingForType(Exp->getEncodedType(), StrEncoding);
380 Expr *Replacement = new StringLiteral(StrEncoding.c_str(),
381 StrEncoding.length(), false, StrType,
Chris Lattner01c57482007-10-17 22:35:30 +0000382 SourceLocation(), SourceLocation());
383 Rewrite.ReplaceStmt(Exp, Replacement);
Chris Lattnere64b7772007-10-24 16:57:36 +0000384 delete Exp;
385 return Replacement;
Chris Lattner311ff022007-10-16 22:36:42 +0000386}
387
Steve Naroff934f2762007-10-24 22:48:43 +0000388CallExpr *RewriteTest::SynthesizeCallToFunctionDecl(
389 FunctionDecl *FD, Expr **args, unsigned nargs) {
Steve Naroffebf2b562007-10-23 23:50:29 +0000390 // Get the type, we will need to reference it in a couple spots.
Steve Naroff934f2762007-10-24 22:48:43 +0000391 QualType msgSendType = FD->getType();
Steve Naroffebf2b562007-10-23 23:50:29 +0000392
393 // Create a reference to the objc_msgSend() declaration.
Steve Naroff934f2762007-10-24 22:48:43 +0000394 DeclRefExpr *DRE = new DeclRefExpr(FD, msgSendType, SourceLocation());
Steve Naroffebf2b562007-10-23 23:50:29 +0000395
396 // Now, we cast the reference to a pointer to the objc_msgSend type.
Chris Lattnerf04da132007-10-24 17:06:59 +0000397 QualType pToFunc = Context->getPointerType(msgSendType);
Steve Naroffebf2b562007-10-23 23:50:29 +0000398 ImplicitCastExpr *ICE = new ImplicitCastExpr(pToFunc, DRE);
399
400 const FunctionType *FT = msgSendType->getAsFunctionType();
Chris Lattnere64b7772007-10-24 16:57:36 +0000401
Steve Naroff934f2762007-10-24 22:48:43 +0000402 return new CallExpr(ICE, args, nargs, FT->getResultType(), SourceLocation());
403}
404
Steve Naroff09b266e2007-10-30 23:14:51 +0000405void RewriteTest::RewriteFunctionDecl(FunctionDecl *FD) {
406 // declared in <objc/objc.h>
407 if (strcmp(FD->getName(), "sel_getUid") == 0)
408 SelGetUidFunctionDecl = FD;
409
410 // FIXME: Check if any types are isa<ObjcQualifiedInterfaceType> (yuck).
411}
412
413// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
414void RewriteTest::SynthMsgSendFunctionDecl() {
415 IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend");
416 llvm::SmallVector<QualType, 16> ArgTys;
417 QualType argT = Context->getObjcIdType();
418 assert(!argT.isNull() && "Can't find 'id' type");
419 ArgTys.push_back(argT);
420 argT = Context->getObjcSelType();
421 assert(!argT.isNull() && "Can't find 'SEL' type");
422 ArgTys.push_back(argT);
423 QualType msgSendType = Context->getFunctionType(Context->getObjcIdType(),
424 &ArgTys[0], ArgTys.size(),
425 true /*isVariadic*/);
426 MsgSendFunctionDecl = new FunctionDecl(SourceLocation(),
427 msgSendIdent, msgSendType,
428 FunctionDecl::Extern, false, 0);
429}
430
431// SynthGetClassFunctionDecl - id objc_getClass(const char *name);
432void RewriteTest::SynthGetClassFunctionDecl() {
433 IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass");
434 llvm::SmallVector<QualType, 16> ArgTys;
435 ArgTys.push_back(Context->getPointerType(
436 Context->CharTy.getQualifiedType(QualType::Const)));
437 QualType getClassType = Context->getFunctionType(Context->getObjcIdType(),
438 &ArgTys[0], ArgTys.size(),
439 false /*isVariadic*/);
440 GetClassFunctionDecl = new FunctionDecl(SourceLocation(),
441 getClassIdent, getClassType,
442 FunctionDecl::Extern, false, 0);
443}
444
Steve Naroff934f2762007-10-24 22:48:43 +0000445Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) {
Steve Naroff934f2762007-10-24 22:48:43 +0000446 assert(SelGetUidFunctionDecl && "Can't find sel_getUid() decl");
Steve Naroff09b266e2007-10-30 23:14:51 +0000447 if (!MsgSendFunctionDecl)
448 SynthMsgSendFunctionDecl();
449 if (!GetClassFunctionDecl)
450 SynthGetClassFunctionDecl();
Steve Naroff934f2762007-10-24 22:48:43 +0000451
452 // Synthesize a call to objc_msgSend().
453 llvm::SmallVector<Expr*, 8> MsgExprs;
454 IdentifierInfo *clsName = Exp->getClassName();
455
456 // Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend().
457 if (clsName) { // class message.
458 llvm::SmallVector<Expr*, 8> ClsExprs;
459 QualType argType = Context->getPointerType(Context->CharTy);
460 ClsExprs.push_back(new StringLiteral(clsName->getName(),
461 clsName->getLength(),
462 false, argType, SourceLocation(),
463 SourceLocation()));
464 CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
465 &ClsExprs[0], ClsExprs.size());
466 MsgExprs.push_back(Cls);
467 } else // instance message.
468 MsgExprs.push_back(Exp->getReceiver());
469
470 // Create a call to sel_getUid("selName"), it will be the 2nd argument.
471 llvm::SmallVector<Expr*, 8> SelExprs;
472 QualType argType = Context->getPointerType(Context->CharTy);
473 SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
474 Exp->getSelector().getName().size(),
475 false, argType, SourceLocation(),
476 SourceLocation()));
477 CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
478 &SelExprs[0], SelExprs.size());
479 MsgExprs.push_back(SelExp);
480
481 // Now push any user supplied arguments.
482 for (unsigned i = 0; i < Exp->getNumArgs(); i++) {
483 MsgExprs.push_back(Exp->getArg(i));
484 // We've transferred the ownership to MsgExprs. Null out the argument in
485 // the original expression, since we will delete it below.
486 Exp->setArg(i, 0);
487 }
488 CallExpr *MessExp = SynthesizeCallToFunctionDecl(MsgSendFunctionDecl,
489 &MsgExprs[0], MsgExprs.size());
490 // Now do the actual rewrite.
491 Rewrite.ReplaceStmt(Exp, MessExp);
492
Chris Lattnere64b7772007-10-24 16:57:36 +0000493 delete Exp;
Steve Naroff934f2762007-10-24 22:48:43 +0000494 return MessExp;
Steve Naroffebf2b562007-10-23 23:50:29 +0000495}
496
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000497/// SynthesizeObjcInternalStruct - Rewrite one internal struct corresponding to
498/// an objective-c class with ivars.
499void RewriteTest::SynthesizeObjcInternalStruct(ObjcInterfaceDecl *CDecl,
500 std::string &Result) {
501 assert(CDecl && "Class missing in SynthesizeObjcInternalStruct");
502 assert(CDecl->getName() && "Name missing in SynthesizeObjcInternalStruct");
503 ObjcInterfaceDecl *RCDecl = CDecl->getSuperClass();
504 if (RCDecl && !ObjcSynthesizedStructs.count(RCDecl)) {
505 // Do it for the root
506 SynthesizeObjcInternalStruct(RCDecl, Result);
507 }
508
509 int NumIvars = CDecl->getIntfDeclNumIvars();
510 if (NumIvars <= 0 && (!RCDecl || !ObjcSynthesizedStructs.count(RCDecl)))
511 return;
512
513 Result += "\nstruct _interface_";
514 Result += CDecl->getName();
515 Result += " {\n";
516 if (RCDecl && ObjcSynthesizedStructs.count(RCDecl)) {
517 Result += "\tstruct _interface_";
518 Result += RCDecl->getName();
519 Result += " _";
520 Result += RCDecl->getName();
521 Result += ";\n";
522 }
523
524 ObjcIvarDecl **Ivars = CDecl->getIntfDeclIvars();
525 for (int i = 0; i < NumIvars; i++) {
526 Result += "\t";
527 std::string Name = Ivars[i]->getName();
528 Ivars[i]->getType().getAsStringInternal(Name);
529 Result += Name;
530 Result += ";\n";
531 }
532 Result += "};\n";
533 // Mark this struct as having been generated.
534 if (!ObjcSynthesizedStructs.insert(CDecl))
535 assert(true && "struct already synthesize- SynthesizeObjcInternalStruct");
536}
537
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000538// RewriteObjcMethodsMetaData - Rewrite methods metadata for instance or
539/// class methods.
540void RewriteTest::RewriteObjcMethodsMetaData(ObjcMethodDecl **Methods,
541 int NumMethods,
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +0000542 bool IsInstanceMethod,
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000543 const char *prefix,
Chris Lattner158ecb92007-10-25 17:07:24 +0000544 const char *ClassName,
545 std::string &Result) {
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000546 static bool objc_impl_method = false;
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000547 if (NumMethods > 0 && !objc_impl_method) {
548 /* struct _objc_method {
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000549 SEL _cmd;
550 char *method_types;
551 void *_imp;
552 }
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000553 */
Chris Lattner158ecb92007-10-25 17:07:24 +0000554 Result += "\nstruct _objc_method {\n";
555 Result += "\tSEL _cmd;\n";
556 Result += "\tchar *method_types;\n";
557 Result += "\tvoid *_imp;\n";
558 Result += "};\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000559
560 /* struct _objc_method_list {
561 struct _objc_method_list *next_method;
562 int method_count;
563 struct _objc_method method_list[];
564 }
565 */
566 Result += "\nstruct _objc_method_list {\n";
567 Result += "\tstruct _objc_method_list *next_method;\n";
568 Result += "\tint method_count;\n";
569 Result += "\tstruct _objc_method method_list[];\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000570 objc_impl_method = true;
Fariborz Jahanian776d6ff2007-10-19 00:36:46 +0000571 }
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000572 // Build _objc_method_list for class's methods if needed
573 if (NumMethods > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000574 Result += "\nstatic struct _objc_method_list _OBJC_";
Chris Lattner158ecb92007-10-25 17:07:24 +0000575 Result += prefix;
576 Result += IsInstanceMethod ? "INSTANCE" : "CLASS";
577 Result += "_METHODS_";
578 Result += ClassName;
579 Result += " __attribute__ ((section (\"__OBJC, __";
580 Result += IsInstanceMethod ? "inst" : "cls";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000581 Result += "_meth\")))= ";
582 Result += "{\n\t0, " + utostr(NumMethods) + "\n";
583
584 Result += "\t,{{(SEL)\"";
585 Result += Methods[0]->getSelector().getName().c_str();
Fariborz Jahanian33e1d642007-10-29 22:57:28 +0000586 std::string MethodTypeString;
587 Context->getObjcEncodingForMethodDecl(Methods[0], MethodTypeString);
588 Result += "\", \"";
589 Result += MethodTypeString;
590 Result += "\", 0}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000591 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahanian33e1d642007-10-29 22:57:28 +0000592 // TODO: Need method address as 3rd initializer.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000593 Result += "\t ,{(SEL)\"";
594 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanian33e1d642007-10-29 22:57:28 +0000595 std::string MethodTypeString;
596 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
597 Result += "\", \"";
598 Result += MethodTypeString;
599 Result += "\", 0}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000600 }
601 Result += "\t }\n};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000602 }
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000603}
604
605/// RewriteObjcProtocolsMetaData - Rewrite protocols meta-data.
606void RewriteTest::RewriteObjcProtocolsMetaData(ObjcProtocolDecl **Protocols,
607 int NumProtocols,
608 const char *prefix,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000609 const char *ClassName,
610 std::string &Result) {
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000611 static bool objc_protocol_methods = false;
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000612 if (NumProtocols > 0) {
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000613 for (int i = 0; i < NumProtocols; i++) {
614 ObjcProtocolDecl *PDecl = Protocols[i];
615 // Output struct protocol_methods holder of method selector and type.
616 if (!objc_protocol_methods &&
617 (PDecl->getNumInstanceMethods() > 0
618 || PDecl->getNumClassMethods() > 0)) {
619 /* struct protocol_methods {
620 SEL _cmd;
621 char *method_types;
622 }
623 */
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000624 Result += "\nstruct protocol_methods {\n";
625 Result += "\tSEL _cmd;\n";
626 Result += "\tchar *method_types;\n";
627 Result += "};\n";
628
629 /* struct _objc_protocol_method_list {
630 int protocol_method_count;
631 struct protocol_methods protocols[];
632 }
633 */
634 Result += "\nstruct _objc_protocol_method_list {\n";
635 Result += "\tint protocol_method_count;\n";
636 Result += "\tstruct protocol_methods protocols[];\n};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000637 objc_protocol_methods = true;
638 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000639
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000640 // Output instance methods declared in this protocol.
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000641 int NumMethods = PDecl->getNumInstanceMethods();
642 if (NumMethods > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000643 Result += "\nstatic struct _objc_protocol_method_list "
644 "_OBJC_PROTOCOL_INSTANCE_METHODS_";
645 Result += PDecl->getName();
646 Result += " __attribute__ ((section (\"__OBJC, __cat_inst_meth\")))= "
647 "{\n\t" + utostr(NumMethods) + "\n";
648
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000649 ObjcMethodDecl **Methods = PDecl->getInstanceMethods();
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000650 Result += "\t,{{(SEL)\"";
651 Result += Methods[0]->getSelector().getName().c_str();
652 Result += "\", \"\"}\n";
653
654 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000655 Result += "\t ,{(SEL)\"";
656 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanian33e1d642007-10-29 22:57:28 +0000657 std::string MethodTypeString;
658 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
659 Result += "\", \"";
660 Result += MethodTypeString;
661 Result += "\"}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000662 }
663 Result += "\t }\n};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000664 }
665
666 // Output class methods declared in this protocol.
667 NumMethods = PDecl->getNumClassMethods();
668 if (NumMethods > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000669 Result += "\nstatic struct _objc_protocol_method_list "
670 "_OBJC_PROTOCOL_CLASS_METHODS_";
671 Result += PDecl->getName();
672 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
673 "{\n\t";
674 Result += utostr(NumMethods);
675 Result += "\n";
676
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000677 ObjcMethodDecl **Methods = PDecl->getClassMethods();
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000678 Result += "\t,{{(SEL)\"";
679 Result += Methods[0]->getSelector().getName().c_str();
680 Result += "\", \"\"}\n";
681
682 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000683 Result += "\t ,{(SEL)\"";
684 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanian33e1d642007-10-29 22:57:28 +0000685 std::string MethodTypeString;
686 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
687 Result += "\", \"";
688 Result += MethodTypeString;
689 Result += "\"}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000690 }
691 Result += "\t }\n};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000692 }
693 // Output:
694 /* struct _objc_protocol {
695 // Objective-C 1.0 extensions
696 struct _objc_protocol_extension *isa;
697 char *protocol_name;
698 struct _objc_protocol **protocol_list;
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000699 struct _objc_protocol_method_list *instance_methods;
700 struct _objc_protocol_method_list *class_methods;
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000701 };
702 */
703 static bool objc_protocol = false;
704 if (!objc_protocol) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000705 Result += "\nstruct _objc_protocol {\n";
706 Result += "\tstruct _objc_protocol_extension *isa;\n";
707 Result += "\tchar *protocol_name;\n";
708 Result += "\tstruct _objc_protocol **protocol_list;\n";
709 Result += "\tstruct _objc_protocol_method_list *instance_methods;\n";
710 Result += "\tstruct _objc_protocol_method_list *class_methods;\n";
711 Result += "};\n";
712
713 /* struct _objc_protocol_list {
714 struct _objc_protocol_list *next;
715 int protocol_count;
716 struct _objc_protocol *class_protocols[];
717 }
718 */
719 Result += "\nstruct _objc_protocol_list {\n";
720 Result += "\tstruct _objc_protocol_list *next;\n";
721 Result += "\tint protocol_count;\n";
722 Result += "\tstruct _objc_protocol *class_protocols[];\n";
723 Result += "};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000724 objc_protocol = true;
725 }
726
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000727 Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_";
728 Result += PDecl->getName();
729 Result += " __attribute__ ((section (\"__OBJC, __protocol\")))= "
730 "{\n\t0, \"";
731 Result += PDecl->getName();
732 Result += "\", 0, ";
733 if (PDecl->getInstanceMethods() > 0) {
734 Result += "&_OBJC_PROTOCOL_INSTANCE_METHODS_";
735 Result += PDecl->getName();
736 Result += ", ";
737 }
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000738 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000739 Result += "0, ";
740 if (PDecl->getClassMethods() > 0) {
741 Result += "&_OBJC_PROTOCOL_CLASS_METHODS_";
742 Result += PDecl->getName();
743 Result += "\n";
744 }
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000745 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000746 Result += "0\n";
747 Result += "};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000748 }
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000749 // Output the top lovel protocol meta-data for the class.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000750 Result += "\nstatic struct _objc_protocol_list _OBJC_";
751 Result += prefix;
752 Result += "_PROTOCOLS_";
753 Result += ClassName;
754 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
755 "{\n\t0, ";
756 Result += utostr(NumProtocols);
757 Result += "\n";
758
759 Result += "\t,{&_OBJC_PROTOCOL_";
760 Result += Protocols[0]->getName();
761 Result += " \n";
762
763 for (int i = 1; i < NumProtocols; i++) {
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000764 ObjcProtocolDecl *PDecl = Protocols[i];
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000765 Result += "\t ,&_OBJC_PROTOCOL_";
766 Result += PDecl->getName();
767 Result += "\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000768 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000769 Result += "\t }\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000770 }
771}
772
773/// RewriteObjcCategoryImplDecl - Rewrite metadata for each category
774/// implementation.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000775void RewriteTest::RewriteObjcCategoryImplDecl(ObjcCategoryImplDecl *IDecl,
776 std::string &Result) {
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000777 ObjcInterfaceDecl *ClassDecl = IDecl->getClassInterface();
778 // Find category declaration for this implementation.
779 ObjcCategoryDecl *CDecl;
780 for (CDecl = ClassDecl->getCategoryList(); CDecl;
781 CDecl = CDecl->getNextClassCategory())
782 if (CDecl->getIdentifier() == IDecl->getIdentifier())
783 break;
784 assert(CDecl && "RewriteObjcCategoryImplDecl - bad category");
785
786 char *FullCategoryName = (char*)alloca(
787 strlen(ClassDecl->getName()) + strlen(IDecl->getName()) + 2);
788 sprintf(FullCategoryName, "%s_%s", ClassDecl->getName(), IDecl->getName());
789
790 // Build _objc_method_list for class's instance methods if needed
791 RewriteObjcMethodsMetaData(IDecl->getInstanceMethods(),
792 IDecl->getNumInstanceMethods(),
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +0000793 true,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000794 "CATEGORY_", FullCategoryName, Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000795
796 // Build _objc_method_list for class's class methods if needed
797 RewriteObjcMethodsMetaData(IDecl->getClassMethods(),
798 IDecl->getNumClassMethods(),
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +0000799 false,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000800 "CATEGORY_", FullCategoryName, Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000801
802 // Protocols referenced in class declaration?
803 RewriteObjcProtocolsMetaData(CDecl->getReferencedProtocols(),
804 CDecl->getNumReferencedProtocols(),
805 "CATEGORY",
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000806 FullCategoryName, Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000807
808 /* struct _objc_category {
809 char *category_name;
810 char *class_name;
811 struct _objc_method_list *instance_methods;
812 struct _objc_method_list *class_methods;
813 struct _objc_protocol_list *protocols;
814 // Objective-C 1.0 extensions
815 uint32_t size; // sizeof (struct _objc_category)
816 struct _objc_property_list *instance_properties; // category's own
817 // @property decl.
818 };
819 */
820
821 static bool objc_category = false;
822 if (!objc_category) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000823 Result += "\nstruct _objc_category {\n";
824 Result += "\tchar *category_name;\n";
825 Result += "\tchar *class_name;\n";
826 Result += "\tstruct _objc_method_list *instance_methods;\n";
827 Result += "\tstruct _objc_method_list *class_methods;\n";
828 Result += "\tstruct _objc_protocol_list *protocols;\n";
829 Result += "\tunsigned int size;\n";
830 Result += "\tstruct _objc_property_list *instance_properties;\n";
831 Result += "};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000832 objc_category = true;
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000833 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000834 Result += "\nstatic struct _objc_category _OBJC_CATEGORY_";
835 Result += FullCategoryName;
836 Result += " __attribute__ ((section (\"__OBJC, __category\")))= {\n\t\"";
837 Result += IDecl->getName();
838 Result += "\"\n\t, \"";
839 Result += ClassDecl->getName();
840 Result += "\"\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000841
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000842 if (IDecl->getNumInstanceMethods() > 0) {
843 Result += "\t, (struct _objc_method_list *)"
844 "&_OBJC_CATEGORY_INSTANCE_METHODS_";
845 Result += FullCategoryName;
846 Result += "\n";
847 }
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000848 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000849 Result += "\t, 0\n";
850 if (IDecl->getNumClassMethods() > 0) {
851 Result += "\t, (struct _objc_method_list *)"
852 "&_OBJC_CATEGORY_CLASS_METHODS_";
853 Result += FullCategoryName;
854 Result += "\n";
855 }
856 else
857 Result += "\t, 0\n";
858
859 if (CDecl->getNumReferencedProtocols() > 0) {
860 Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";
861 Result += FullCategoryName;
862 Result += "\n";
863 }
864 else
865 Result += "\t, 0\n";
866 Result += "\t, sizeof(struct _objc_category), 0\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000867}
868
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000869/// SynthesizeIvarOffsetComputation - This rutine synthesizes computation of
870/// ivar offset.
871void RewriteTest::SynthesizeIvarOffsetComputation(ObjcImplementationDecl *IDecl,
872 ObjcIvarDecl *ivar,
873 std::string &Result) {
874 Result += "offsetof(struct _interface_";
875 Result += IDecl->getName();
876 Result += ", ";
877 Result += ivar->getName();
878 Result += ")";
879}
880
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000881//===----------------------------------------------------------------------===//
882// Meta Data Emission
883//===----------------------------------------------------------------------===//
884
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000885void RewriteTest::RewriteObjcClassMetaData(ObjcImplementationDecl *IDecl,
886 std::string &Result) {
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000887 ObjcInterfaceDecl *CDecl = IDecl->getClassInterface();
888
889 // Build _objc_ivar_list metadata for classes ivars if needed
890 int NumIvars = IDecl->getImplDeclNumIvars() > 0
891 ? IDecl->getImplDeclNumIvars()
892 : (CDecl ? CDecl->getIntfDeclNumIvars() : 0);
893
Fariborz Jahanian4d733d32007-10-26 23:09:28 +0000894 SynthesizeObjcInternalStruct(CDecl, Result);
895
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000896 if (NumIvars > 0) {
897 static bool objc_ivar = false;
898 if (!objc_ivar) {
899 /* struct _objc_ivar {
900 char *ivar_name;
901 char *ivar_type;
902 int ivar_offset;
903 };
904 */
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000905 Result += "\nstruct _objc_ivar {\n";
906 Result += "\tchar *ivar_name;\n";
907 Result += "\tchar *ivar_type;\n";
908 Result += "\tint ivar_offset;\n";
909 Result += "};\n";
910
911 /* struct _objc_ivar_list {
912 int ivar_count;
913 struct _objc_ivar ivar_list[];
914 };
915 */
916 Result += "\nstruct _objc_ivar_list {\n";
917 Result += "\tint ivar_count;\n";
918 Result += "\tstruct _objc_ivar ivar_list[];\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000919 objc_ivar = true;
920 }
921
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000922 Result += "\nstatic struct _objc_ivar_list _OBJC_INSTANCE_VARIABLES_";
923 Result += IDecl->getName();
924 Result += " __attribute__ ((section (\"__OBJC, __instance_vars\")))= "
925 "{\n\t";
926 Result += utostr(NumIvars);
927 Result += "\n";
928
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000929 ObjcIvarDecl **Ivars = IDecl->getImplDeclIVars()
930 ? IDecl->getImplDeclIVars()
931 : CDecl->getIntfDeclIvars();
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000932 Result += "\t,{{\"";
933 Result += Ivars[0]->getName();
Fariborz Jahanian160eb652007-10-29 17:16:25 +0000934 Result += "\", \"";
935 std::string StrEncoding;
936 Context->getObjcEncodingForType(Ivars[0]->getType(), StrEncoding);
937 Result += StrEncoding;
938 Result += "\", ";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000939 SynthesizeIvarOffsetComputation(IDecl, Ivars[0], Result);
940 Result += "}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000941 for (int i = 1; i < NumIvars; i++) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000942 Result += "\t ,{\"";
943 Result += Ivars[i]->getName();
Fariborz Jahanian160eb652007-10-29 17:16:25 +0000944 Result += "\", \"";
945 std::string StrEncoding;
946 Context->getObjcEncodingForType(Ivars[i]->getType(), StrEncoding);
947 Result += StrEncoding;
948 Result += "\", ";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000949 SynthesizeIvarOffsetComputation(IDecl, Ivars[i], Result);
950 Result += "}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000951 }
952
953 Result += "\t }\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000954 }
955
956 // Build _objc_method_list for class's instance methods if needed
957 RewriteObjcMethodsMetaData(IDecl->getInstanceMethods(),
958 IDecl->getNumInstanceMethods(),
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000959 true,
960 "", IDecl->getName(), Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000961
962 // Build _objc_method_list for class's class methods if needed
963 RewriteObjcMethodsMetaData(IDecl->getClassMethods(),
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +0000964 IDecl->getNumClassMethods(),
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000965 false,
966 "", IDecl->getName(), Result);
967
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000968 // Protocols referenced in class declaration?
969 RewriteObjcProtocolsMetaData(CDecl->getReferencedProtocols(),
970 CDecl->getNumIntfRefProtocols(),
971 "CLASS",
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000972 CDecl->getName(), Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000973
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +0000974
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000975 // Declaration of class/meta-class metadata
976 /* struct _objc_class {
977 struct _objc_class *isa; // or const char *root_class_name when metadata
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +0000978 const char *super_class_name;
979 char *name;
980 long version;
981 long info;
982 long instance_size;
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000983 struct _objc_ivar_list *ivars;
984 struct _objc_method_list *methods;
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +0000985 struct objc_cache *cache;
986 struct objc_protocol_list *protocols;
987 const char *ivar_layout;
988 struct _objc_class_ext *ext;
989 };
990 */
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000991 static bool objc_class = false;
992 if (!objc_class) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000993 Result += "\nstruct _objc_class {\n";
994 Result += "\tstruct _objc_class *isa;\n";
995 Result += "\tconst char *super_class_name;\n";
996 Result += "\tchar *name;\n";
997 Result += "\tlong version;\n";
998 Result += "\tlong info;\n";
999 Result += "\tlong instance_size;\n";
1000 Result += "\tstruct _objc_ivar_list *ivars;\n";
1001 Result += "\tstruct _objc_method_list *methods;\n";
1002 Result += "\tstruct objc_cache *cache;\n";
1003 Result += "\tstruct _objc_protocol_list *protocols;\n";
1004 Result += "\tconst char *ivar_layout;\n";
1005 Result += "\tstruct _objc_class_ext *ext;\n";
1006 Result += "};\n";
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001007 objc_class = true;
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001008 }
1009
1010 // Meta-class metadata generation.
1011 ObjcInterfaceDecl *RootClass = 0;
1012 ObjcInterfaceDecl *SuperClass = CDecl->getSuperClass();
1013 while (SuperClass) {
1014 RootClass = SuperClass;
1015 SuperClass = SuperClass->getSuperClass();
1016 }
1017 SuperClass = CDecl->getSuperClass();
1018
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001019 Result += "\nstatic struct _objc_class _OBJC_METACLASS_";
1020 Result += CDecl->getName();
1021 Result += " __attribute__ ((section (\"__OBJC, __meta_class\")))= "
1022 "{\n\t(struct _objc_class *)\"";
1023 Result += (RootClass ? RootClass->getName() : CDecl->getName());
1024 Result += "\"";
1025
1026 if (SuperClass) {
1027 Result += ", \"";
1028 Result += SuperClass->getName();
1029 Result += "\", \"";
1030 Result += CDecl->getName();
1031 Result += "\"";
1032 }
1033 else {
1034 Result += ", 0, \"";
1035 Result += CDecl->getName();
1036 Result += "\"";
1037 }
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001038 // TODO: 'ivars' field for root class is currently set to 0.
1039 // 'info' field is initialized to CLS_META(2) for metaclass
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001040 Result += ", 0,2, sizeof(struct _objc_class), 0";
1041 if (CDecl->getNumClassMethods() > 0) {
1042 Result += "\n\t, &_OBJC_CLASS_METHODS_";
1043 Result += CDecl->getName();
1044 Result += "\n";
1045 }
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001046 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001047 Result += ", 0\n";
1048 if (CDecl->getNumIntfRefProtocols() > 0) {
1049 Result += "\t,0, &_OBJC_CLASS_PROTOCOLS_";
1050 Result += CDecl->getName();
1051 Result += ",0,0\n";
1052 }
Fariborz Jahanian454cb012007-10-24 20:54:23 +00001053 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001054 Result += "\t,0,0,0,0\n";
1055 Result += "};\n";
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001056
1057 // class metadata generation.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001058 Result += "\nstatic struct _objc_class _OBJC_CLASS_";
1059 Result += CDecl->getName();
1060 Result += " __attribute__ ((section (\"__OBJC, __class\")))= "
1061 "{\n\t&_OBJC_METACLASS_";
1062 Result += CDecl->getName();
1063 if (SuperClass) {
1064 Result += ", \"";
1065 Result += SuperClass->getName();
1066 Result += "\", \"";
1067 Result += CDecl->getName();
1068 Result += "\"";
1069 }
1070 else {
1071 Result += ", 0, \"";
1072 Result += CDecl->getName();
1073 Result += "\"";
1074 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001075 // 'info' field is initialized to CLS_CLASS(1) for class
Fariborz Jahanian4d733d32007-10-26 23:09:28 +00001076 Result += ", 0,1";
1077 if (!ObjcSynthesizedStructs.count(CDecl))
1078 Result += ",0";
1079 else {
1080 // class has size. Must synthesize its size.
1081 Result += ",sizeof(struct _interface_";
1082 Result += CDecl->getName();
1083 Result += ")";
1084 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001085 if (NumIvars > 0) {
1086 Result += ", &_OBJC_INSTANCE_VARIABLES_";
1087 Result += CDecl->getName();
1088 Result += "\n\t";
1089 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001090 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001091 Result += ",0";
1092 if (IDecl->getNumInstanceMethods() > 0) {
1093 Result += ", &_OBJC_INSTANCE_METHODS_";
1094 Result += CDecl->getName();
1095 Result += ", 0\n\t";
1096 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001097 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001098 Result += ",0,0";
1099 if (CDecl->getNumIntfRefProtocols() > 0) {
1100 Result += ", &_OBJC_CLASS_PROTOCOLS_";
1101 Result += CDecl->getName();
1102 Result += ", 0,0\n";
1103 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001104 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001105 Result += ",0,0,0\n";
1106 Result += "};\n";
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001107}
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00001108
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001109void RewriteTest::WriteObjcMetaData(std::string &Result) {
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001110 int ClsDefCount = ClassImplementation.size();
1111 int CatDefCount = CategoryImplementation.size();
1112 if (ClsDefCount == 0 && CatDefCount == 0)
1113 return;
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00001114
Fariborz Jahanian454cb012007-10-24 20:54:23 +00001115 // TODO: This is temporary until we decide how to access objc types in a
1116 // c program
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001117 Result += "#include <Objc/objc.h>\n";
1118 // This is needed for use of offsetof
1119 Result += "#include <stddef.h>\n";
Fariborz Jahanian454cb012007-10-24 20:54:23 +00001120
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001121 // For each implemented class, write out all its meta data.
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00001122 for (int i = 0; i < ClsDefCount; i++)
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001123 RewriteObjcClassMetaData(ClassImplementation[i], Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001124
1125 // For each implemented category, write out all its meta data.
1126 for (int i = 0; i < CatDefCount; i++)
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001127 RewriteObjcCategoryImplDecl(CategoryImplementation[i], Result);
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00001128
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001129 // Write objc_symtab metadata
1130 /*
1131 struct _objc_symtab
1132 {
1133 long sel_ref_cnt;
1134 SEL *refs;
1135 short cls_def_cnt;
1136 short cat_def_cnt;
1137 void *defs[cls_def_cnt + cat_def_cnt];
1138 };
1139 */
1140
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001141 Result += "\nstruct _objc_symtab {\n";
1142 Result += "\tlong sel_ref_cnt;\n";
1143 Result += "\tSEL *refs;\n";
1144 Result += "\tshort cls_def_cnt;\n";
1145 Result += "\tshort cat_def_cnt;\n";
1146 Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n";
1147 Result += "};\n\n";
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001148
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001149 Result += "static struct _objc_symtab "
1150 "_OBJC_SYMBOLS __attribute__((section (\"__OBJC, __symbols\")))= {\n";
1151 Result += "\t0, 0, " + utostr(ClsDefCount)
1152 + ", " + utostr(CatDefCount) + "\n";
1153 for (int i = 0; i < ClsDefCount; i++) {
1154 Result += "\t,&_OBJC_CLASS_";
1155 Result += ClassImplementation[i]->getName();
1156 Result += "\n";
1157 }
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001158
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001159 for (int i = 0; i < CatDefCount; i++) {
1160 Result += "\t,&_OBJC_CATEGORY_";
1161 Result += CategoryImplementation[i]->getClassInterface()->getName();
1162 Result += "_";
1163 Result += CategoryImplementation[i]->getName();
1164 Result += "\n";
1165 }
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001166
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001167 Result += "};\n\n";
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001168
1169 // Write objc_module metadata
1170
1171 /*
1172 struct _objc_module {
1173 long version;
1174 long size;
1175 const char *name;
1176 struct _objc_symtab *symtab;
1177 }
1178 */
1179
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001180 Result += "\nstruct _objc_module {\n";
1181 Result += "\tlong version;\n";
1182 Result += "\tlong size;\n";
1183 Result += "\tconst char *name;\n";
1184 Result += "\tstruct _objc_symtab *symtab;\n";
1185 Result += "};\n\n";
1186 Result += "static struct _objc_module "
1187 "_OBJC_MODULES __attribute__ ((section (\"__OBJC, __module_info\")))= {\n";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001188 Result += "\t" + utostr(OBJC_ABI_VERSION) +
1189 ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001190 Result += "};\n\n";
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001191}
Chris Lattner311ff022007-10-16 22:36:42 +00001192