blob: 6b625a67e79661ba08fc7b59b93c119e409d1471 [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 Lattner77cd2a02007-10-11 00:43:27 +000020using namespace clang;
21
22
23namespace {
Chris Lattner8a12c272007-10-11 18:38:32 +000024 class RewriteTest : public ASTConsumer {
Chris Lattner2c64b7b2007-10-16 21:07:07 +000025 Rewriter Rewrite;
Chris Lattner01c57482007-10-17 22:35:30 +000026 ASTContext *Context;
Chris Lattner77cd2a02007-10-11 00:43:27 +000027 SourceManager *SM;
Chris Lattner8a12c272007-10-11 18:38:32 +000028 unsigned MainFileID;
Chris Lattner2c64b7b2007-10-16 21:07:07 +000029 SourceLocation LastIncLoc;
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +000030 llvm::SmallVector<ObjcImplementationDecl *, 8> ClassImplementation;
31 llvm::SmallVector<ObjcCategoryImplDecl *, 8> CategoryImplementation;
Steve Naroffebf2b562007-10-23 23:50:29 +000032
33 FunctionDecl *MsgSendFunctionDecl;
34 FunctionDecl *GetClassFunctionDecl;
35
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +000036 static const int OBJC_ABI_VERSION =7 ;
Chris Lattner77cd2a02007-10-11 00:43:27 +000037 public:
Chris Lattner01c57482007-10-17 22:35:30 +000038 void Initialize(ASTContext &context, unsigned mainFileID) {
39 Context = &context;
40 SM = &Context->SourceMgr;
Chris Lattner8a12c272007-10-11 18:38:32 +000041 MainFileID = mainFileID;
Steve Naroffebf2b562007-10-23 23:50:29 +000042 MsgSendFunctionDecl = 0;
Steve Naroffc0006092007-10-24 01:09:48 +000043 GetClassFunctionDecl = 0;
Chris Lattner01c57482007-10-17 22:35:30 +000044 Rewrite.setSourceMgr(Context->SourceMgr);
Chris Lattner77cd2a02007-10-11 00:43:27 +000045 }
46
47 virtual void HandleTopLevelDecl(Decl *D);
Chris Lattner8a12c272007-10-11 18:38:32 +000048
Chris Lattner2c64b7b2007-10-16 21:07:07 +000049 void HandleDeclInMainFile(Decl *D);
50 void RewriteInclude(SourceLocation Loc);
Chris Lattner311ff022007-10-16 22:36:42 +000051
Chris Lattnere64b7772007-10-24 16:57:36 +000052 Stmt *RewriteFunctionBody(Stmt *S);
53 Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
54 Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
Steve Naroff7e158912007-10-23 20:20:08 +000055 void RewriteForwardClassDecl(ObjcClassDecl *Dcl);
56
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +000057 void WriteObjcClassMetaData(ObjcImplementationDecl *IDecl);
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +000058 void WriteObjcMetaData();
59
Chris Lattner8a12c272007-10-11 18:38:32 +000060 ~RewriteTest();
Chris Lattner77cd2a02007-10-11 00:43:27 +000061 };
62}
63
Chris Lattner8a12c272007-10-11 18:38:32 +000064ASTConsumer *clang::CreateCodeRewriterTest() { return new RewriteTest(); }
Chris Lattner77cd2a02007-10-11 00:43:27 +000065
Chris Lattner8a12c272007-10-11 18:38:32 +000066void RewriteTest::HandleTopLevelDecl(Decl *D) {
Chris Lattner2c64b7b2007-10-16 21:07:07 +000067 // Two cases: either the decl could be in the main file, or it could be in a
68 // #included file. If the former, rewrite it now. If the later, check to see
69 // if we rewrote the #include/#import.
70 SourceLocation Loc = D->getLocation();
71 Loc = SM->getLogicalLoc(Loc);
72
73 // If this is for a builtin, ignore it.
74 if (Loc.isInvalid()) return;
75
Steve Naroffebf2b562007-10-23 23:50:29 +000076 // Look for built-in declarations that we need to refer during the rewrite.
77 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Steve Naroffc0006092007-10-24 01:09:48 +000078 if (strcmp(FD->getName(), "objc_msgSend") == 0)
Steve Naroffebf2b562007-10-23 23:50:29 +000079 MsgSendFunctionDecl = FD;
Steve Naroffc0006092007-10-24 01:09:48 +000080 else if (strcmp(FD->getName(), "objc_getClass") == 0)
Steve Naroffebf2b562007-10-23 23:50:29 +000081 GetClassFunctionDecl = FD;
82 }
Chris Lattner2c64b7b2007-10-16 21:07:07 +000083 if (SM->getDecomposedFileLoc(Loc).first == MainFileID)
84 return HandleDeclInMainFile(D);
85
86 RewriteInclude(Loc);
87}
88
89void RewriteTest::RewriteInclude(SourceLocation Loc) {
90 // Rip up the #include stack to the main file.
91 SourceLocation IncLoc = Loc, NextLoc = Loc;
92 do {
93 IncLoc = Loc;
94 Loc = SM->getLogicalLoc(NextLoc);
95 NextLoc = SM->getIncludeLoc(Loc);
96 } while (!NextLoc.isInvalid());
97
98 // Loc is now the location of the #include filename "foo" or <foo/bar.h>.
99 // IncLoc indicates the header that was included if it is useful.
100 IncLoc = SM->getLogicalLoc(IncLoc);
101 if (SM->getDecomposedFileLoc(Loc).first != MainFileID ||
102 Loc == LastIncLoc)
103 return;
104 LastIncLoc = Loc;
105
106 unsigned IncCol = SM->getColumnNumber(Loc);
107 SourceLocation LineStartLoc = Loc.getFileLocWithOffset(-IncCol+1);
108
109 // Replace the #import with #include.
110 Rewrite.ReplaceText(LineStartLoc, IncCol-1, "#include ", strlen("#include "));
111}
112
113/// HandleDeclInMainFile - This is called for each top-level decl defined in the
114/// main file of the input.
115void RewriteTest::HandleDeclInMainFile(Decl *D) {
Chris Lattner311ff022007-10-16 22:36:42 +0000116 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
117 if (Stmt *Body = FD->getBody())
Chris Lattnere64b7772007-10-24 16:57:36 +0000118 FD->setBody(RewriteFunctionBody(Body));
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +0000119
120 if (ObjcImplementationDecl *CI = dyn_cast<ObjcImplementationDecl>(D))
121 ClassImplementation.push_back(CI);
122 else if (ObjcCategoryImplDecl *CI = dyn_cast<ObjcCategoryImplDecl>(D))
123 CategoryImplementation.push_back(CI);
Steve Naroff7e158912007-10-23 20:20:08 +0000124 else if (ObjcClassDecl *CD = dyn_cast<ObjcClassDecl>(D))
125 RewriteForwardClassDecl(CD);
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000126 // Nothing yet.
Chris Lattner8a12c272007-10-11 18:38:32 +0000127}
128
129
Chris Lattnere64b7772007-10-24 16:57:36 +0000130Stmt *RewriteTest::RewriteFunctionBody(Stmt *S) {
Chris Lattner311ff022007-10-16 22:36:42 +0000131 // Otherwise, just rewrite all children.
132 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
133 CI != E; ++CI)
Chris Lattner50754772007-10-17 21:28:00 +0000134 if (*CI)
Chris Lattnere64b7772007-10-24 16:57:36 +0000135 *CI = RewriteFunctionBody(*CI);
Steve Naroffebf2b562007-10-23 23:50:29 +0000136
137 // Handle specific things.
138 if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
139 return RewriteAtEncode(AtEncode);
140
141 if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S))
142 return RewriteMessageExpr(MessExpr);
143
Chris Lattnere64b7772007-10-24 16:57:36 +0000144 // Return this stmt unmodified.
145 return S;
Chris Lattner311ff022007-10-16 22:36:42 +0000146}
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +0000147
Chris Lattnere64b7772007-10-24 16:57:36 +0000148Stmt *RewriteTest::RewriteAtEncode(ObjCEncodeExpr *Exp) {
Chris Lattner01c57482007-10-17 22:35:30 +0000149 // Create a new string expression.
150 QualType StrType = Context->getPointerType(Context->CharTy);
151 Expr *Replacement = new StringLiteral("foo", 3, false, StrType,
152 SourceLocation(), SourceLocation());
153 Rewrite.ReplaceStmt(Exp, Replacement);
Chris Lattnere64b7772007-10-24 16:57:36 +0000154 delete Exp;
155 return Replacement;
Chris Lattner311ff022007-10-16 22:36:42 +0000156}
157
Steve Naroffebf2b562007-10-23 23:50:29 +0000158
Chris Lattnere64b7772007-10-24 16:57:36 +0000159Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) {
Steve Naroffebf2b562007-10-23 23:50:29 +0000160 assert(MsgSendFunctionDecl && "Can't find objc_msgSend() decl");
161 //Exp->dumpPretty();
162 //printf("\n");
163
164 // Synthesize a call to objc_msgSend().
165
166 // Get the type, we will need to reference it in a couple spots.
167 QualType msgSendType = MsgSendFunctionDecl->getType();
168
169 // Create a reference to the objc_msgSend() declaration.
170 DeclRefExpr *DRE = new DeclRefExpr(MsgSendFunctionDecl, msgSendType,
171 SourceLocation());
172
173 // Now, we cast the reference to a pointer to the objc_msgSend type.
174 QualType pToFunc = Context->getPointerType(msgSendType);
175 ImplicitCastExpr *ICE = new ImplicitCastExpr(pToFunc, DRE);
176
177 const FunctionType *FT = msgSendType->getAsFunctionType();
178 CallExpr *CE = new CallExpr(ICE, 0, 0, FT->getResultType(),
179 SourceLocation());
180 Rewrite.ReplaceStmt(Exp, CE);
181 //Exp->dump();
182 //CE->dump();
Chris Lattnere64b7772007-10-24 16:57:36 +0000183
184 // FIXME: Walk the operands of Exp, setting them to null before we delete Exp.
185 // This will be needed when "CE" points to the operands of Exp.
186 delete Exp;
187 return CE;
Steve Naroffebf2b562007-10-23 23:50:29 +0000188}
189
Steve Naroff7e158912007-10-23 20:20:08 +0000190void RewriteTest::RewriteForwardClassDecl(ObjcClassDecl *ClassDecl) {
191 int numDecls = ClassDecl->getNumForwardDecls();
192 ObjcInterfaceDecl **ForwardDecls = ClassDecl->getForwardDecls();
193
194 // Get the start location and compute the semi location.
195 SourceLocation startLoc = ClassDecl->getLocation();
196 const char *startBuf = SM->getCharacterData(startLoc);
Steve Naroffc0006092007-10-24 01:09:48 +0000197 const char *semiPtr = strchr(startBuf, ';');
Steve Naroff7e158912007-10-23 20:20:08 +0000198
199 // Translate to typedef's that forward reference structs with the same name
200 // as the class. As a convenience, we include the original declaration
201 // as a comment.
202 std::string typedefString;
203 typedefString += "// ";
204 typedefString.append(startBuf, semiPtr-startBuf+1);
205 typedefString += "\n";
206 for (int i = 0; i < numDecls; i++) {
207 ObjcInterfaceDecl *ForwardDecl = ForwardDecls[i];
208 typedefString += "typedef struct ";
209 typedefString += ForwardDecl->getName();
210 typedefString += " ";
211 typedefString += ForwardDecl->getName();
212 typedefString += ";\n";
213 }
214
215 // Replace the @class with typedefs corresponding to the classes.
216 Rewrite.ReplaceText(startLoc, semiPtr-startBuf+1,
217 typedefString.c_str(), typedefString.size());
218}
219
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +0000220void RewriteTest::WriteObjcClassMetaData(ObjcImplementationDecl *IDecl) {
221 ObjcInterfaceDecl *CDecl = IDecl->getClassInterface();
222
Fariborz Jahanian776d6ff2007-10-19 00:36:46 +0000223 // Build _objc_ivar_list metadata for classes ivars if needed
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000224 int NumIvars = IDecl->getImplDeclNumIvars() > 0
225 ? IDecl->getImplDeclNumIvars()
226 : (CDecl ? CDecl->getIntfDeclNumIvars() : 0);
227
228 if (NumIvars > 0) {
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +0000229 static bool objc_ivar = false;
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +0000230 if (!objc_ivar) {
231 /* struct _objc_ivar {
232 char *ivar_name;
233 char *ivar_type;
234 int ivar_offset;
235 };
236 */
237 printf("\nstruct _objc_ivar {\n");
238 printf("\tchar *ivar_name;\n");
239 printf("\tchar *ivar_type;\n");
240 printf("\tint ivar_offset;\n");
241 printf("};\n");
242 objc_ivar = true;
243 }
244
245 /* struct _objc_ivar_list {
246 int ivar_count;
247 struct _objc_ivar ivar_list[ivar_count];
248 };
249 */
250 printf("\nstatic struct {\n");
251 printf("\tint ivar_count;\n");
252 printf("\tstruct _objc_ivar ivar_list[%d];\n", NumIvars);
253 printf("} _OBJC_INSTANCE_VARIABLES_%s "
254 "__attribute__ ((section (\"__OBJC, __instance_vars\")))= "
255 "{\n\t%d\n",IDecl->getName(),
256 NumIvars);
257 ObjcIvarDecl **Ivars = IDecl->getImplDeclIVars()
258 ? IDecl->getImplDeclIVars()
259 : CDecl->getIntfDeclIvars();
260 for (int i = 0; i < NumIvars; i++)
261 // TODO: 1) ivar names may have to go to another section. 2) encode
262 // ivar_type type of each ivar . 3) compute and add ivar offset.
263 printf("\t,\"%s\", \"\", 0\n", Ivars[i]->getName());
264 printf("};\n");
265 }
266
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000267 // Build _objc_method for class's instance or class methods metadata if needed
268 static bool objc_impl_method = false;
269 if (IDecl->getNumInstanceMethods() > 0 || IDecl->getNumClassMethods() > 0) {
270 if (!objc_impl_method) {
Fariborz Jahanian776d6ff2007-10-19 00:36:46 +0000271 /* struct _objc_method {
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000272 SEL _cmd;
273 char *method_types;
274 void *_imp;
275 }
276 */
Fariborz Jahanian776d6ff2007-10-19 00:36:46 +0000277 printf("\nstruct _objc_method {\n");
278 printf("\tSEL _cmd;\n");
279 printf("\tchar *method_types;\n");
280 printf("\tvoid *_imp;\n");
281 printf("};\n");
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000282 objc_impl_method = true;
Fariborz Jahanian776d6ff2007-10-19 00:36:46 +0000283 }
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000284 }
285 // Build _objc_method_list for class's instance methods if needed
286 if (IDecl->getNumInstanceMethods() > 0) {
287 int NumMethods = IDecl->getNumInstanceMethods();
Fariborz Jahanian776d6ff2007-10-19 00:36:46 +0000288 /* struct _objc_method_list {
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000289 struct _objc_method_list *next_method;
Fariborz Jahanian776d6ff2007-10-19 00:36:46 +0000290 int method_count;
291 struct _objc_method method_list[method_count];
292 }
293 */
294 printf("\nstatic struct {\n");
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000295 printf("\tstruct _objc_method_list *next_method;\n");
Fariborz Jahanian776d6ff2007-10-19 00:36:46 +0000296 printf("\tint method_count;\n");
297 printf("\tstruct _objc_method method_list[%d];\n", NumMethods);
298 printf("} _OBJC_INSTANCE_METHODS_%s "
299 "__attribute__ ((section (\"__OBJC, __inst_meth\")))= "
300 "{\n\t0, %d\n", IDecl->getName(), NumMethods);
301 ObjcMethodDecl **Methods = IDecl->getInstanceMethods();
302 for (int i = 0; i < NumMethods; i++)
303 // TODO: 1) method selector name may hav to go into their own section
304 // 2) encode method types for use here (which may have to go into
305 // __meth_var_types section, 3) Need method address as 3rd initializer.
306 printf("\t,(SEL)\"%s\", \"\", 0\n",
307 Methods[i]->getSelector().getName().c_str());
308 printf("};\n");
309 }
310
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000311 // Build _objc_method_list for class's class methods if needed
312 if (IDecl->getNumClassMethods() > 0) {
313 int NumMethods = IDecl->getNumClassMethods();
314 /* struct _objc_method_list {
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000315 struct _objc_method_list *next_method;
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000316 int method_count;
317 struct _objc_method method_list[method_count];
318 }
319 */
320 printf("\nstatic struct {\n");
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000321 printf("\tstruct _objc_method_list *next_method;\n");
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000322 printf("\tint method_count;\n");
323 printf("\tstruct _objc_method method_list[%d];\n", NumMethods);
324 printf("} _OBJC_CLASS_METHODS_%s "
325 "__attribute__ ((section (\"__OBJC, __cls_meth\")))= "
326 "{\n\t0, %d\n", IDecl->getName(), NumMethods);
327 ObjcMethodDecl **Methods = IDecl->getClassMethods();
328 for (int i = 0; i < NumMethods; i++)
329 // TODO: 1) method selector name may hav to go into their own section
330 // 2) encode method types for use here (which may have to go into
331 // __meth_var_types section, 3) Need method address as 3rd initializer.
332 printf("\t,(SEL)\"%s\", \"\", 0\n",
333 Methods[i]->getSelector().getName().c_str());
334 printf("};\n");
335 }
Fariborz Jahanian776d6ff2007-10-19 00:36:46 +0000336
Fariborz Jahaniane887c092007-10-22 21:41:37 +0000337 // Protocols referenced in class declaration?
338 static bool objc_protocol_methods = false;
339 int NumProtocols = CDecl->getNumIntfRefProtocols();
340 if (NumProtocols > 0) {
341 ObjcProtocolDecl **Protocols = CDecl->getReferencedProtocols();
342 for (int i = 0; i < NumProtocols; i++) {
343 ObjcProtocolDecl *PDecl = Protocols[i];
344 // Output struct protocol_methods holder of method selector and type.
345 if (!objc_protocol_methods &&
346 (PDecl->getNumInstanceMethods() > 0
347 || PDecl->getNumClassMethods() > 0)) {
348 /* struct protocol_methods {
349 SEL _cmd;
350 char *method_types;
351 }
352 */
353 printf("\nstruct protocol_methods {\n");
354 printf("\tSEL _cmd;\n");
355 printf("\tchar *method_types;\n");
356 printf("};\n");
357 objc_protocol_methods = true;
358 }
359 // Output instance methods declared in this protocol.
360 /* struct _objc_protocol_method_list {
361 int protocol_method_count;
362 struct protocol_methods protocols[protocol_method_count];
363 }
364 */
365 int NumMethods = PDecl->getNumInstanceMethods();
366 if (NumMethods > 0) {
367 printf("\nstatic struct {\n");
368 printf("\tint protocol_method_count;\n");
369 printf("\tstruct protocol_methods protocols[%d];\n", NumMethods);
370 printf("} _OBJC_PROTOCOL_INSTANCE_METHODS_%s "
371 "__attribute__ ((section (\"__OBJC, __cat_inst_meth\")))= "
372 "{\n\t%d\n",PDecl->getName(), NumMethods);
373 ObjcMethodDecl **Methods = PDecl->getInstanceMethods();
374 for (int i = 0; i < NumMethods; i++)
375 // TODO: 1) method selector name may hav to go into their own section
376 // 2) encode method types for use here (which may have to go into
377 // __meth_var_types section.
378 printf("\t,(SEL)\"%s\", \"\"\n",
379 Methods[i]->getSelector().getName().c_str());
380 printf("};\n");
381 }
382
383 // Output class methods declared in this protocol.
384 NumMethods = PDecl->getNumClassMethods();
385 if (NumMethods > 0) {
386 printf("\nstatic struct {\n");
387 printf("\tint protocol_method_count;\n");
388 printf("\tstruct protocol_methods protocols[%d];\n", NumMethods);
389 printf("} _OBJC_PROTOCOL_CLASS_METHODS_%s "
390 "__attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
391 "{\n\t%d\n",PDecl->getName(), NumMethods);
392 ObjcMethodDecl **Methods = PDecl->getClassMethods();
393 for (int i = 0; i < NumMethods; i++)
394 // TODO: 1) method selector name may hav to go into their own section
395 // 2) encode method types for use here (which may have to go into
396 // __meth_var_types section.
397 printf("\t,(SEL)\"%s\", \"\"\n",
398 Methods[i]->getSelector().getName().c_str());
399 printf("};\n");
400 }
401 // Output:
402 /* struct _objc_protocol {
403 // Objective-C 1.0 extensions
404 struct _objc_protocol_extension *isa;
405 char *protocol_name;
406 struct _objc_protocol **protocol_list;
407 struct _objc__method_prototype_list *instance_methods;
408 struct _objc__method_prototype_list *class_methods;
409 };
410 */
411 static bool objc_protocol = false;
412 if (!objc_protocol) {
413 printf("\nstruct _objc_protocol {\n");
414 printf("\tstruct _objc_protocol_extension *isa;\n");
415 printf("\tchar *protocol_name;\n");
416 printf("\tstruct _objc_protocol **protocol_list;\n");
417 printf("\tstruct _objc__method_prototype_list *instance_methods;\n");
418 printf("\tstruct _objc__method_prototype_list *class_methods;\n");
419 printf("};\n");
420 objc_protocol = true;
421 }
422
423 printf("\nstatic struct _objc_protocol _OBJC_PROTOCOL_%s "
424 "__attribute__ ((section (\"__OBJC, __protocol\")))= "
425 "{\n\t0, \"%s\", 0, ", PDecl->getName(), PDecl->getName());
426 if (PDecl->getInstanceMethods() > 0)
427 printf("(struct _objc__method_prototype_list *)"
428 "&_OBJC_PROTOCOL_INSTANCE_METHODS_%s, ", PDecl->getName());
429 else
430 printf("0, ");
431 if (PDecl->getClassMethods() > 0)
432 printf("(struct _objc__method_prototype_list *)"
433 "&_OBJC_PROTOCOL_CLASS_METHODS_%s\n", PDecl->getName());
434 else
435 printf("0\n");
436 printf("};\n");
437 }
438 }
439 if (NumProtocols > 0) {
440 // Output the top lovel protocol meta-data for the class.
441 /* struct _objc_protocol_list {
442 struct _objc_protocol_list *next;
443 int protocol_count;
444 struct _objc_protocol *class_protocols[protocol_count];
445 }
446 */
447 printf("\nstatic struct {\n");
448 printf("\tstruct _objc_protocol_list *next;\n");
449 printf("\tint protocol_count;\n");
450 printf("\tstruct _objc_protocol *class_protocols[%d];\n"
451 "} _OBJC_CLASS_PROTOCOLS_%s "
452 "__attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
453 "{\n\t0, %d\n",NumProtocols, CDecl->getName(), NumProtocols);
454 ObjcProtocolDecl **Protocols = CDecl->getReferencedProtocols();
455 for (int i = 0; i < NumProtocols; i++) {
456 ObjcProtocolDecl *PDecl = Protocols[i];
457 printf("\t,&_OBJC_PROTOCOL_%s \n",
458 PDecl->getName());
459 }
460 printf("};\n");
461 }
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +0000462
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000463 // Declaration of class/meta-class metadata
464 /* struct _objc_class {
465 struct _objc_class *isa; // or const char *root_class_name when metadata
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +0000466 const char *super_class_name;
467 char *name;
468 long version;
469 long info;
470 long instance_size;
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000471 struct _objc_ivar_list *ivars;
472 struct _objc_method_list *methods;
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +0000473 struct objc_cache *cache;
474 struct objc_protocol_list *protocols;
475 const char *ivar_layout;
476 struct _objc_class_ext *ext;
477 };
478 */
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000479 static bool objc_class = false;
480 if (!objc_class) {
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +0000481 printf("\nstruct _objc_class {\n");
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000482 printf("\tstruct _objc_class *isa;\n");
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +0000483 printf("\tconst char *super_class_name;\n");
484 printf("\tchar *name;\n");
485 printf("\tlong version;\n");
486 printf("\tlong info;\n");
487 printf("\tlong instance_size;\n");
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000488 printf("\tstruct _objc_ivar_list *ivars;\n");
489 printf("\tstruct _objc_method_list *methods;\n");
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +0000490 printf("\tstruct objc_cache *cache;\n");
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000491 printf("\tstruct _objc_protocol_list *protocols;\n");
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +0000492 printf("\tconst char *ivar_layout;\n");
493 printf("\tstruct _objc_class_ext *ext;\n");
494 printf("};\n");
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000495 objc_class = true;
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +0000496 }
497
498 // Meta-class metadata generation.
499 ObjcInterfaceDecl *RootClass = 0;
500 ObjcInterfaceDecl *SuperClass = CDecl->getSuperClass();
501 while (SuperClass) {
502 RootClass = SuperClass;
503 SuperClass = SuperClass->getSuperClass();
504 }
505 SuperClass = CDecl->getSuperClass();
506
507 printf("\nstatic struct _objc_class _OBJC_METACLASS_%s "
508 "__attribute__ ((section (\"__OBJC, __meta_class\")))= "
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000509 "{\n\t(struct _objc_class *)\"%s\"",
510 CDecl->getName(), RootClass ? RootClass->getName()
511 : CDecl->getName());
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +0000512 if (SuperClass)
513 printf(", \"%s\", \"%s\"", SuperClass->getName(), CDecl->getName());
514 else
515 printf(", 0, \"%s\"", CDecl->getName());
516 // FIXME: better way of getting size struct _objc_class (48)
517 // TODO: 'ivars' field for root class is currently set to 0.
518 // 'info' field is initialized to CLS_META(2) for metaclass
519 printf(", 0,2,48,0");
520 if (CDecl->getNumClassMethods() > 0)
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000521 printf("\n\t, (struct _objc_method_list *)&_OBJC_CLASS_METHODS_%s\n",
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +0000522 CDecl->getName());
523 else
524 printf(", 0\n");
525 printf("\t,0,0,0,0\n");
526 printf("};\n");
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000527
528 // class metadata generation.
529 printf("\nstatic struct _objc_class _OBJC_CLASS_%s "
530 "__attribute__ ((section (\"__OBJC, __class\")))= "
531 "{\n\t&_OBJC_METACLASS_%s", CDecl->getName(), CDecl->getName());
532 if (SuperClass)
533 printf(", \"%s\", \"%s\"", SuperClass->getName(), CDecl->getName());
534 else
535 printf(", 0, \"%s\"", CDecl->getName());
536 // 'info' field is initialized to CLS_CLASS(1) for class
537 // TODO: instance_size is curently set to 0.
538 printf(", 0,1,0");
539 if (NumIvars > 0)
540 printf(", (struct _objc_ivar_list *)&_OBJC_INSTANCE_VARIABLES_%s\n\t",
541 CDecl->getName());
542 else
543 printf(",0");
544 if (IDecl->getNumInstanceMethods() > 0)
545 printf(", (struct _objc_method_list*)&_OBJC_INSTANCE_METHODS_%s, 0\n\t",
546 CDecl->getName());
547 else
548 printf(",0,0");
549 if (NumProtocols > 0)
550 printf(", (struct _objc_protocol_list*)&_OBJC_CLASS_PROTOCOLS_%s, 0,0\n",
551 CDecl->getName());
552 else
553 printf(",0,0,0\n");
554 printf("};\n");
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +0000555}
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +0000556
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +0000557void RewriteTest::WriteObjcMetaData() {
558 int ClsDefCount = ClassImplementation.size();
559 int CatDefCount = CategoryImplementation.size();
560 if (ClsDefCount == 0 && CatDefCount == 0)
561 return;
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +0000562
563 // For each defined class, write out all its meta data.
564 for (int i = 0; i < ClsDefCount; i++)
565 WriteObjcClassMetaData(ClassImplementation[i]);
566
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +0000567 // Write objc_symtab metadata
568 /*
569 struct _objc_symtab
570 {
571 long sel_ref_cnt;
572 SEL *refs;
573 short cls_def_cnt;
574 short cat_def_cnt;
575 void *defs[cls_def_cnt + cat_def_cnt];
576 };
577 */
578
579 printf("\nstruct _objc_symtab {\n");
580 printf("\tlong sel_ref_cnt;\n");
581 printf("\tSEL *refs;\n");
582 printf("\tshort cls_def_cnt;\n");
583 printf("\tshort cat_def_cnt;\n");
584 printf("\tvoid *defs[%d];\n", ClsDefCount + CatDefCount);
585 printf("};\n\n");
586
587 printf("static struct _objc_symtab "
588 "_OBJC_SYMBOLS __attribute__ ((section (\"__OBJC, __symbols\")))= {\n");
589 printf("\t0, 0, %d, %d\n", ClsDefCount, CatDefCount);
590 for (int i = 0; i < ClsDefCount; i++)
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000591 printf("\t,&_OBJC_CLASS_%s\n", ClassImplementation[i]->getName());
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +0000592
593 for (int i = 0; i < CatDefCount; i++)
Fariborz Jahaniandeef5182007-10-23 18:53:48 +0000594 printf("\t,&_OBJC_CATEGORY_%s_%s\n",
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +0000595 CategoryImplementation[i]->getClassInterface()->getName(),
596 CategoryImplementation[i]->getName());
597
598 printf("};\n\n");
599
600 // Write objc_module metadata
601
602 /*
603 struct _objc_module {
604 long version;
605 long size;
606 const char *name;
607 struct _objc_symtab *symtab;
608 }
609 */
610
611 printf("\nstruct _objc_module {\n");
612 printf("\tlong version;\n");
613 printf("\tlong size;\n");
614 printf("\tconst char *name;\n");
615 printf("\tstruct _objc_symtab *symtab;");
616 printf("};\n\n");
617 printf("static struct _objc_module "
618 "_OBJC_MODULES __attribute__ ((section (\"__OBJC, __module_info\")))= {\n");
619 printf("\t%d, %d, \"\", &_OBJC_SYMBOLS\n", OBJC_ABI_VERSION, 16);
620 printf("};\n\n");
621}
Chris Lattner311ff022007-10-16 22:36:42 +0000622
Chris Lattner8a12c272007-10-11 18:38:32 +0000623RewriteTest::~RewriteTest() {
Chris Lattner8a12c272007-10-11 18:38:32 +0000624 // Get the top-level buffer that this corresponds to.
625 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
626 const char *MainBufStart = MainBuf.first;
627 const char *MainBufEnd = MainBuf.second;
628
629 // Loop over the whole file, looking for tabs.
630 for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) {
631 if (*BufPtr != '\t')
632 continue;
633
634 // Okay, we found a tab. This tab will turn into at least one character,
635 // but it depends on which 'virtual column' it is in. Compute that now.
636 unsigned VCol = 0;
637 while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' &&
638 BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r')
639 ++VCol;
640
641 // Okay, now that we know the virtual column, we know how many spaces to
642 // insert. We assume 8-character tab-stops.
643 unsigned Spaces = 8-(VCol & 7);
644
645 // Get the location of the tab.
646 SourceLocation TabLoc =
647 SourceLocation::getFileLoc(MainFileID, BufPtr-MainBufStart);
648
649 // Rewrite the single tab character into a sequence of spaces.
Chris Lattner57c337d2007-10-13 00:46:29 +0000650 Rewrite.ReplaceText(TabLoc, 1, " ", Spaces);
Chris Lattner8a12c272007-10-11 18:38:32 +0000651 }
652
653 // Get the buffer corresponding to MainFileID. If we haven't changed it, then
654 // we are done.
655 if (const RewriteBuffer *RewriteBuf =
656 Rewrite.getRewriteBufferFor(MainFileID)) {
Chris Lattner7c239602007-10-13 00:11:23 +0000657 printf("Changed:\n");
658 std::string S(RewriteBuf->begin(), RewriteBuf->end());
659 printf("%s\n", S.c_str());
Chris Lattner8a12c272007-10-11 18:38:32 +0000660 } else {
661 printf("No changes\n");
662 }
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +0000663 // Rewrite Objective-c meta data*
664 WriteObjcMetaData();
Chris Lattner77cd2a02007-10-11 00:43:27 +0000665}