blob: b199f7151f9eaf710ca070aa9c8249cc0f0d5c9b [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 Lattner4478db92007-11-30 22:53:43 +000020#include "clang/Basic/Diagnostic.h"
Chris Lattnerae43eb72007-12-02 01:13:47 +000021#include "clang/Lex/Lexer.h"
Chris Lattnerc3aa5c42007-10-25 17:07:24 +000022#include "llvm/ADT/StringExtras.h"
Fariborz Jahanianf185aef2007-10-26 19:46:17 +000023#include "llvm/ADT/SmallPtrSet.h"
Chris Lattnerae43eb72007-12-02 01:13:47 +000024#include "llvm/Support/MemoryBuffer.h"
Steve Naroff764c1ae2007-11-15 10:28:18 +000025#include <sstream>
Chris Lattnerb429ae42007-10-11 00:43:27 +000026using namespace clang;
Chris Lattnerc3aa5c42007-10-25 17:07:24 +000027using llvm::utostr;
Chris Lattnerb429ae42007-10-11 00:43:27 +000028
Chris Lattnerb429ae42007-10-11 00:43:27 +000029namespace {
Chris Lattner569faa62007-10-11 18:38:32 +000030 class RewriteTest : public ASTConsumer {
Chris Lattner74db1682007-10-16 21:07:07 +000031 Rewriter Rewrite;
Chris Lattner258f26c2007-11-30 22:25:36 +000032 Diagnostic &Diags;
Chris Lattnerbf0bfa62007-10-17 22:35:30 +000033 ASTContext *Context;
Chris Lattnerb429ae42007-10-11 00:43:27 +000034 SourceManager *SM;
Chris Lattner569faa62007-10-11 18:38:32 +000035 unsigned MainFileID;
Chris Lattnerae43eb72007-12-02 01:13:47 +000036 const char *MainFileStart, *MainFileEnd;
Chris Lattner74db1682007-10-16 21:07:07 +000037 SourceLocation LastIncLoc;
Fariborz Jahanian640a01f2007-10-18 19:23:00 +000038 llvm::SmallVector<ObjcImplementationDecl *, 8> ClassImplementation;
39 llvm::SmallVector<ObjcCategoryImplDecl *, 8> CategoryImplementation;
Fariborz Jahanianf185aef2007-10-26 19:46:17 +000040 llvm::SmallPtrSet<ObjcInterfaceDecl*, 8> ObjcSynthesizedStructs;
Steve Naroff809b4f02007-10-31 22:11:35 +000041 llvm::SmallPtrSet<ObjcInterfaceDecl*, 8> ObjcForwardDecls;
Fariborz Jahanianbd2fd922007-11-13 21:02:00 +000042 llvm::DenseMap<ObjcMethodDecl*, std::string> MethodInternalNames;
Steve Naroffe9780582007-10-23 23:50:29 +000043
44 FunctionDecl *MsgSendFunctionDecl;
Steve Naroff764c1ae2007-11-15 10:28:18 +000045 FunctionDecl *MsgSendSuperFunctionDecl;
Steve Naroffe9780582007-10-23 23:50:29 +000046 FunctionDecl *GetClassFunctionDecl;
Steve Naroff71226032007-10-24 22:48:43 +000047 FunctionDecl *SelGetUidFunctionDecl;
Steve Naroffabb96362007-11-08 14:30:50 +000048 FunctionDecl *CFStringFunctionDecl;
Steve Naroffe9780582007-10-23 23:50:29 +000049
Steve Naroff0add5d22007-11-03 11:27:19 +000050 // ObjC string constant support.
51 FileVarDecl *ConstantStringClassReference;
52 RecordDecl *NSStringRecord;
Steve Naroff0744c472007-11-04 22:37:50 +000053
Steve Naroff764c1ae2007-11-15 10:28:18 +000054 // Needed for super.
55 ObjcMethodDecl *CurMethodDecl;
56 RecordDecl *SuperStructDecl;
57
Fariborz Jahanian640a01f2007-10-18 19:23:00 +000058 static const int OBJC_ABI_VERSION =7 ;
Chris Lattnerb429ae42007-10-11 00:43:27 +000059 public:
Chris Lattnerbf0bfa62007-10-17 22:35:30 +000060 void Initialize(ASTContext &context, unsigned mainFileID) {
61 Context = &context;
62 SM = &Context->SourceMgr;
Steve Naroffe9780582007-10-23 23:50:29 +000063 MsgSendFunctionDecl = 0;
Steve Naroff764c1ae2007-11-15 10:28:18 +000064 MsgSendSuperFunctionDecl = 0;
Steve Naroff95b28c12007-10-24 01:09:48 +000065 GetClassFunctionDecl = 0;
Steve Naroff71226032007-10-24 22:48:43 +000066 SelGetUidFunctionDecl = 0;
Steve Naroffabb96362007-11-08 14:30:50 +000067 CFStringFunctionDecl = 0;
Steve Naroff0add5d22007-11-03 11:27:19 +000068 ConstantStringClassReference = 0;
69 NSStringRecord = 0;
Steve Naroff764c1ae2007-11-15 10:28:18 +000070 CurMethodDecl = 0;
71 SuperStructDecl = 0;
72
Chris Lattnerae43eb72007-12-02 01:13:47 +000073 // Get the ID and start/end of the main file.
74 MainFileID = mainFileID;
75 const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID);
76 MainFileStart = MainBuf->getBufferStart();
77 MainFileEnd = MainBuf->getBufferEnd();
78
79
Chris Lattnerbf0bfa62007-10-17 22:35:30 +000080 Rewrite.setSourceMgr(Context->SourceMgr);
Steve Narofffcab7932007-11-05 14:55:35 +000081 // declaring objc_selector outside the parameter list removes a silly
82 // scope related warning...
Steve Naroff9b99a262007-11-15 17:06:21 +000083 const char *s = "struct objc_selector; struct objc_class; struct objc_super;\n"
Steve Narofffcab7932007-11-05 14:55:35 +000084 "extern struct objc_object *objc_msgSend"
Steve Naroff0744c472007-11-04 22:37:50 +000085 "(struct objc_object *, struct objc_selector *, ...);\n"
Steve Naroff764c1ae2007-11-15 10:28:18 +000086 "extern struct objc_object *objc_msgSendSuper"
87 "(struct objc_super *, struct objc_selector *, ...);\n"
Steve Naroff0744c472007-11-04 22:37:50 +000088 "extern struct objc_object *objc_getClass"
Steve Naroffd3287d82007-11-07 18:43:40 +000089 "(const char *);\n"
90 "extern void objc_exception_throw(struct objc_object *);\n"
91 "extern void objc_exception_try_enter(void *);\n"
92 "extern void objc_exception_try_exit(void *);\n"
93 "extern struct objc_object *objc_exception_extract(void *);\n"
94 "extern int objc_exception_match"
Fariborz Jahanian8d9c7352007-11-14 22:26:25 +000095 "(struct objc_class *, struct objc_object *, ...);\n"
96 "#include <Objc/objc.h>\n";
Steve Naroffd3287d82007-11-07 18:43:40 +000097
Steve Naroff0744c472007-11-04 22:37:50 +000098 Rewrite.InsertText(SourceLocation::getFileLoc(mainFileID, 0),
99 s, strlen(s));
Chris Lattnerb429ae42007-10-11 00:43:27 +0000100 }
Chris Lattner569faa62007-10-11 18:38:32 +0000101
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000102 // Top Level Driver code.
103 virtual void HandleTopLevelDecl(Decl *D);
Chris Lattner74db1682007-10-16 21:07:07 +0000104 void HandleDeclInMainFile(Decl *D);
Chris Lattner258f26c2007-11-30 22:25:36 +0000105 RewriteTest(Diagnostic &D) : Diags(D) {}
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000106 ~RewriteTest();
107
108 // Syntactic Rewriting.
Steve Naroff0744c472007-11-04 22:37:50 +0000109 void RewritePrologue(SourceLocation Loc);
Chris Lattner74db1682007-10-16 21:07:07 +0000110 void RewriteInclude(SourceLocation Loc);
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000111 void RewriteTabs();
112 void RewriteForwardClassDecl(ObjcClassDecl *Dcl);
Steve Naroff3774dd92007-10-26 20:53:56 +0000113 void RewriteInterfaceDecl(ObjcInterfaceDecl *Dcl);
Fariborz Jahanian0136e372007-11-13 20:04:28 +0000114 void RewriteImplementationDecl(NamedDecl *Dcl);
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000115 void RewriteObjcMethodDecl(ObjcMethodDecl *MDecl, std::string &ResultStr);
Steve Naroff667f1682007-10-30 13:30:57 +0000116 void RewriteCategoryDecl(ObjcCategoryDecl *Dcl);
Steve Narofff4b7d6a2007-10-30 16:42:30 +0000117 void RewriteProtocolDecl(ObjcProtocolDecl *Dcl);
Fariborz Jahanian016a1882007-11-14 00:42:16 +0000118 void RewriteForwardProtocolDecl(ObjcForwardProtocolDecl *Dcl);
Steve Naroff18c83382007-11-13 23:01:27 +0000119 void RewriteMethodDeclarations(int nMethods, ObjcMethodDecl **Methods);
Fariborz Jahanianeca7fad2007-11-07 00:09:37 +0000120 void RewriteProperties(int nProperties, ObjcPropertyDecl **Properties);
Steve Naroff02a82aa2007-10-30 23:14:51 +0000121 void RewriteFunctionDecl(FunctionDecl *FD);
Steve Naroffc8a92d12007-11-01 13:24:47 +0000122 void RewriteObjcQualifiedInterfaceTypes(
123 const FunctionTypeProto *proto, FunctionDecl *FD);
124 bool needToScanForQualifiers(QualType T);
Steve Naroff764c1ae2007-11-15 10:28:18 +0000125 ObjcInterfaceDecl *isSuperReceiver(Expr *recExpr);
126 QualType getSuperStructType();
Chris Lattner6fe8b272007-10-16 22:36:42 +0000127
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000128 // Expression Rewriting.
Steve Naroff334fbc22007-11-09 15:20:18 +0000129 Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S);
Chris Lattner0021f452007-10-24 16:57:36 +0000130 Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
Steve Naroff6b759ce2007-11-15 02:58:25 +0000131 Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV);
Steve Naroff296b74f2007-11-05 14:50:49 +0000132 Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp);
Chris Lattner0021f452007-10-24 16:57:36 +0000133 Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
Steve Naroff0add5d22007-11-03 11:27:19 +0000134 Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp);
Fariborz Jahanian9447e462007-11-05 17:47:33 +0000135 Stmt *RewriteObjcTryStmt(ObjcAtTryStmt *S);
136 Stmt *RewriteObjcCatchStmt(ObjcAtCatchStmt *S);
137 Stmt *RewriteObjcFinallyStmt(ObjcAtFinallyStmt *S);
Steve Naroff8b1fb8c2007-11-07 15:32:26 +0000138 Stmt *RewriteObjcThrowStmt(ObjcAtThrowStmt *S);
Steve Naroff71226032007-10-24 22:48:43 +0000139 CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD,
140 Expr **args, unsigned nargs);
Steve Naroff02a82aa2007-10-30 23:14:51 +0000141 void SynthMsgSendFunctionDecl();
Steve Naroff764c1ae2007-11-15 10:28:18 +0000142 void SynthMsgSendSuperFunctionDecl();
Steve Naroff02a82aa2007-10-30 23:14:51 +0000143 void SynthGetClassFunctionDecl();
Steve Naroffabb96362007-11-08 14:30:50 +0000144 void SynthCFStringFunctionDecl();
145
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000146 // Metadata emission.
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000147 void RewriteObjcClassMetaData(ObjcImplementationDecl *IDecl,
148 std::string &Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000149
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000150 void RewriteObjcCategoryImplDecl(ObjcCategoryImplDecl *CDecl,
151 std::string &Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000152
Steve Naroffb82c50f2007-11-11 17:19:15 +0000153 void RewriteObjcMethodsMetaData(ObjcMethodDecl *const*Methods,
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000154 int NumMethods,
Fariborz Jahaniana3986372007-10-25 00:14:44 +0000155 bool IsInstanceMethod,
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000156 const char *prefix,
Chris Lattnerc3aa5c42007-10-25 17:07:24 +0000157 const char *ClassName,
158 std::string &Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000159
160 void RewriteObjcProtocolsMetaData(ObjcProtocolDecl **Protocols,
161 int NumProtocols,
162 const char *prefix,
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000163 const char *ClassName,
164 std::string &Result);
Fariborz Jahanianf185aef2007-10-26 19:46:17 +0000165 void SynthesizeObjcInternalStruct(ObjcInterfaceDecl *CDecl,
166 std::string &Result);
Fariborz Jahanianf185aef2007-10-26 19:46:17 +0000167 void SynthesizeIvarOffsetComputation(ObjcImplementationDecl *IDecl,
168 ObjcIvarDecl *ivar,
169 std::string &Result);
Fariborz Jahanian8c664912007-11-13 19:21:13 +0000170 void RewriteImplementations(std::string &Result);
Chris Lattnerb429ae42007-10-11 00:43:27 +0000171 };
172}
173
Chris Lattner258f26c2007-11-30 22:25:36 +0000174ASTConsumer *clang::CreateCodeRewriterTest(Diagnostic &Diags) {
175 return new RewriteTest(Diags);
176}
Chris Lattnerb429ae42007-10-11 00:43:27 +0000177
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000178//===----------------------------------------------------------------------===//
179// Top Level Driver Code
180//===----------------------------------------------------------------------===//
181
Chris Lattner569faa62007-10-11 18:38:32 +0000182void RewriteTest::HandleTopLevelDecl(Decl *D) {
Chris Lattner74db1682007-10-16 21:07:07 +0000183 // Two cases: either the decl could be in the main file, or it could be in a
184 // #included file. If the former, rewrite it now. If the later, check to see
185 // if we rewrote the #include/#import.
186 SourceLocation Loc = D->getLocation();
187 Loc = SM->getLogicalLoc(Loc);
188
189 // If this is for a builtin, ignore it.
190 if (Loc.isInvalid()) return;
191
Steve Naroffe9780582007-10-23 23:50:29 +0000192 // Look for built-in declarations that we need to refer during the rewrite.
193 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Steve Naroff02a82aa2007-10-30 23:14:51 +0000194 RewriteFunctionDecl(FD);
Steve Naroff0add5d22007-11-03 11:27:19 +0000195 } else if (FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
196 // declared in <Foundation/NSString.h>
197 if (strcmp(FVD->getName(), "_NSConstantStringClassReference") == 0) {
198 ConstantStringClassReference = FVD;
199 return;
200 }
Steve Naroff3774dd92007-10-26 20:53:56 +0000201 } else if (ObjcInterfaceDecl *MD = dyn_cast<ObjcInterfaceDecl>(D)) {
202 RewriteInterfaceDecl(MD);
Steve Naroff667f1682007-10-30 13:30:57 +0000203 } else if (ObjcCategoryDecl *CD = dyn_cast<ObjcCategoryDecl>(D)) {
204 RewriteCategoryDecl(CD);
Steve Narofff4b7d6a2007-10-30 16:42:30 +0000205 } else if (ObjcProtocolDecl *PD = dyn_cast<ObjcProtocolDecl>(D)) {
206 RewriteProtocolDecl(PD);
Fariborz Jahanian016a1882007-11-14 00:42:16 +0000207 } else if (ObjcForwardProtocolDecl *FP =
208 dyn_cast<ObjcForwardProtocolDecl>(D)){
209 RewriteForwardProtocolDecl(FP);
Steve Naroffe9780582007-10-23 23:50:29 +0000210 }
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000211 // If we have a decl in the main file, see if we should rewrite it.
Chris Lattner74db1682007-10-16 21:07:07 +0000212 if (SM->getDecomposedFileLoc(Loc).first == MainFileID)
213 return HandleDeclInMainFile(D);
214
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000215 // Otherwise, see if there is a #import in the main file that should be
216 // rewritten.
Steve Naroff2aeae312007-11-09 12:50:28 +0000217 //RewriteInclude(Loc);
Chris Lattner74db1682007-10-16 21:07:07 +0000218}
219
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000220/// HandleDeclInMainFile - This is called for each top-level decl defined in the
221/// main file of the input.
222void RewriteTest::HandleDeclInMainFile(Decl *D) {
223 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
224 if (Stmt *Body = FD->getBody())
Steve Naroff334fbc22007-11-09 15:20:18 +0000225 FD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
Steve Naroff18c83382007-11-13 23:01:27 +0000226
227 if (ObjcMethodDecl *MD = dyn_cast<ObjcMethodDecl>(D)) {
Steve Naroff764c1ae2007-11-15 10:28:18 +0000228 if (Stmt *Body = MD->getBody()) {
229 //Body->dump();
230 CurMethodDecl = MD;
Steve Naroff18c83382007-11-13 23:01:27 +0000231 MD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
Steve Naroff764c1ae2007-11-15 10:28:18 +0000232 CurMethodDecl = 0;
233 }
Steve Naroff18c83382007-11-13 23:01:27 +0000234 }
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000235 if (ObjcImplementationDecl *CI = dyn_cast<ObjcImplementationDecl>(D))
236 ClassImplementation.push_back(CI);
237 else if (ObjcCategoryImplDecl *CI = dyn_cast<ObjcCategoryImplDecl>(D))
238 CategoryImplementation.push_back(CI);
239 else if (ObjcClassDecl *CD = dyn_cast<ObjcClassDecl>(D))
240 RewriteForwardClassDecl(CD);
Steve Naroff334fbc22007-11-09 15:20:18 +0000241 else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
242 if (VD->getInit())
243 RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
244 }
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000245 // Nothing yet.
246}
247
248RewriteTest::~RewriteTest() {
249 // Get the top-level buffer that this corresponds to.
Chris Lattner257236c2007-11-08 04:27:23 +0000250
251 // Rewrite tabs if we care.
252 //RewriteTabs();
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000253
Fariborz Jahanian9447e462007-11-05 17:47:33 +0000254 // Rewrite Objective-c meta data*
255 std::string ResultStr;
Fariborz Jahanian8c664912007-11-13 19:21:13 +0000256 RewriteImplementations(ResultStr);
Fariborz Jahanian9447e462007-11-05 17:47:33 +0000257
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000258 // Get the buffer corresponding to MainFileID. If we haven't changed it, then
259 // we are done.
260 if (const RewriteBuffer *RewriteBuf =
261 Rewrite.getRewriteBufferFor(MainFileID)) {
Steve Naroff0add5d22007-11-03 11:27:19 +0000262 //printf("Changed:\n");
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000263 std::string S(RewriteBuf->begin(), RewriteBuf->end());
264 printf("%s\n", S.c_str());
265 } else {
266 printf("No changes\n");
267 }
Fariborz Jahanian70ef5462007-11-07 18:40:28 +0000268 // Emit metadata.
269 printf("%s", ResultStr.c_str());
Fariborz Jahanianf185aef2007-10-26 19:46:17 +0000270}
271
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000272//===----------------------------------------------------------------------===//
273// Syntactic (non-AST) Rewriting Code
274//===----------------------------------------------------------------------===//
275
Chris Lattner74db1682007-10-16 21:07:07 +0000276void RewriteTest::RewriteInclude(SourceLocation Loc) {
277 // Rip up the #include stack to the main file.
278 SourceLocation IncLoc = Loc, NextLoc = Loc;
279 do {
280 IncLoc = Loc;
281 Loc = SM->getLogicalLoc(NextLoc);
282 NextLoc = SM->getIncludeLoc(Loc);
283 } while (!NextLoc.isInvalid());
284
285 // Loc is now the location of the #include filename "foo" or <foo/bar.h>.
286 // IncLoc indicates the header that was included if it is useful.
287 IncLoc = SM->getLogicalLoc(IncLoc);
288 if (SM->getDecomposedFileLoc(Loc).first != MainFileID ||
289 Loc == LastIncLoc)
290 return;
291 LastIncLoc = Loc;
292
293 unsigned IncCol = SM->getColumnNumber(Loc);
294 SourceLocation LineStartLoc = Loc.getFileLocWithOffset(-IncCol+1);
295
296 // Replace the #import with #include.
297 Rewrite.ReplaceText(LineStartLoc, IncCol-1, "#include ", strlen("#include "));
298}
299
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000300void RewriteTest::RewriteTabs() {
301 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
302 const char *MainBufStart = MainBuf.first;
303 const char *MainBufEnd = MainBuf.second;
Fariborz Jahanian640a01f2007-10-18 19:23:00 +0000304
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000305 // Loop over the whole file, looking for tabs.
306 for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) {
307 if (*BufPtr != '\t')
308 continue;
309
310 // Okay, we found a tab. This tab will turn into at least one character,
311 // but it depends on which 'virtual column' it is in. Compute that now.
312 unsigned VCol = 0;
313 while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' &&
314 BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r')
315 ++VCol;
316
317 // Okay, now that we know the virtual column, we know how many spaces to
318 // insert. We assume 8-character tab-stops.
319 unsigned Spaces = 8-(VCol & 7);
320
321 // Get the location of the tab.
322 SourceLocation TabLoc =
323 SourceLocation::getFileLoc(MainFileID, BufPtr-MainBufStart);
324
325 // Rewrite the single tab character into a sequence of spaces.
326 Rewrite.ReplaceText(TabLoc, 1, " ", Spaces);
327 }
Chris Lattner569faa62007-10-11 18:38:32 +0000328}
329
330
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000331void RewriteTest::RewriteForwardClassDecl(ObjcClassDecl *ClassDecl) {
332 int numDecls = ClassDecl->getNumForwardDecls();
333 ObjcInterfaceDecl **ForwardDecls = ClassDecl->getForwardDecls();
334
335 // Get the start location and compute the semi location.
336 SourceLocation startLoc = ClassDecl->getLocation();
337 const char *startBuf = SM->getCharacterData(startLoc);
338 const char *semiPtr = strchr(startBuf, ';');
339
340 // Translate to typedef's that forward reference structs with the same name
341 // as the class. As a convenience, we include the original declaration
342 // as a comment.
343 std::string typedefString;
344 typedefString += "// ";
Steve Naroff71226032007-10-24 22:48:43 +0000345 typedefString.append(startBuf, semiPtr-startBuf+1);
346 typedefString += "\n";
347 for (int i = 0; i < numDecls; i++) {
348 ObjcInterfaceDecl *ForwardDecl = ForwardDecls[i];
Steve Naroff2aeae312007-11-09 12:50:28 +0000349 typedefString += "#ifndef _REWRITER_typedef_";
350 typedefString += ForwardDecl->getName();
351 typedefString += "\n";
352 typedefString += "#define _REWRITER_typedef_";
353 typedefString += ForwardDecl->getName();
354 typedefString += "\n";
Steve Naroff4242b972007-11-05 14:36:37 +0000355 typedefString += "typedef struct objc_object ";
Steve Naroff71226032007-10-24 22:48:43 +0000356 typedefString += ForwardDecl->getName();
Steve Naroff2aeae312007-11-09 12:50:28 +0000357 typedefString += ";\n#endif\n";
Steve Naroff71226032007-10-24 22:48:43 +0000358 }
359
360 // Replace the @class with typedefs corresponding to the classes.
361 Rewrite.ReplaceText(startLoc, semiPtr-startBuf+1,
362 typedefString.c_str(), typedefString.size());
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000363}
364
Steve Naroff18c83382007-11-13 23:01:27 +0000365void RewriteTest::RewriteMethodDeclarations(int nMethods, ObjcMethodDecl **Methods) {
Steve Naroff667f1682007-10-30 13:30:57 +0000366 for (int i = 0; i < nMethods; i++) {
367 ObjcMethodDecl *Method = Methods[i];
Steve Narofffbfb46d2007-11-14 14:34:23 +0000368 SourceLocation LocStart = Method->getLocStart();
369 SourceLocation LocEnd = Method->getLocEnd();
Steve Naroff667f1682007-10-30 13:30:57 +0000370
Steve Narofffbfb46d2007-11-14 14:34:23 +0000371 if (SM->getLineNumber(LocEnd) > SM->getLineNumber(LocStart)) {
372 Rewrite.InsertText(LocStart, "/* ", 3);
373 Rewrite.ReplaceText(LocEnd, 1, ";*/ ", 4);
374 } else {
375 Rewrite.InsertText(LocStart, "// ", 3);
376 }
Steve Naroff667f1682007-10-30 13:30:57 +0000377 }
378}
379
Fariborz Jahanianeca7fad2007-11-07 00:09:37 +0000380void RewriteTest::RewriteProperties(int nProperties, ObjcPropertyDecl **Properties)
381{
382 for (int i = 0; i < nProperties; i++) {
383 ObjcPropertyDecl *Property = Properties[i];
384 SourceLocation Loc = Property->getLocation();
385
386 Rewrite.ReplaceText(Loc, 0, "// ", 3);
387
388 // FIXME: handle properties that are declared across multiple lines.
389 }
390}
391
Steve Naroff667f1682007-10-30 13:30:57 +0000392void RewriteTest::RewriteCategoryDecl(ObjcCategoryDecl *CatDecl) {
393 SourceLocation LocStart = CatDecl->getLocStart();
394
395 // FIXME: handle category headers that are declared across multiple lines.
396 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
397
Steve Naroff18c83382007-11-13 23:01:27 +0000398 RewriteMethodDeclarations(CatDecl->getNumInstanceMethods(),
399 CatDecl->getInstanceMethods());
400 RewriteMethodDeclarations(CatDecl->getNumClassMethods(),
401 CatDecl->getClassMethods());
Steve Naroff667f1682007-10-30 13:30:57 +0000402 // Lastly, comment out the @end.
403 Rewrite.ReplaceText(CatDecl->getAtEndLoc(), 0, "// ", 3);
404}
405
Steve Narofff4b7d6a2007-10-30 16:42:30 +0000406void RewriteTest::RewriteProtocolDecl(ObjcProtocolDecl *PDecl) {
Fariborz Jahanian3960e9c2007-11-14 01:37:46 +0000407 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
Fariborz Jahanian3960e9c2007-11-14 01:37:46 +0000408
Steve Narofff4b7d6a2007-10-30 16:42:30 +0000409 SourceLocation LocStart = PDecl->getLocStart();
410
411 // FIXME: handle protocol headers that are declared across multiple lines.
412 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
413
Steve Naroff18c83382007-11-13 23:01:27 +0000414 RewriteMethodDeclarations(PDecl->getNumInstanceMethods(),
415 PDecl->getInstanceMethods());
416 RewriteMethodDeclarations(PDecl->getNumClassMethods(),
417 PDecl->getClassMethods());
Steve Narofff4b7d6a2007-10-30 16:42:30 +0000418 // Lastly, comment out the @end.
Fariborz Jahanian3960e9c2007-11-14 01:37:46 +0000419 SourceLocation LocEnd = PDecl->getAtEndLoc();
420 Rewrite.ReplaceText(LocEnd, 0, "// ", 3);
Steve Naroff268fa592007-11-14 15:03:57 +0000421
Fariborz Jahanian3960e9c2007-11-14 01:37:46 +0000422 // Must comment out @optional/@required
423 const char *startBuf = SM->getCharacterData(LocStart);
424 const char *endBuf = SM->getCharacterData(LocEnd);
425 for (const char *p = startBuf; p < endBuf; p++) {
426 if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) {
427 std::string CommentedOptional = "/* @optional */";
Steve Naroff268fa592007-11-14 15:03:57 +0000428 SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
Fariborz Jahanian3960e9c2007-11-14 01:37:46 +0000429 Rewrite.ReplaceText(OptionalLoc, strlen("@optional"),
430 CommentedOptional.c_str(), CommentedOptional.size());
431
432 }
433 else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) {
434 std::string CommentedRequired = "/* @required */";
Steve Naroff268fa592007-11-14 15:03:57 +0000435 SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
Fariborz Jahanian3960e9c2007-11-14 01:37:46 +0000436 Rewrite.ReplaceText(OptionalLoc, strlen("@required"),
437 CommentedRequired.c_str(), CommentedRequired.size());
438
439 }
440 }
Steve Narofff4b7d6a2007-10-30 16:42:30 +0000441}
442
Fariborz Jahanian016a1882007-11-14 00:42:16 +0000443void RewriteTest::RewriteForwardProtocolDecl(ObjcForwardProtocolDecl *PDecl) {
444 SourceLocation LocStart = PDecl->getLocation();
Steve Naroff0540f3f2007-11-14 03:37:28 +0000445 if (LocStart.isInvalid())
446 assert(false && "Invalid SourceLocation");
Fariborz Jahanian016a1882007-11-14 00:42:16 +0000447 // FIXME: handle forward protocol that are declared across multiple lines.
448 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
449}
450
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000451void RewriteTest::RewriteObjcMethodDecl(ObjcMethodDecl *OMD,
452 std::string &ResultStr) {
453 ResultStr += "\nstatic ";
454 ResultStr += OMD->getResultType().getAsString();
Fariborz Jahanianbd2fd922007-11-13 21:02:00 +0000455 ResultStr += "\n";
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000456
457 // Unique method name
Fariborz Jahanianbd2fd922007-11-13 21:02:00 +0000458 std::string NameStr;
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000459
Fariborz Jahanianbd2fd922007-11-13 21:02:00 +0000460 if (OMD->isInstance())
461 NameStr += "_I_";
462 else
463 NameStr += "_C_";
464
465 NameStr += OMD->getClassInterface()->getName();
466 NameStr += "_";
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000467
468 NamedDecl *MethodContext = OMD->getMethodContext();
469 if (ObjcCategoryImplDecl *CID =
470 dyn_cast<ObjcCategoryImplDecl>(MethodContext)) {
Fariborz Jahanianbd2fd922007-11-13 21:02:00 +0000471 NameStr += CID->getName();
472 NameStr += "_";
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000473 }
474 // Append selector names, replacing ':' with '_'
475 const char *selName = OMD->getSelector().getName().c_str();
476 if (!strchr(selName, ':'))
Fariborz Jahanianbd2fd922007-11-13 21:02:00 +0000477 NameStr += OMD->getSelector().getName();
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000478 else {
479 std::string selString = OMD->getSelector().getName();
480 int len = selString.size();
481 for (int i = 0; i < len; i++)
482 if (selString[i] == ':')
483 selString[i] = '_';
Fariborz Jahanianbd2fd922007-11-13 21:02:00 +0000484 NameStr += selString;
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000485 }
Fariborz Jahanianbd2fd922007-11-13 21:02:00 +0000486 // Remember this name for metadata emission
487 MethodInternalNames[OMD] = NameStr;
488 ResultStr += NameStr;
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000489
490 // Rewrite arguments
491 ResultStr += "(";
492
493 // invisible arguments
494 if (OMD->isInstance()) {
495 QualType selfTy = Context->getObjcInterfaceType(OMD->getClassInterface());
496 selfTy = Context->getPointerType(selfTy);
Fariborz Jahanian0136e372007-11-13 20:04:28 +0000497 if (ObjcSynthesizedStructs.count(OMD->getClassInterface()))
498 ResultStr += "struct ";
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000499 ResultStr += selfTy.getAsString();
500 }
501 else
502 ResultStr += Context->getObjcIdType().getAsString();
503
504 ResultStr += " self, ";
505 ResultStr += Context->getObjcSelType().getAsString();
506 ResultStr += " _cmd";
507
508 // Method arguments.
509 for (int i = 0; i < OMD->getNumParams(); i++) {
510 ParmVarDecl *PDecl = OMD->getParamDecl(i);
511 ResultStr += ", ";
512 ResultStr += PDecl->getType().getAsString();
513 ResultStr += " ";
514 ResultStr += PDecl->getName();
515 }
516 ResultStr += ")";
517
518}
Fariborz Jahanian0136e372007-11-13 20:04:28 +0000519void RewriteTest::RewriteImplementationDecl(NamedDecl *OID) {
520 ObjcImplementationDecl *IMD = dyn_cast<ObjcImplementationDecl>(OID);
521 ObjcCategoryImplDecl *CID = dyn_cast<ObjcCategoryImplDecl>(OID);
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000522
Fariborz Jahanian0136e372007-11-13 20:04:28 +0000523 if (IMD)
524 Rewrite.InsertText(IMD->getLocStart(), "// ", 3);
525 else
526 Rewrite.InsertText(CID->getLocStart(), "// ", 3);
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000527
Fariborz Jahanian0136e372007-11-13 20:04:28 +0000528 int numMethods = IMD ? IMD->getNumInstanceMethods()
529 : CID->getNumInstanceMethods();
530
531 for (int i = 0; i < numMethods; i++) {
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000532 std::string ResultStr;
Fariborz Jahanian0136e372007-11-13 20:04:28 +0000533 ObjcMethodDecl *OMD;
534 if (IMD)
535 OMD = IMD->getInstanceMethods()[i];
536 else
537 OMD = CID->getInstanceMethods()[i];
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000538 RewriteObjcMethodDecl(OMD, ResultStr);
539 SourceLocation LocStart = OMD->getLocStart();
540 SourceLocation LocEnd = OMD->getBody()->getLocStart();
541
542 const char *startBuf = SM->getCharacterData(LocStart);
543 const char *endBuf = SM->getCharacterData(LocEnd);
544 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
545 ResultStr.c_str(), ResultStr.size());
546 }
547
Fariborz Jahanian0136e372007-11-13 20:04:28 +0000548 numMethods = IMD ? IMD->getNumClassMethods() : CID->getNumClassMethods();
549 for (int i = 0; i < numMethods; i++) {
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000550 std::string ResultStr;
Fariborz Jahanian0136e372007-11-13 20:04:28 +0000551 ObjcMethodDecl *OMD;
552 if (IMD)
553 OMD = IMD->getClassMethods()[i];
554 else
555 OMD = CID->getClassMethods()[i];
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000556 RewriteObjcMethodDecl(OMD, ResultStr);
557 SourceLocation LocStart = OMD->getLocStart();
558 SourceLocation LocEnd = OMD->getBody()->getLocStart();
559
560 const char *startBuf = SM->getCharacterData(LocStart);
561 const char *endBuf = SM->getCharacterData(LocEnd);
562 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
563 ResultStr.c_str(), ResultStr.size());
564 }
Fariborz Jahanian0136e372007-11-13 20:04:28 +0000565 if (IMD)
566 Rewrite.InsertText(IMD->getLocEnd(), "// ", 3);
567 else
568 Rewrite.InsertText(CID->getLocEnd(), "// ", 3);
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000569}
570
Steve Naroff3774dd92007-10-26 20:53:56 +0000571void RewriteTest::RewriteInterfaceDecl(ObjcInterfaceDecl *ClassDecl) {
Steve Naroffef20ed32007-10-30 02:23:23 +0000572 std::string ResultStr;
Steve Naroff77d081b2007-11-01 03:35:41 +0000573 if (!ObjcForwardDecls.count(ClassDecl)) {
574 // we haven't seen a forward decl - generate a typedef.
Steve Naroff2adead72007-11-14 23:02:56 +0000575 ResultStr = "#ifndef _REWRITER_typedef_";
Steve Naroff2aeae312007-11-09 12:50:28 +0000576 ResultStr += ClassDecl->getName();
577 ResultStr += "\n";
578 ResultStr += "#define _REWRITER_typedef_";
579 ResultStr += ClassDecl->getName();
580 ResultStr += "\n";
Steve Naroff4242b972007-11-05 14:36:37 +0000581 ResultStr += "typedef struct objc_object ";
Steve Naroff77d081b2007-11-01 03:35:41 +0000582 ResultStr += ClassDecl->getName();
Steve Naroff2aeae312007-11-09 12:50:28 +0000583 ResultStr += ";\n#endif\n";
Steve Naroff77d081b2007-11-01 03:35:41 +0000584
585 // Mark this typedef as having been generated.
586 ObjcForwardDecls.insert(ClassDecl);
587 }
Steve Naroffef20ed32007-10-30 02:23:23 +0000588 SynthesizeObjcInternalStruct(ClassDecl, ResultStr);
589
Fariborz Jahanianeca7fad2007-11-07 00:09:37 +0000590 RewriteProperties(ClassDecl->getNumPropertyDecl(),
591 ClassDecl->getPropertyDecl());
Steve Naroff18c83382007-11-13 23:01:27 +0000592 RewriteMethodDeclarations(ClassDecl->getNumInstanceMethods(),
593 ClassDecl->getInstanceMethods());
594 RewriteMethodDeclarations(ClassDecl->getNumClassMethods(),
595 ClassDecl->getClassMethods());
Steve Naroff3774dd92007-10-26 20:53:56 +0000596
Steve Naroff1ccf4632007-10-30 03:43:13 +0000597 // Lastly, comment out the @end.
598 Rewrite.ReplaceText(ClassDecl->getAtEndLoc(), 0, "// ", 3);
Steve Naroff3774dd92007-10-26 20:53:56 +0000599}
600
Steve Naroff6b759ce2007-11-15 02:58:25 +0000601Stmt *RewriteTest::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
602 ObjcIvarDecl *D = IV->getDecl();
603 if (IV->isFreeIvar()) {
604 Expr *Replacement = new MemberExpr(IV->getBase(), true, D,
605 IV->getLocation());
606 Rewrite.ReplaceStmt(IV, Replacement);
607 delete IV;
608 return Replacement;
Steve Naroff292b7b92007-11-15 11:33:00 +0000609 } else {
610 if (CurMethodDecl) {
611 if (const PointerType *pType = IV->getBase()->getType()->getAsPointerType()) {
612 ObjcInterfaceType *intT = dyn_cast<ObjcInterfaceType>(pType->getPointeeType());
613 if (CurMethodDecl->getClassInterface() == intT->getDecl()) {
614 IdentifierInfo *II = intT->getDecl()->getIdentifier();
615 RecordDecl *RD = new RecordDecl(Decl::Struct, SourceLocation(),
616 II, 0);
617 QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
618
619 CastExpr *castExpr = new CastExpr(castT, IV->getBase(), SourceLocation());
620 // Don't forget the parens to enforce the proper binding.
621 ParenExpr *PE = new ParenExpr(SourceLocation(), SourceLocation(), castExpr);
622 Rewrite.ReplaceStmt(IV->getBase(), PE);
623 delete IV->getBase();
624 return PE;
625 }
626 }
627 }
Steve Naroff6b759ce2007-11-15 02:58:25 +0000628 return IV;
Steve Naroff292b7b92007-11-15 11:33:00 +0000629 }
Steve Naroff6b759ce2007-11-15 02:58:25 +0000630}
631
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000632//===----------------------------------------------------------------------===//
633// Function Body / Expression rewriting
634//===----------------------------------------------------------------------===//
635
Steve Naroff334fbc22007-11-09 15:20:18 +0000636Stmt *RewriteTest::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
Chris Lattner6fe8b272007-10-16 22:36:42 +0000637 // Otherwise, just rewrite all children.
638 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
639 CI != E; ++CI)
Steve Naroffe9f69842007-11-07 04:08:17 +0000640 if (*CI) {
Steve Naroff334fbc22007-11-09 15:20:18 +0000641 Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(*CI);
Steve Naroffe9f69842007-11-07 04:08:17 +0000642 if (newStmt)
643 *CI = newStmt;
644 }
Steve Naroffe9780582007-10-23 23:50:29 +0000645
646 // Handle specific things.
647 if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
648 return RewriteAtEncode(AtEncode);
Steve Naroff6b759ce2007-11-15 02:58:25 +0000649
650 if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S))
651 return RewriteObjCIvarRefExpr(IvarRefExpr);
Steve Naroff296b74f2007-11-05 14:50:49 +0000652
653 if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S))
654 return RewriteAtSelector(AtSelector);
Steve Naroff0add5d22007-11-03 11:27:19 +0000655
656 if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S))
657 return RewriteObjCStringLiteral(AtString);
Steve Naroffe9780582007-10-23 23:50:29 +0000658
Steve Naroff71226032007-10-24 22:48:43 +0000659 if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {
660 // Before we rewrite it, put the original message expression in a comment.
661 SourceLocation startLoc = MessExpr->getLocStart();
662 SourceLocation endLoc = MessExpr->getLocEnd();
663
664 const char *startBuf = SM->getCharacterData(startLoc);
665 const char *endBuf = SM->getCharacterData(endLoc);
666
667 std::string messString;
668 messString += "// ";
669 messString.append(startBuf, endBuf-startBuf+1);
670 messString += "\n";
Steve Naroff3774dd92007-10-26 20:53:56 +0000671
Steve Naroff71226032007-10-24 22:48:43 +0000672 // FIXME: Missing definition of Rewrite.InsertText(clang::SourceLocation, char const*, unsigned int).
673 // Rewrite.InsertText(startLoc, messString.c_str(), messString.size());
674 // Tried this, but it didn't work either...
Steve Narofff4b7d6a2007-10-30 16:42:30 +0000675 // Rewrite.ReplaceText(startLoc, 0, messString.c_str(), messString.size());
Steve Naroffe9780582007-10-23 23:50:29 +0000676 return RewriteMessageExpr(MessExpr);
Steve Naroff71226032007-10-24 22:48:43 +0000677 }
Fariborz Jahanian9447e462007-11-05 17:47:33 +0000678
679 if (ObjcAtTryStmt *StmtTry = dyn_cast<ObjcAtTryStmt>(S))
680 return RewriteObjcTryStmt(StmtTry);
Steve Naroff8b1fb8c2007-11-07 15:32:26 +0000681
682 if (ObjcAtThrowStmt *StmtThrow = dyn_cast<ObjcAtThrowStmt>(S))
683 return RewriteObjcThrowStmt(StmtThrow);
Steve Naroff764c1ae2007-11-15 10:28:18 +0000684#if 0
685 if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) {
686 CastExpr *Replacement = new CastExpr(ICE->getType(), ICE->getSubExpr(), SourceLocation());
687 // Get the new text.
688 std::ostringstream Buf;
689 Replacement->printPretty(Buf);
690 const std::string &Str = Buf.str();
691
692 printf("CAST = %s\n", &Str[0]);
693 Rewrite.InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size());
694 delete S;
695 return Replacement;
696 }
697#endif
Chris Lattner0021f452007-10-24 16:57:36 +0000698 // Return this stmt unmodified.
699 return S;
Chris Lattner6fe8b272007-10-16 22:36:42 +0000700}
Fariborz Jahanian45d52f72007-10-18 22:09:03 +0000701
Fariborz Jahanian9447e462007-11-05 17:47:33 +0000702Stmt *RewriteTest::RewriteObjcTryStmt(ObjcAtTryStmt *S) {
Steve Naroffe9f69842007-11-07 04:08:17 +0000703 // Get the start location and compute the semi location.
704 SourceLocation startLoc = S->getLocStart();
705 const char *startBuf = SM->getCharacterData(startLoc);
706
707 assert((*startBuf == '@') && "bogus @try location");
708
709 std::string buf;
710 // declare a new scope with two variables, _stack and _rethrow.
711 buf = "/* @try scope begin */ { struct _objc_exception_data {\n";
712 buf += "int buf[18/*32-bit i386*/];\n";
713 buf += "char *pointers[4];} _stack;\n";
714 buf += "id volatile _rethrow = 0;\n";
715 buf += "objc_exception_try_enter(&_stack);\n";
Steve Naroffd3287d82007-11-07 18:43:40 +0000716 buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";
Steve Naroffe9f69842007-11-07 04:08:17 +0000717
718 Rewrite.ReplaceText(startLoc, 4, buf.c_str(), buf.size());
719
720 startLoc = S->getTryBody()->getLocEnd();
721 startBuf = SM->getCharacterData(startLoc);
722
723 assert((*startBuf == '}') && "bogus @try block");
724
725 SourceLocation lastCurlyLoc = startLoc;
726
727 startLoc = startLoc.getFileLocWithOffset(1);
728 buf = " /* @catch begin */ else {\n";
729 buf += " id _caught = objc_exception_extract(&_stack);\n";
730 buf += " objc_exception_try_enter (&_stack);\n";
Steve Naroffd3287d82007-11-07 18:43:40 +0000731 buf += " if (_setjmp(_stack.buf))\n";
Steve Naroffe9f69842007-11-07 04:08:17 +0000732 buf += " _rethrow = objc_exception_extract(&_stack);\n";
733 buf += " else { /* @catch continue */";
734
Chris Lattner3c82a7e2007-11-08 04:41:51 +0000735 Rewrite.InsertText(startLoc, buf.c_str(), buf.size());
Steve Naroffe9f69842007-11-07 04:08:17 +0000736
737 bool sawIdTypedCatch = false;
738 Stmt *lastCatchBody = 0;
739 ObjcAtCatchStmt *catchList = S->getCatchStmts();
740 while (catchList) {
741 Stmt *catchStmt = catchList->getCatchParamStmt();
742
743 if (catchList == S->getCatchStmts())
744 buf = "if ("; // we are generating code for the first catch clause
745 else
746 buf = "else if (";
747 startLoc = catchList->getLocStart();
748 startBuf = SM->getCharacterData(startLoc);
749
750 assert((*startBuf == '@') && "bogus @catch location");
751
752 const char *lParenLoc = strchr(startBuf, '(');
753
754 if (DeclStmt *declStmt = dyn_cast<DeclStmt>(catchStmt)) {
755 QualType t = dyn_cast<ValueDecl>(declStmt->getDecl())->getType();
756 if (t == Context->getObjcIdType()) {
757 buf += "1) { ";
758 Rewrite.ReplaceText(startLoc, lParenLoc-startBuf+1,
759 buf.c_str(), buf.size());
760 sawIdTypedCatch = true;
761 } else if (const PointerType *pType = t->getAsPointerType()) {
762 ObjcInterfaceType *cls; // Should be a pointer to a class.
763
764 cls = dyn_cast<ObjcInterfaceType>(pType->getPointeeType().getTypePtr());
765 if (cls) {
Steve Naroffd3287d82007-11-07 18:43:40 +0000766 buf += "objc_exception_match((struct objc_class *)objc_getClass(\"";
Steve Naroffe9f69842007-11-07 04:08:17 +0000767 buf += cls->getDecl()->getName();
Steve Naroffd3287d82007-11-07 18:43:40 +0000768 buf += "\"), (struct objc_object *)_caught)) { ";
Steve Naroffe9f69842007-11-07 04:08:17 +0000769 Rewrite.ReplaceText(startLoc, lParenLoc-startBuf+1,
770 buf.c_str(), buf.size());
771 }
772 }
773 // Now rewrite the body...
774 lastCatchBody = catchList->getCatchBody();
775 SourceLocation rParenLoc = catchList->getRParenLoc();
776 SourceLocation bodyLoc = lastCatchBody->getLocStart();
777 const char *bodyBuf = SM->getCharacterData(bodyLoc);
778 const char *rParenBuf = SM->getCharacterData(rParenLoc);
779 assert((*rParenBuf == ')') && "bogus @catch paren location");
780 assert((*bodyBuf == '{') && "bogus @catch body location");
781
782 buf = " = _caught;";
783 // Here we replace ") {" with "= _caught;" (which initializes and
784 // declares the @catch parameter).
785 Rewrite.ReplaceText(rParenLoc, bodyBuf-rParenBuf+1,
786 buf.c_str(), buf.size());
Steve Naroff8b1fb8c2007-11-07 15:32:26 +0000787 } else if (!isa<NullStmt>(catchStmt)) {
Steve Naroffe9f69842007-11-07 04:08:17 +0000788 assert(false && "@catch rewrite bug");
Steve Naroff8b1fb8c2007-11-07 15:32:26 +0000789 }
Steve Naroffe9f69842007-11-07 04:08:17 +0000790 catchList = catchList->getNextCatchStmt();
791 }
792 // Complete the catch list...
793 if (lastCatchBody) {
794 SourceLocation bodyLoc = lastCatchBody->getLocEnd();
795 const char *bodyBuf = SM->getCharacterData(bodyLoc);
796 assert((*bodyBuf == '}') && "bogus @catch body location");
797 bodyLoc = bodyLoc.getFileLocWithOffset(1);
798 buf = " } } /* @catch end */\n";
799
Chris Lattner3c82a7e2007-11-08 04:41:51 +0000800 Rewrite.InsertText(bodyLoc, buf.c_str(), buf.size());
Steve Naroffe9f69842007-11-07 04:08:17 +0000801
802 // Set lastCurlyLoc
803 lastCurlyLoc = lastCatchBody->getLocEnd();
804 }
805 if (ObjcAtFinallyStmt *finalStmt = S->getFinallyStmt()) {
806 startLoc = finalStmt->getLocStart();
807 startBuf = SM->getCharacterData(startLoc);
808 assert((*startBuf == '@') && "bogus @finally start");
809
810 buf = "/* @finally */";
811 Rewrite.ReplaceText(startLoc, 8, buf.c_str(), buf.size());
812
813 Stmt *body = finalStmt->getFinallyBody();
814 SourceLocation startLoc = body->getLocStart();
815 SourceLocation endLoc = body->getLocEnd();
816 const char *startBuf = SM->getCharacterData(startLoc);
817 const char *endBuf = SM->getCharacterData(endLoc);
818 assert((*startBuf == '{') && "bogus @finally body location");
819 assert((*endBuf == '}') && "bogus @finally body location");
820
821 startLoc = startLoc.getFileLocWithOffset(1);
822 buf = " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
Chris Lattner3c82a7e2007-11-08 04:41:51 +0000823 Rewrite.InsertText(startLoc, buf.c_str(), buf.size());
Steve Naroffe9f69842007-11-07 04:08:17 +0000824 endLoc = endLoc.getFileLocWithOffset(-1);
825 buf = " if (_rethrow) objc_exception_throw(_rethrow);\n";
Chris Lattner3c82a7e2007-11-08 04:41:51 +0000826 Rewrite.InsertText(endLoc, buf.c_str(), buf.size());
Steve Naroffe9f69842007-11-07 04:08:17 +0000827
828 // Set lastCurlyLoc
829 lastCurlyLoc = body->getLocEnd();
830 }
831 // Now emit the final closing curly brace...
832 lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1);
833 buf = " } /* @try scope end */\n";
Chris Lattner3c82a7e2007-11-08 04:41:51 +0000834 Rewrite.InsertText(lastCurlyLoc, buf.c_str(), buf.size());
Fariborz Jahanian9447e462007-11-05 17:47:33 +0000835 return 0;
836}
837
838Stmt *RewriteTest::RewriteObjcCatchStmt(ObjcAtCatchStmt *S) {
839 return 0;
840}
841
842Stmt *RewriteTest::RewriteObjcFinallyStmt(ObjcAtFinallyStmt *S) {
843 return 0;
844}
845
Steve Naroff8b1fb8c2007-11-07 15:32:26 +0000846// This can't be done with Rewrite.ReplaceStmt(S, ThrowExpr), since
847// the throw expression is typically a message expression that's already
848// been rewritten! (which implies the SourceLocation's are invalid).
849Stmt *RewriteTest::RewriteObjcThrowStmt(ObjcAtThrowStmt *S) {
850 // Get the start location and compute the semi location.
851 SourceLocation startLoc = S->getLocStart();
852 const char *startBuf = SM->getCharacterData(startLoc);
853
854 assert((*startBuf == '@') && "bogus @throw location");
855
856 std::string buf;
857 /* void objc_exception_throw(id) __attribute__((noreturn)); */
858 buf = "objc_exception_throw(";
859 Rewrite.ReplaceText(startLoc, 6, buf.c_str(), buf.size());
860 const char *semiBuf = strchr(startBuf, ';');
861 assert((*semiBuf == ';') && "@throw: can't find ';'");
862 SourceLocation semiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf);
863 buf = ");";
864 Rewrite.ReplaceText(semiLoc, 1, buf.c_str(), buf.size());
865 return 0;
866}
Fariborz Jahanian9447e462007-11-05 17:47:33 +0000867
Chris Lattner0021f452007-10-24 16:57:36 +0000868Stmt *RewriteTest::RewriteAtEncode(ObjCEncodeExpr *Exp) {
Chris Lattnerbf0bfa62007-10-17 22:35:30 +0000869 // Create a new string expression.
870 QualType StrType = Context->getPointerType(Context->CharTy);
Anders Carlsson36f07d82007-10-29 05:01:08 +0000871 std::string StrEncoding;
872 Context->getObjcEncodingForType(Exp->getEncodedType(), StrEncoding);
873 Expr *Replacement = new StringLiteral(StrEncoding.c_str(),
874 StrEncoding.length(), false, StrType,
Chris Lattnerbf0bfa62007-10-17 22:35:30 +0000875 SourceLocation(), SourceLocation());
Chris Lattner258f26c2007-11-30 22:25:36 +0000876 if (Rewrite.ReplaceStmt(Exp, Replacement)) {
877 // replacement failed.
Chris Lattner217df512007-12-02 01:09:57 +0000878 unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
879 "rewriter could not replace sub-expression due to macros");
880 SourceRange Range = Exp->getSourceRange();
881 Diags.Report(Exp->getAtLoc(), DiagID, 0, 0, &Range, 1);
882 delete Replacement;
Chris Lattner258f26c2007-11-30 22:25:36 +0000883 return Exp;
884 }
885
Chris Lattner4478db92007-11-30 22:53:43 +0000886 // Replace this subexpr in the parent.
Chris Lattner0021f452007-10-24 16:57:36 +0000887 delete Exp;
888 return Replacement;
Chris Lattner6fe8b272007-10-16 22:36:42 +0000889}
890
Steve Naroff296b74f2007-11-05 14:50:49 +0000891Stmt *RewriteTest::RewriteAtSelector(ObjCSelectorExpr *Exp) {
892 assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");
893 // Create a call to sel_registerName("selName").
894 llvm::SmallVector<Expr*, 8> SelExprs;
895 QualType argType = Context->getPointerType(Context->CharTy);
896 SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
897 Exp->getSelector().getName().size(),
898 false, argType, SourceLocation(),
899 SourceLocation()));
900 CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
901 &SelExprs[0], SelExprs.size());
902 Rewrite.ReplaceStmt(Exp, SelExp);
903 delete Exp;
904 return SelExp;
905}
906
Steve Naroff71226032007-10-24 22:48:43 +0000907CallExpr *RewriteTest::SynthesizeCallToFunctionDecl(
908 FunctionDecl *FD, Expr **args, unsigned nargs) {
Steve Naroffe9780582007-10-23 23:50:29 +0000909 // Get the type, we will need to reference it in a couple spots.
Steve Naroff71226032007-10-24 22:48:43 +0000910 QualType msgSendType = FD->getType();
Steve Naroffe9780582007-10-23 23:50:29 +0000911
912 // Create a reference to the objc_msgSend() declaration.
Steve Naroff71226032007-10-24 22:48:43 +0000913 DeclRefExpr *DRE = new DeclRefExpr(FD, msgSendType, SourceLocation());
Steve Naroffe9780582007-10-23 23:50:29 +0000914
915 // Now, we cast the reference to a pointer to the objc_msgSend type.
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000916 QualType pToFunc = Context->getPointerType(msgSendType);
Steve Naroffe9780582007-10-23 23:50:29 +0000917 ImplicitCastExpr *ICE = new ImplicitCastExpr(pToFunc, DRE);
918
919 const FunctionType *FT = msgSendType->getAsFunctionType();
Chris Lattner0021f452007-10-24 16:57:36 +0000920
Steve Naroff71226032007-10-24 22:48:43 +0000921 return new CallExpr(ICE, args, nargs, FT->getResultType(), SourceLocation());
922}
923
Steve Naroffc8a92d12007-11-01 13:24:47 +0000924static bool scanForProtocolRefs(const char *startBuf, const char *endBuf,
925 const char *&startRef, const char *&endRef) {
926 while (startBuf < endBuf) {
927 if (*startBuf == '<')
928 startRef = startBuf; // mark the start.
929 if (*startBuf == '>') {
Steve Naroff2aeae312007-11-09 12:50:28 +0000930 if (startRef && *startRef == '<') {
931 endRef = startBuf; // mark the end.
932 return true;
933 }
934 return false;
Steve Naroffc8a92d12007-11-01 13:24:47 +0000935 }
936 startBuf++;
937 }
938 return false;
939}
940
941bool RewriteTest::needToScanForQualifiers(QualType T) {
942 // FIXME: we don't currently represent "id <Protocol>" in the type system.
943 if (T == Context->getObjcIdType())
944 return true;
945
946 if (const PointerType *pType = T->getAsPointerType()) {
Steve Naroff05d6ff52007-10-31 04:38:33 +0000947 Type *pointeeType = pType->getPointeeType().getTypePtr();
948 if (isa<ObjcQualifiedInterfaceType>(pointeeType))
949 return true; // we have "Class <Protocol> *".
950 }
Steve Naroffc8a92d12007-11-01 13:24:47 +0000951 return false;
952}
953
954void RewriteTest::RewriteObjcQualifiedInterfaceTypes(
955 const FunctionTypeProto *proto, FunctionDecl *FD) {
956
957 if (needToScanForQualifiers(proto->getResultType())) {
958 // Since types are unique, we need to scan the buffer.
959 SourceLocation Loc = FD->getLocation();
960
961 const char *endBuf = SM->getCharacterData(Loc);
962 const char *startBuf = endBuf;
Chris Lattnerae43eb72007-12-02 01:13:47 +0000963 while (*startBuf != ';' && startBuf != MainFileStart)
Steve Naroffc8a92d12007-11-01 13:24:47 +0000964 startBuf--; // scan backward (from the decl location) for return type.
965 const char *startRef = 0, *endRef = 0;
966 if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
967 // Get the locations of the startRef, endRef.
968 SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-endBuf);
969 SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-endBuf+1);
970 // Comment out the protocol references.
Chris Lattner3c82a7e2007-11-08 04:41:51 +0000971 Rewrite.InsertText(LessLoc, "/*", 2);
972 Rewrite.InsertText(GreaterLoc, "*/", 2);
Steve Naroff05d6ff52007-10-31 04:38:33 +0000973 }
974 }
Steve Naroffc8a92d12007-11-01 13:24:47 +0000975 // Now check arguments.
976 for (unsigned i = 0; i < proto->getNumArgs(); i++) {
977 if (needToScanForQualifiers(proto->getArgType(i))) {
978 // Since types are unique, we need to scan the buffer.
979 SourceLocation Loc = FD->getLocation();
980
981 const char *startBuf = SM->getCharacterData(Loc);
982 const char *endBuf = startBuf;
983 while (*endBuf != ';')
984 endBuf++; // scan forward (from the decl location) for argument types.
985 const char *startRef = 0, *endRef = 0;
986 if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
987 // Get the locations of the startRef, endRef.
988 SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-startBuf);
989 SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-startBuf+1);
990 // Comment out the protocol references.
Chris Lattner3c82a7e2007-11-08 04:41:51 +0000991 Rewrite.InsertText(LessLoc, "/*", 2);
992 Rewrite.InsertText(GreaterLoc, "*/", 2);
Steve Naroffc8a92d12007-11-01 13:24:47 +0000993 }
994 }
995 }
Steve Naroff05d6ff52007-10-31 04:38:33 +0000996}
997
Steve Naroff02a82aa2007-10-30 23:14:51 +0000998void RewriteTest::RewriteFunctionDecl(FunctionDecl *FD) {
999 // declared in <objc/objc.h>
Steve Naroff0add5d22007-11-03 11:27:19 +00001000 if (strcmp(FD->getName(), "sel_registerName") == 0) {
Steve Naroff02a82aa2007-10-30 23:14:51 +00001001 SelGetUidFunctionDecl = FD;
Steve Naroff05d6ff52007-10-31 04:38:33 +00001002 return;
1003 }
1004 // Check for ObjC 'id' and class types that have been adorned with protocol
1005 // information (id<p>, C<p>*). The protocol references need to be rewritten!
1006 const FunctionType *funcType = FD->getType()->getAsFunctionType();
1007 assert(funcType && "missing function type");
Steve Naroffc8a92d12007-11-01 13:24:47 +00001008 if (const FunctionTypeProto *proto = dyn_cast<FunctionTypeProto>(funcType))
1009 RewriteObjcQualifiedInterfaceTypes(proto, FD);
Steve Naroff02a82aa2007-10-30 23:14:51 +00001010}
1011
1012// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
1013void RewriteTest::SynthMsgSendFunctionDecl() {
1014 IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend");
1015 llvm::SmallVector<QualType, 16> ArgTys;
1016 QualType argT = Context->getObjcIdType();
1017 assert(!argT.isNull() && "Can't find 'id' type");
1018 ArgTys.push_back(argT);
1019 argT = Context->getObjcSelType();
1020 assert(!argT.isNull() && "Can't find 'SEL' type");
1021 ArgTys.push_back(argT);
1022 QualType msgSendType = Context->getFunctionType(Context->getObjcIdType(),
1023 &ArgTys[0], ArgTys.size(),
1024 true /*isVariadic*/);
1025 MsgSendFunctionDecl = new FunctionDecl(SourceLocation(),
1026 msgSendIdent, msgSendType,
1027 FunctionDecl::Extern, false, 0);
1028}
1029
Steve Naroff764c1ae2007-11-15 10:28:18 +00001030// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...);
1031void RewriteTest::SynthMsgSendSuperFunctionDecl() {
1032 IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper");
1033 llvm::SmallVector<QualType, 16> ArgTys;
1034 RecordDecl *RD = new RecordDecl(Decl::Struct, SourceLocation(),
1035 &Context->Idents.get("objc_super"), 0);
1036 QualType argT = Context->getPointerType(Context->getTagDeclType(RD));
1037 assert(!argT.isNull() && "Can't build 'struct objc_super *' type");
1038 ArgTys.push_back(argT);
1039 argT = Context->getObjcSelType();
1040 assert(!argT.isNull() && "Can't find 'SEL' type");
1041 ArgTys.push_back(argT);
1042 QualType msgSendType = Context->getFunctionType(Context->getObjcIdType(),
1043 &ArgTys[0], ArgTys.size(),
1044 true /*isVariadic*/);
1045 MsgSendSuperFunctionDecl = new FunctionDecl(SourceLocation(),
1046 msgSendIdent, msgSendType,
1047 FunctionDecl::Extern, false, 0);
1048}
1049
Steve Naroff02a82aa2007-10-30 23:14:51 +00001050// SynthGetClassFunctionDecl - id objc_getClass(const char *name);
1051void RewriteTest::SynthGetClassFunctionDecl() {
1052 IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass");
1053 llvm::SmallVector<QualType, 16> ArgTys;
1054 ArgTys.push_back(Context->getPointerType(
1055 Context->CharTy.getQualifiedType(QualType::Const)));
1056 QualType getClassType = Context->getFunctionType(Context->getObjcIdType(),
1057 &ArgTys[0], ArgTys.size(),
1058 false /*isVariadic*/);
1059 GetClassFunctionDecl = new FunctionDecl(SourceLocation(),
1060 getClassIdent, getClassType,
1061 FunctionDecl::Extern, false, 0);
1062}
1063
Steve Naroffabb96362007-11-08 14:30:50 +00001064// SynthCFStringFunctionDecl - id __builtin___CFStringMakeConstantString(const char *name);
1065void RewriteTest::SynthCFStringFunctionDecl() {
1066 IdentifierInfo *getClassIdent = &Context->Idents.get("__builtin___CFStringMakeConstantString");
1067 llvm::SmallVector<QualType, 16> ArgTys;
1068 ArgTys.push_back(Context->getPointerType(
1069 Context->CharTy.getQualifiedType(QualType::Const)));
1070 QualType getClassType = Context->getFunctionType(Context->getObjcIdType(),
1071 &ArgTys[0], ArgTys.size(),
1072 false /*isVariadic*/);
1073 CFStringFunctionDecl = new FunctionDecl(SourceLocation(),
1074 getClassIdent, getClassType,
1075 FunctionDecl::Extern, false, 0);
1076}
1077
Steve Naroff0add5d22007-11-03 11:27:19 +00001078Stmt *RewriteTest::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
Steve Naroffabb96362007-11-08 14:30:50 +00001079#if 1
1080 // This rewrite is specific to GCC, which has builtin support for CFString.
1081 if (!CFStringFunctionDecl)
1082 SynthCFStringFunctionDecl();
1083 // Create a call to __builtin___CFStringMakeConstantString("cstr").
1084 llvm::SmallVector<Expr*, 8> StrExpr;
1085 StrExpr.push_back(Exp->getString());
1086 CallExpr *call = SynthesizeCallToFunctionDecl(CFStringFunctionDecl,
1087 &StrExpr[0], StrExpr.size());
1088 // cast to NSConstantString *
1089 CastExpr *cast = new CastExpr(Exp->getType(), call, SourceLocation());
1090 Rewrite.ReplaceStmt(Exp, cast);
1091 delete Exp;
1092 return cast;
1093#else
Steve Naroff0add5d22007-11-03 11:27:19 +00001094 assert(ConstantStringClassReference && "Can't find constant string reference");
1095 llvm::SmallVector<Expr*, 4> InitExprs;
1096
1097 // Synthesize "(Class)&_NSConstantStringClassReference"
1098 DeclRefExpr *ClsRef = new DeclRefExpr(ConstantStringClassReference,
1099 ConstantStringClassReference->getType(),
1100 SourceLocation());
1101 QualType expType = Context->getPointerType(ClsRef->getType());
1102 UnaryOperator *Unop = new UnaryOperator(ClsRef, UnaryOperator::AddrOf,
1103 expType, SourceLocation());
1104 CastExpr *cast = new CastExpr(Context->getObjcClassType(), Unop,
1105 SourceLocation());
1106 InitExprs.push_back(cast); // set the 'isa'.
1107 InitExprs.push_back(Exp->getString()); // set "char *bytes".
1108 unsigned IntSize = static_cast<unsigned>(
1109 Context->getTypeSize(Context->IntTy, Exp->getLocStart()));
1110 llvm::APInt IntVal(IntSize, Exp->getString()->getByteLength());
1111 IntegerLiteral *len = new IntegerLiteral(IntVal, Context->IntTy,
1112 Exp->getLocStart());
1113 InitExprs.push_back(len); // set "int numBytes".
1114
1115 // struct NSConstantString
1116 QualType CFConstantStrType = Context->getCFConstantStringType();
1117 // (struct NSConstantString) { <exprs from above> }
1118 InitListExpr *ILE = new InitListExpr(SourceLocation(),
1119 &InitExprs[0], InitExprs.size(),
1120 SourceLocation());
1121 CompoundLiteralExpr *StrRep = new CompoundLiteralExpr(CFConstantStrType, ILE);
1122 // struct NSConstantString *
1123 expType = Context->getPointerType(StrRep->getType());
1124 Unop = new UnaryOperator(StrRep, UnaryOperator::AddrOf, expType,
1125 SourceLocation());
Steve Naroff4242b972007-11-05 14:36:37 +00001126 // cast to NSConstantString *
1127 cast = new CastExpr(Exp->getType(), Unop, SourceLocation());
Steve Naroff0add5d22007-11-03 11:27:19 +00001128 Rewrite.ReplaceStmt(Exp, cast);
1129 delete Exp;
Steve Naroff4242b972007-11-05 14:36:37 +00001130 return cast;
Steve Naroffabb96362007-11-08 14:30:50 +00001131#endif
Steve Naroff0add5d22007-11-03 11:27:19 +00001132}
1133
Steve Naroff764c1ae2007-11-15 10:28:18 +00001134ObjcInterfaceDecl *RewriteTest::isSuperReceiver(Expr *recExpr) {
1135 if (CurMethodDecl) { // check if we are sending a message to 'super'
1136 if (CastExpr *CE = dyn_cast<CastExpr>(recExpr)) {
1137 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) {
1138 if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
1139 if (!strcmp(PVD->getName(), "self")) {
1140 if (const PointerType *PT = CE->getType()->getAsPointerType()) {
1141 if (ObjcInterfaceType *IT =
1142 dyn_cast<ObjcInterfaceType>(PT->getPointeeType())) {
1143 if (IT->getDecl() ==
1144 CurMethodDecl->getClassInterface()->getSuperClass())
1145 return IT->getDecl();
1146 }
1147 }
1148 }
1149 }
1150 }
1151 }
1152 }
1153 return 0;
1154}
1155
1156// struct objc_super { struct objc_object *receiver; struct objc_class *super; };
1157QualType RewriteTest::getSuperStructType() {
1158 if (!SuperStructDecl) {
1159 SuperStructDecl = new RecordDecl(Decl::Struct, SourceLocation(),
1160 &Context->Idents.get("objc_super"), 0);
1161 QualType FieldTypes[2];
1162
1163 // struct objc_object *receiver;
1164 FieldTypes[0] = Context->getObjcIdType();
1165 // struct objc_class *super;
1166 FieldTypes[1] = Context->getObjcClassType();
1167 // Create fields
1168 FieldDecl *FieldDecls[2];
1169
1170 for (unsigned i = 0; i < 2; ++i)
1171 FieldDecls[i] = new FieldDecl(SourceLocation(), 0, FieldTypes[i]);
1172
1173 SuperStructDecl->defineBody(FieldDecls, 4);
1174 }
1175 return Context->getTagDeclType(SuperStructDecl);
1176}
1177
Steve Naroff71226032007-10-24 22:48:43 +00001178Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) {
Steve Naroff0add5d22007-11-03 11:27:19 +00001179 assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");
Steve Naroff02a82aa2007-10-30 23:14:51 +00001180 if (!MsgSendFunctionDecl)
1181 SynthMsgSendFunctionDecl();
Steve Naroff764c1ae2007-11-15 10:28:18 +00001182 if (!MsgSendSuperFunctionDecl)
1183 SynthMsgSendSuperFunctionDecl();
Steve Naroff02a82aa2007-10-30 23:14:51 +00001184 if (!GetClassFunctionDecl)
1185 SynthGetClassFunctionDecl();
Steve Naroff71226032007-10-24 22:48:43 +00001186
Steve Naroff764c1ae2007-11-15 10:28:18 +00001187 // default to objc_msgSend().
1188 FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl;
1189
Steve Naroff71226032007-10-24 22:48:43 +00001190 // Synthesize a call to objc_msgSend().
1191 llvm::SmallVector<Expr*, 8> MsgExprs;
1192 IdentifierInfo *clsName = Exp->getClassName();
1193
1194 // Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend().
1195 if (clsName) { // class message.
1196 llvm::SmallVector<Expr*, 8> ClsExprs;
1197 QualType argType = Context->getPointerType(Context->CharTy);
1198 ClsExprs.push_back(new StringLiteral(clsName->getName(),
1199 clsName->getLength(),
1200 false, argType, SourceLocation(),
1201 SourceLocation()));
1202 CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
1203 &ClsExprs[0], ClsExprs.size());
1204 MsgExprs.push_back(Cls);
Steve Naroff885e2122007-11-14 23:54:14 +00001205 } else { // instance message.
1206 Expr *recExpr = Exp->getReceiver();
Steve Naroff764c1ae2007-11-15 10:28:18 +00001207
1208 if (ObjcInterfaceDecl *ID = isSuperReceiver(recExpr)) {
1209 MsgSendFlavor = MsgSendSuperFunctionDecl;
1210 assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
1211
1212 llvm::SmallVector<Expr*, 4> InitExprs;
1213
1214 InitExprs.push_back(recExpr); // set the 'receiver'.
1215
1216 llvm::SmallVector<Expr*, 8> ClsExprs;
1217 QualType argType = Context->getPointerType(Context->CharTy);
1218 ClsExprs.push_back(new StringLiteral(ID->getIdentifier()->getName(),
1219 ID->getIdentifier()->getLength(),
1220 false, argType, SourceLocation(),
1221 SourceLocation()));
1222 CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
1223 &ClsExprs[0], ClsExprs.size());
1224 InitExprs.push_back(Cls); // set 'super class', using objc_getClass().
1225 // struct objc_super
1226 QualType superType = getSuperStructType();
1227 // (struct objc_super) { <exprs from above> }
1228 InitListExpr *ILE = new InitListExpr(SourceLocation(),
1229 &InitExprs[0], InitExprs.size(),
1230 SourceLocation());
1231 CompoundLiteralExpr *SuperRep = new CompoundLiteralExpr(superType, ILE);
1232 // struct objc_super *
1233 Expr *Unop = new UnaryOperator(SuperRep, UnaryOperator::AddrOf,
1234 Context->getPointerType(SuperRep->getType()),
1235 SourceLocation());
1236 MsgExprs.push_back(Unop);
1237 } else {
1238 recExpr = new CastExpr(Context->getObjcIdType(), recExpr, SourceLocation());
1239 MsgExprs.push_back(recExpr);
1240 }
Steve Naroff885e2122007-11-14 23:54:14 +00001241 }
Steve Naroff0add5d22007-11-03 11:27:19 +00001242 // Create a call to sel_registerName("selName"), it will be the 2nd argument.
Steve Naroff71226032007-10-24 22:48:43 +00001243 llvm::SmallVector<Expr*, 8> SelExprs;
1244 QualType argType = Context->getPointerType(Context->CharTy);
1245 SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
1246 Exp->getSelector().getName().size(),
1247 false, argType, SourceLocation(),
1248 SourceLocation()));
1249 CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
1250 &SelExprs[0], SelExprs.size());
1251 MsgExprs.push_back(SelExp);
1252
1253 // Now push any user supplied arguments.
1254 for (unsigned i = 0; i < Exp->getNumArgs(); i++) {
Steve Naroff885e2122007-11-14 23:54:14 +00001255 Expr *userExpr = Exp->getArg(i);
Steve Naroff6b759ce2007-11-15 02:58:25 +00001256 // Make all implicit casts explicit...ICE comes in handy:-)
1257 if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) {
1258 // Reuse the ICE type, it is exactly what the doctor ordered.
1259 userExpr = new CastExpr(ICE->getType(), userExpr, SourceLocation());
1260 }
Steve Naroff885e2122007-11-14 23:54:14 +00001261 MsgExprs.push_back(userExpr);
Steve Naroff71226032007-10-24 22:48:43 +00001262 // We've transferred the ownership to MsgExprs. Null out the argument in
1263 // the original expression, since we will delete it below.
1264 Exp->setArg(i, 0);
1265 }
Steve Naroff0744c472007-11-04 22:37:50 +00001266 // Generate the funky cast.
1267 CastExpr *cast;
1268 llvm::SmallVector<QualType, 8> ArgTypes;
1269 QualType returnType;
1270
1271 // Push 'id' and 'SEL', the 2 implicit arguments.
Steve Naroff0c04bb62007-11-15 10:43:57 +00001272 if (MsgSendFlavor == MsgSendSuperFunctionDecl)
1273 ArgTypes.push_back(Context->getPointerType(getSuperStructType()));
1274 else
1275 ArgTypes.push_back(Context->getObjcIdType());
Steve Naroff0744c472007-11-04 22:37:50 +00001276 ArgTypes.push_back(Context->getObjcSelType());
1277 if (ObjcMethodDecl *mDecl = Exp->getMethodDecl()) {
1278 // Push any user argument types.
Steve Naroff4242b972007-11-05 14:36:37 +00001279 for (int i = 0; i < mDecl->getNumParams(); i++) {
1280 QualType t = mDecl->getParamDecl(i)->getType();
Steve Naroff4242b972007-11-05 14:36:37 +00001281 ArgTypes.push_back(t);
1282 }
Steve Naroff0744c472007-11-04 22:37:50 +00001283 returnType = mDecl->getResultType();
1284 } else {
1285 returnType = Context->getObjcIdType();
1286 }
1287 // Get the type, we will need to reference it in a couple spots.
Steve Naroff764c1ae2007-11-15 10:28:18 +00001288 QualType msgSendType = MsgSendFlavor->getType();
Steve Naroff0744c472007-11-04 22:37:50 +00001289
1290 // Create a reference to the objc_msgSend() declaration.
Steve Naroff764c1ae2007-11-15 10:28:18 +00001291 DeclRefExpr *DRE = new DeclRefExpr(MsgSendFlavor, msgSendType, SourceLocation());
Steve Naroff0744c472007-11-04 22:37:50 +00001292
1293 // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid).
1294 // If we don't do this cast, we get the following bizarre warning/note:
1295 // xx.m:13: warning: function called through a non-compatible type
1296 // xx.m:13: note: if this code is reached, the program will abort
1297 cast = new CastExpr(Context->getPointerType(Context->VoidTy), DRE,
1298 SourceLocation());
Steve Naroff29fe7462007-11-15 12:35:21 +00001299
Steve Naroff0744c472007-11-04 22:37:50 +00001300 // Now do the "normal" pointer to function cast.
1301 QualType castType = Context->getFunctionType(returnType,
1302 &ArgTypes[0], ArgTypes.size(),
Steve Naroff29fe7462007-11-15 12:35:21 +00001303 Exp->getMethodDecl()->isVariadic());
Steve Naroff0744c472007-11-04 22:37:50 +00001304 castType = Context->getPointerType(castType);
1305 cast = new CastExpr(castType, cast, SourceLocation());
1306
1307 // Don't forget the parens to enforce the proper binding.
1308 ParenExpr *PE = new ParenExpr(SourceLocation(), SourceLocation(), cast);
1309
1310 const FunctionType *FT = msgSendType->getAsFunctionType();
1311 CallExpr *CE = new CallExpr(PE, &MsgExprs[0], MsgExprs.size(),
1312 FT->getResultType(), SourceLocation());
Steve Naroff71226032007-10-24 22:48:43 +00001313 // Now do the actual rewrite.
Steve Naroff0744c472007-11-04 22:37:50 +00001314 Rewrite.ReplaceStmt(Exp, CE);
Steve Naroff71226032007-10-24 22:48:43 +00001315
Chris Lattner0021f452007-10-24 16:57:36 +00001316 delete Exp;
Steve Naroff0744c472007-11-04 22:37:50 +00001317 return CE;
Steve Naroffe9780582007-10-23 23:50:29 +00001318}
1319
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00001320/// SynthesizeObjcInternalStruct - Rewrite one internal struct corresponding to
1321/// an objective-c class with ivars.
1322void RewriteTest::SynthesizeObjcInternalStruct(ObjcInterfaceDecl *CDecl,
1323 std::string &Result) {
1324 assert(CDecl && "Class missing in SynthesizeObjcInternalStruct");
1325 assert(CDecl->getName() && "Name missing in SynthesizeObjcInternalStruct");
Fariborz Jahanianfb4f6a32007-10-31 23:08:24 +00001326 // Do not synthesize more than once.
1327 if (ObjcSynthesizedStructs.count(CDecl))
1328 return;
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00001329 ObjcInterfaceDecl *RCDecl = CDecl->getSuperClass();
1330 if (RCDecl && !ObjcSynthesizedStructs.count(RCDecl)) {
1331 // Do it for the root
1332 SynthesizeObjcInternalStruct(RCDecl, Result);
1333 }
1334
Steve Naroffdd2e26c2007-11-12 13:56:41 +00001335 int NumIvars = CDecl->getNumInstanceVariables();
Steve Naroff2c7afc92007-11-14 19:25:57 +00001336 SourceLocation LocStart = CDecl->getLocStart();
1337 SourceLocation LocEnd = CDecl->getLocEnd();
1338
1339 const char *startBuf = SM->getCharacterData(LocStart);
1340 const char *endBuf = SM->getCharacterData(LocEnd);
Fariborz Jahanian920cde32007-11-26 19:52:57 +00001341 // If no ivars and no root or if its root, directly or indirectly,
1342 // have no ivars (thus not synthesized) then no need to synthesize this class.
1343 if (NumIvars <= 0 && (!RCDecl || !ObjcSynthesizedStructs.count(RCDecl))) {
Fariborz Jahanian920cde32007-11-26 19:52:57 +00001344 endBuf += Lexer::MeasureTokenLength(LocEnd, *SM);
1345 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
1346 Result.c_str(), Result.size());
1347 return;
1348 }
1349
1350 // FIXME: This has potential of causing problem. If
1351 // SynthesizeObjcInternalStruct is ever called recursively.
1352 Result += "\nstruct ";
1353 Result += CDecl->getName();
Steve Naroff2c7afc92007-11-14 19:25:57 +00001354
Fariborz Jahanian6acfa2b2007-10-31 17:29:28 +00001355 if (NumIvars > 0) {
Steve Naroff2c7afc92007-11-14 19:25:57 +00001356 const char *cursor = strchr(startBuf, '{');
1357 assert((cursor && endBuf)
Fariborz Jahanian6acfa2b2007-10-31 17:29:28 +00001358 && "SynthesizeObjcInternalStruct - malformed @interface");
Steve Naroff2c7afc92007-11-14 19:25:57 +00001359
1360 // rewrite the original header *without* disturbing the '{'
1361 Rewrite.ReplaceText(LocStart, cursor-startBuf-1,
1362 Result.c_str(), Result.size());
1363 if (RCDecl && ObjcSynthesizedStructs.count(RCDecl)) {
1364 Result = "\n struct ";
1365 Result += RCDecl->getName();
1366 Result += " _";
1367 Result += RCDecl->getName();
1368 Result += ";\n";
1369
1370 // insert the super class structure definition.
1371 SourceLocation OnePastCurly = LocStart.getFileLocWithOffset(cursor-startBuf+1);
1372 Rewrite.InsertText(OnePastCurly, Result.c_str(), Result.size());
1373 }
1374 cursor++; // past '{'
1375
1376 // Now comment out any visibility specifiers.
1377 while (cursor < endBuf) {
1378 if (*cursor == '@') {
1379 SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
Chris Lattnerf04ead52007-11-14 22:57:51 +00001380 // Skip whitespace.
1381 for (++cursor; cursor[0] == ' ' || cursor[0] == '\t'; ++cursor)
1382 /*scan*/;
1383
Fariborz Jahanian6acfa2b2007-10-31 17:29:28 +00001384 // FIXME: presence of @public, etc. inside comment results in
1385 // this transformation as well, which is still correct c-code.
Steve Naroff2c7afc92007-11-14 19:25:57 +00001386 if (!strncmp(cursor, "public", strlen("public")) ||
1387 !strncmp(cursor, "private", strlen("private")) ||
Fariborz Jahanian8d9c7352007-11-14 22:26:25 +00001388 !strncmp(cursor, "protected", strlen("protected")))
Steve Naroff2c7afc92007-11-14 19:25:57 +00001389 Rewrite.InsertText(atLoc, "// ", 3);
Fariborz Jahanian6acfa2b2007-10-31 17:29:28 +00001390 }
Fariborz Jahanian8d9c7352007-11-14 22:26:25 +00001391 // FIXME: If there are cases where '<' is used in ivar declaration part
1392 // of user code, then scan the ivar list and use needToScanForQualifiers
1393 // for type checking.
1394 else if (*cursor == '<') {
1395 SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
1396 Rewrite.InsertText(atLoc, "/* ", 3);
1397 cursor = strchr(cursor, '>');
1398 cursor++;
1399 atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
1400 Rewrite.InsertText(atLoc, " */", 3);
1401 }
Steve Naroff2c7afc92007-11-14 19:25:57 +00001402 cursor++;
Fariborz Jahanian6acfa2b2007-10-31 17:29:28 +00001403 }
Steve Naroff2c7afc92007-11-14 19:25:57 +00001404 // Don't forget to add a ';'!!
1405 Rewrite.InsertText(LocEnd.getFileLocWithOffset(1), ";", 1);
1406 } else { // we don't have any instance variables - insert super struct.
1407 endBuf += Lexer::MeasureTokenLength(LocEnd, *SM);
1408 Result += " {\n struct ";
1409 Result += RCDecl->getName();
1410 Result += " _";
1411 Result += RCDecl->getName();
1412 Result += ";\n};\n";
1413 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
1414 Result.c_str(), Result.size());
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00001415 }
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00001416 // Mark this struct as having been generated.
1417 if (!ObjcSynthesizedStructs.insert(CDecl))
Fariborz Jahanian2a3c7762007-10-31 22:57:04 +00001418 assert(false && "struct already synthesize- SynthesizeObjcInternalStruct");
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00001419}
1420
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001421// RewriteObjcMethodsMetaData - Rewrite methods metadata for instance or
1422/// class methods.
Steve Naroffb82c50f2007-11-11 17:19:15 +00001423void RewriteTest::RewriteObjcMethodsMetaData(ObjcMethodDecl *const*Methods,
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001424 int NumMethods,
Fariborz Jahaniana3986372007-10-25 00:14:44 +00001425 bool IsInstanceMethod,
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001426 const char *prefix,
Chris Lattnerc3aa5c42007-10-25 17:07:24 +00001427 const char *ClassName,
1428 std::string &Result) {
Fariborz Jahanian04455192007-10-22 21:41:37 +00001429 static bool objc_impl_method = false;
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001430 if (NumMethods > 0 && !objc_impl_method) {
1431 /* struct _objc_method {
Fariborz Jahanian04455192007-10-22 21:41:37 +00001432 SEL _cmd;
1433 char *method_types;
1434 void *_imp;
1435 }
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001436 */
Chris Lattnerc3aa5c42007-10-25 17:07:24 +00001437 Result += "\nstruct _objc_method {\n";
1438 Result += "\tSEL _cmd;\n";
1439 Result += "\tchar *method_types;\n";
1440 Result += "\tvoid *_imp;\n";
1441 Result += "};\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001442
1443 /* struct _objc_method_list {
1444 struct _objc_method_list *next_method;
1445 int method_count;
1446 struct _objc_method method_list[];
1447 }
1448 */
1449 Result += "\nstruct _objc_method_list {\n";
1450 Result += "\tstruct _objc_method_list *next_method;\n";
1451 Result += "\tint method_count;\n";
1452 Result += "\tstruct _objc_method method_list[];\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001453 objc_impl_method = true;
Fariborz Jahanian96b55da2007-10-19 00:36:46 +00001454 }
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001455 // Build _objc_method_list for class's methods if needed
1456 if (NumMethods > 0) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001457 Result += "\nstatic struct _objc_method_list _OBJC_";
Chris Lattnerc3aa5c42007-10-25 17:07:24 +00001458 Result += prefix;
1459 Result += IsInstanceMethod ? "INSTANCE" : "CLASS";
1460 Result += "_METHODS_";
1461 Result += ClassName;
1462 Result += " __attribute__ ((section (\"__OBJC, __";
1463 Result += IsInstanceMethod ? "inst" : "cls";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001464 Result += "_meth\")))= ";
1465 Result += "{\n\t0, " + utostr(NumMethods) + "\n";
1466
1467 Result += "\t,{{(SEL)\"";
1468 Result += Methods[0]->getSelector().getName().c_str();
Fariborz Jahanianc81f3162007-10-29 22:57:28 +00001469 std::string MethodTypeString;
1470 Context->getObjcEncodingForMethodDecl(Methods[0], MethodTypeString);
1471 Result += "\", \"";
1472 Result += MethodTypeString;
Fariborz Jahanianbd2fd922007-11-13 21:02:00 +00001473 Result += "\", ";
1474 Result += MethodInternalNames[Methods[0]];
1475 Result += "}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001476 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001477 Result += "\t ,{(SEL)\"";
1478 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanianc81f3162007-10-29 22:57:28 +00001479 std::string MethodTypeString;
1480 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
1481 Result += "\", \"";
1482 Result += MethodTypeString;
Fariborz Jahanianbd2fd922007-11-13 21:02:00 +00001483 Result += "\", ";
1484 Result += MethodInternalNames[Methods[i]];
1485 Result += "}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001486 }
1487 Result += "\t }\n};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +00001488 }
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001489}
1490
1491/// RewriteObjcProtocolsMetaData - Rewrite protocols meta-data.
1492void RewriteTest::RewriteObjcProtocolsMetaData(ObjcProtocolDecl **Protocols,
1493 int NumProtocols,
1494 const char *prefix,
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001495 const char *ClassName,
1496 std::string &Result) {
Fariborz Jahanian04455192007-10-22 21:41:37 +00001497 static bool objc_protocol_methods = false;
Fariborz Jahanian04455192007-10-22 21:41:37 +00001498 if (NumProtocols > 0) {
Fariborz Jahanian04455192007-10-22 21:41:37 +00001499 for (int i = 0; i < NumProtocols; i++) {
1500 ObjcProtocolDecl *PDecl = Protocols[i];
1501 // Output struct protocol_methods holder of method selector and type.
1502 if (!objc_protocol_methods &&
1503 (PDecl->getNumInstanceMethods() > 0
1504 || PDecl->getNumClassMethods() > 0)) {
1505 /* struct protocol_methods {
1506 SEL _cmd;
1507 char *method_types;
1508 }
1509 */
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001510 Result += "\nstruct protocol_methods {\n";
1511 Result += "\tSEL _cmd;\n";
1512 Result += "\tchar *method_types;\n";
1513 Result += "};\n";
1514
1515 /* struct _objc_protocol_method_list {
1516 int protocol_method_count;
1517 struct protocol_methods protocols[];
1518 }
1519 */
1520 Result += "\nstruct _objc_protocol_method_list {\n";
1521 Result += "\tint protocol_method_count;\n";
1522 Result += "\tstruct protocol_methods protocols[];\n};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +00001523 objc_protocol_methods = true;
1524 }
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001525
Fariborz Jahanian04455192007-10-22 21:41:37 +00001526 // Output instance methods declared in this protocol.
Fariborz Jahanian04455192007-10-22 21:41:37 +00001527 int NumMethods = PDecl->getNumInstanceMethods();
1528 if (NumMethods > 0) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001529 Result += "\nstatic struct _objc_protocol_method_list "
1530 "_OBJC_PROTOCOL_INSTANCE_METHODS_";
1531 Result += PDecl->getName();
1532 Result += " __attribute__ ((section (\"__OBJC, __cat_inst_meth\")))= "
1533 "{\n\t" + utostr(NumMethods) + "\n";
1534
Fariborz Jahanian04455192007-10-22 21:41:37 +00001535 ObjcMethodDecl **Methods = PDecl->getInstanceMethods();
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001536 Result += "\t,{{(SEL)\"";
1537 Result += Methods[0]->getSelector().getName().c_str();
1538 Result += "\", \"\"}\n";
1539
1540 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001541 Result += "\t ,{(SEL)\"";
1542 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanianc81f3162007-10-29 22:57:28 +00001543 std::string MethodTypeString;
1544 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
1545 Result += "\", \"";
1546 Result += MethodTypeString;
1547 Result += "\"}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001548 }
1549 Result += "\t }\n};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +00001550 }
1551
1552 // Output class methods declared in this protocol.
1553 NumMethods = PDecl->getNumClassMethods();
1554 if (NumMethods > 0) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001555 Result += "\nstatic struct _objc_protocol_method_list "
1556 "_OBJC_PROTOCOL_CLASS_METHODS_";
1557 Result += PDecl->getName();
1558 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
1559 "{\n\t";
1560 Result += utostr(NumMethods);
1561 Result += "\n";
1562
Fariborz Jahanian04455192007-10-22 21:41:37 +00001563 ObjcMethodDecl **Methods = PDecl->getClassMethods();
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001564 Result += "\t,{{(SEL)\"";
1565 Result += Methods[0]->getSelector().getName().c_str();
1566 Result += "\", \"\"}\n";
1567
1568 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001569 Result += "\t ,{(SEL)\"";
1570 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanianc81f3162007-10-29 22:57:28 +00001571 std::string MethodTypeString;
1572 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
1573 Result += "\", \"";
1574 Result += MethodTypeString;
1575 Result += "\"}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001576 }
1577 Result += "\t }\n};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +00001578 }
1579 // Output:
1580 /* struct _objc_protocol {
1581 // Objective-C 1.0 extensions
1582 struct _objc_protocol_extension *isa;
1583 char *protocol_name;
1584 struct _objc_protocol **protocol_list;
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001585 struct _objc_protocol_method_list *instance_methods;
1586 struct _objc_protocol_method_list *class_methods;
Fariborz Jahanian04455192007-10-22 21:41:37 +00001587 };
1588 */
1589 static bool objc_protocol = false;
1590 if (!objc_protocol) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001591 Result += "\nstruct _objc_protocol {\n";
1592 Result += "\tstruct _objc_protocol_extension *isa;\n";
1593 Result += "\tchar *protocol_name;\n";
1594 Result += "\tstruct _objc_protocol **protocol_list;\n";
1595 Result += "\tstruct _objc_protocol_method_list *instance_methods;\n";
1596 Result += "\tstruct _objc_protocol_method_list *class_methods;\n";
1597 Result += "};\n";
1598
1599 /* struct _objc_protocol_list {
1600 struct _objc_protocol_list *next;
1601 int protocol_count;
1602 struct _objc_protocol *class_protocols[];
1603 }
1604 */
1605 Result += "\nstruct _objc_protocol_list {\n";
1606 Result += "\tstruct _objc_protocol_list *next;\n";
1607 Result += "\tint protocol_count;\n";
1608 Result += "\tstruct _objc_protocol *class_protocols[];\n";
1609 Result += "};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +00001610 objc_protocol = true;
1611 }
1612
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001613 Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_";
1614 Result += PDecl->getName();
1615 Result += " __attribute__ ((section (\"__OBJC, __protocol\")))= "
1616 "{\n\t0, \"";
1617 Result += PDecl->getName();
1618 Result += "\", 0, ";
1619 if (PDecl->getInstanceMethods() > 0) {
1620 Result += "&_OBJC_PROTOCOL_INSTANCE_METHODS_";
1621 Result += PDecl->getName();
1622 Result += ", ";
1623 }
Fariborz Jahanian04455192007-10-22 21:41:37 +00001624 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001625 Result += "0, ";
1626 if (PDecl->getClassMethods() > 0) {
1627 Result += "&_OBJC_PROTOCOL_CLASS_METHODS_";
1628 Result += PDecl->getName();
1629 Result += "\n";
1630 }
Fariborz Jahanian04455192007-10-22 21:41:37 +00001631 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001632 Result += "0\n";
1633 Result += "};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +00001634 }
Fariborz Jahanian04455192007-10-22 21:41:37 +00001635 // Output the top lovel protocol meta-data for the class.
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001636 Result += "\nstatic struct _objc_protocol_list _OBJC_";
1637 Result += prefix;
1638 Result += "_PROTOCOLS_";
1639 Result += ClassName;
1640 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
1641 "{\n\t0, ";
1642 Result += utostr(NumProtocols);
1643 Result += "\n";
1644
1645 Result += "\t,{&_OBJC_PROTOCOL_";
1646 Result += Protocols[0]->getName();
1647 Result += " \n";
1648
1649 for (int i = 1; i < NumProtocols; i++) {
Fariborz Jahanian04455192007-10-22 21:41:37 +00001650 ObjcProtocolDecl *PDecl = Protocols[i];
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001651 Result += "\t ,&_OBJC_PROTOCOL_";
1652 Result += PDecl->getName();
1653 Result += "\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +00001654 }
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001655 Result += "\t }\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001656 }
1657}
1658
1659/// RewriteObjcCategoryImplDecl - Rewrite metadata for each category
1660/// implementation.
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001661void RewriteTest::RewriteObjcCategoryImplDecl(ObjcCategoryImplDecl *IDecl,
1662 std::string &Result) {
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001663 ObjcInterfaceDecl *ClassDecl = IDecl->getClassInterface();
1664 // Find category declaration for this implementation.
1665 ObjcCategoryDecl *CDecl;
1666 for (CDecl = ClassDecl->getCategoryList(); CDecl;
1667 CDecl = CDecl->getNextClassCategory())
1668 if (CDecl->getIdentifier() == IDecl->getIdentifier())
1669 break;
Fariborz Jahaniand256e062007-11-13 22:09:49 +00001670
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001671 char *FullCategoryName = (char*)alloca(
1672 strlen(ClassDecl->getName()) + strlen(IDecl->getName()) + 2);
1673 sprintf(FullCategoryName, "%s_%s", ClassDecl->getName(), IDecl->getName());
1674
1675 // Build _objc_method_list for class's instance methods if needed
1676 RewriteObjcMethodsMetaData(IDecl->getInstanceMethods(),
1677 IDecl->getNumInstanceMethods(),
Fariborz Jahaniana3986372007-10-25 00:14:44 +00001678 true,
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001679 "CATEGORY_", FullCategoryName, Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001680
1681 // Build _objc_method_list for class's class methods if needed
1682 RewriteObjcMethodsMetaData(IDecl->getClassMethods(),
1683 IDecl->getNumClassMethods(),
Fariborz Jahaniana3986372007-10-25 00:14:44 +00001684 false,
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001685 "CATEGORY_", FullCategoryName, Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001686
1687 // Protocols referenced in class declaration?
Fariborz Jahaniand256e062007-11-13 22:09:49 +00001688 // Null CDecl is case of a category implementation with no category interface
1689 if (CDecl)
1690 RewriteObjcProtocolsMetaData(CDecl->getReferencedProtocols(),
1691 CDecl->getNumReferencedProtocols(),
1692 "CATEGORY",
1693 FullCategoryName, Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001694
1695 /* struct _objc_category {
1696 char *category_name;
1697 char *class_name;
1698 struct _objc_method_list *instance_methods;
1699 struct _objc_method_list *class_methods;
1700 struct _objc_protocol_list *protocols;
1701 // Objective-C 1.0 extensions
1702 uint32_t size; // sizeof (struct _objc_category)
1703 struct _objc_property_list *instance_properties; // category's own
1704 // @property decl.
1705 };
1706 */
1707
1708 static bool objc_category = false;
1709 if (!objc_category) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001710 Result += "\nstruct _objc_category {\n";
1711 Result += "\tchar *category_name;\n";
1712 Result += "\tchar *class_name;\n";
1713 Result += "\tstruct _objc_method_list *instance_methods;\n";
1714 Result += "\tstruct _objc_method_list *class_methods;\n";
1715 Result += "\tstruct _objc_protocol_list *protocols;\n";
1716 Result += "\tunsigned int size;\n";
1717 Result += "\tstruct _objc_property_list *instance_properties;\n";
1718 Result += "};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001719 objc_category = true;
Fariborz Jahanian04455192007-10-22 21:41:37 +00001720 }
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001721 Result += "\nstatic struct _objc_category _OBJC_CATEGORY_";
1722 Result += FullCategoryName;
1723 Result += " __attribute__ ((section (\"__OBJC, __category\")))= {\n\t\"";
1724 Result += IDecl->getName();
1725 Result += "\"\n\t, \"";
1726 Result += ClassDecl->getName();
1727 Result += "\"\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001728
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001729 if (IDecl->getNumInstanceMethods() > 0) {
1730 Result += "\t, (struct _objc_method_list *)"
1731 "&_OBJC_CATEGORY_INSTANCE_METHODS_";
1732 Result += FullCategoryName;
1733 Result += "\n";
1734 }
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001735 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001736 Result += "\t, 0\n";
1737 if (IDecl->getNumClassMethods() > 0) {
1738 Result += "\t, (struct _objc_method_list *)"
1739 "&_OBJC_CATEGORY_CLASS_METHODS_";
1740 Result += FullCategoryName;
1741 Result += "\n";
1742 }
1743 else
1744 Result += "\t, 0\n";
1745
Fariborz Jahaniand256e062007-11-13 22:09:49 +00001746 if (CDecl && CDecl->getNumReferencedProtocols() > 0) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001747 Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";
1748 Result += FullCategoryName;
1749 Result += "\n";
1750 }
1751 else
1752 Result += "\t, 0\n";
1753 Result += "\t, sizeof(struct _objc_category), 0\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001754}
1755
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00001756/// SynthesizeIvarOffsetComputation - This rutine synthesizes computation of
1757/// ivar offset.
1758void RewriteTest::SynthesizeIvarOffsetComputation(ObjcImplementationDecl *IDecl,
1759 ObjcIvarDecl *ivar,
1760 std::string &Result) {
Fariborz Jahanian9447e462007-11-05 17:47:33 +00001761 Result += "offsetof(struct ";
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00001762 Result += IDecl->getName();
1763 Result += ", ";
1764 Result += ivar->getName();
1765 Result += ")";
1766}
1767
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001768//===----------------------------------------------------------------------===//
1769// Meta Data Emission
1770//===----------------------------------------------------------------------===//
1771
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001772void RewriteTest::RewriteObjcClassMetaData(ObjcImplementationDecl *IDecl,
1773 std::string &Result) {
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001774 ObjcInterfaceDecl *CDecl = IDecl->getClassInterface();
1775
1776 // Build _objc_ivar_list metadata for classes ivars if needed
1777 int NumIvars = IDecl->getImplDeclNumIvars() > 0
1778 ? IDecl->getImplDeclNumIvars()
Steve Naroffdd2e26c2007-11-12 13:56:41 +00001779 : (CDecl ? CDecl->getNumInstanceVariables() : 0);
Fariborz Jahanian7e216522007-11-26 20:59:57 +00001780 // Explictly declared @interface's are already synthesized.
1781 if (CDecl->ImplicitInterfaceDecl()) {
1782 // FIXME: Implementation of a class with no @interface (legacy) doese not
1783 // produce correct synthesis as yet.
1784 SynthesizeObjcInternalStruct(CDecl, Result);
1785 }
Fariborz Jahanianab3ec252007-10-26 23:09:28 +00001786
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001787 if (NumIvars > 0) {
1788 static bool objc_ivar = false;
1789 if (!objc_ivar) {
1790 /* struct _objc_ivar {
1791 char *ivar_name;
1792 char *ivar_type;
1793 int ivar_offset;
1794 };
1795 */
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001796 Result += "\nstruct _objc_ivar {\n";
1797 Result += "\tchar *ivar_name;\n";
1798 Result += "\tchar *ivar_type;\n";
1799 Result += "\tint ivar_offset;\n";
1800 Result += "};\n";
1801
1802 /* struct _objc_ivar_list {
1803 int ivar_count;
1804 struct _objc_ivar ivar_list[];
1805 };
1806 */
1807 Result += "\nstruct _objc_ivar_list {\n";
1808 Result += "\tint ivar_count;\n";
1809 Result += "\tstruct _objc_ivar ivar_list[];\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001810 objc_ivar = true;
1811 }
1812
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001813 Result += "\nstatic struct _objc_ivar_list _OBJC_INSTANCE_VARIABLES_";
1814 Result += IDecl->getName();
1815 Result += " __attribute__ ((section (\"__OBJC, __instance_vars\")))= "
1816 "{\n\t";
1817 Result += utostr(NumIvars);
1818 Result += "\n";
1819
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001820 ObjcIvarDecl **Ivars = IDecl->getImplDeclIVars()
1821 ? IDecl->getImplDeclIVars()
Steve Naroffdd2e26c2007-11-12 13:56:41 +00001822 : CDecl->getInstanceVariables();
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001823 Result += "\t,{{\"";
1824 Result += Ivars[0]->getName();
Fariborz Jahaniand5ea4612007-10-29 17:16:25 +00001825 Result += "\", \"";
1826 std::string StrEncoding;
1827 Context->getObjcEncodingForType(Ivars[0]->getType(), StrEncoding);
1828 Result += StrEncoding;
1829 Result += "\", ";
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00001830 SynthesizeIvarOffsetComputation(IDecl, Ivars[0], Result);
1831 Result += "}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001832 for (int i = 1; i < NumIvars; i++) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001833 Result += "\t ,{\"";
1834 Result += Ivars[i]->getName();
Fariborz Jahaniand5ea4612007-10-29 17:16:25 +00001835 Result += "\", \"";
1836 std::string StrEncoding;
1837 Context->getObjcEncodingForType(Ivars[i]->getType(), StrEncoding);
1838 Result += StrEncoding;
1839 Result += "\", ";
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00001840 SynthesizeIvarOffsetComputation(IDecl, Ivars[i], Result);
1841 Result += "}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001842 }
1843
1844 Result += "\t }\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001845 }
1846
1847 // Build _objc_method_list for class's instance methods if needed
1848 RewriteObjcMethodsMetaData(IDecl->getInstanceMethods(),
1849 IDecl->getNumInstanceMethods(),
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001850 true,
1851 "", IDecl->getName(), Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001852
1853 // Build _objc_method_list for class's class methods if needed
1854 RewriteObjcMethodsMetaData(IDecl->getClassMethods(),
Fariborz Jahaniana3986372007-10-25 00:14:44 +00001855 IDecl->getNumClassMethods(),
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001856 false,
1857 "", IDecl->getName(), Result);
1858
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001859 // Protocols referenced in class declaration?
1860 RewriteObjcProtocolsMetaData(CDecl->getReferencedProtocols(),
1861 CDecl->getNumIntfRefProtocols(),
1862 "CLASS",
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001863 CDecl->getName(), Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00001864
Fariborz Jahanian0f013d12007-10-23 00:02:02 +00001865
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00001866 // Declaration of class/meta-class metadata
1867 /* struct _objc_class {
1868 struct _objc_class *isa; // or const char *root_class_name when metadata
Fariborz Jahanian0f013d12007-10-23 00:02:02 +00001869 const char *super_class_name;
1870 char *name;
1871 long version;
1872 long info;
1873 long instance_size;
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00001874 struct _objc_ivar_list *ivars;
1875 struct _objc_method_list *methods;
Fariborz Jahanian0f013d12007-10-23 00:02:02 +00001876 struct objc_cache *cache;
1877 struct objc_protocol_list *protocols;
1878 const char *ivar_layout;
1879 struct _objc_class_ext *ext;
1880 };
1881 */
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00001882 static bool objc_class = false;
1883 if (!objc_class) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001884 Result += "\nstruct _objc_class {\n";
1885 Result += "\tstruct _objc_class *isa;\n";
1886 Result += "\tconst char *super_class_name;\n";
1887 Result += "\tchar *name;\n";
1888 Result += "\tlong version;\n";
1889 Result += "\tlong info;\n";
1890 Result += "\tlong instance_size;\n";
1891 Result += "\tstruct _objc_ivar_list *ivars;\n";
1892 Result += "\tstruct _objc_method_list *methods;\n";
1893 Result += "\tstruct objc_cache *cache;\n";
1894 Result += "\tstruct _objc_protocol_list *protocols;\n";
1895 Result += "\tconst char *ivar_layout;\n";
1896 Result += "\tstruct _objc_class_ext *ext;\n";
1897 Result += "};\n";
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00001898 objc_class = true;
Fariborz Jahanian0f013d12007-10-23 00:02:02 +00001899 }
1900
1901 // Meta-class metadata generation.
1902 ObjcInterfaceDecl *RootClass = 0;
1903 ObjcInterfaceDecl *SuperClass = CDecl->getSuperClass();
1904 while (SuperClass) {
1905 RootClass = SuperClass;
1906 SuperClass = SuperClass->getSuperClass();
1907 }
1908 SuperClass = CDecl->getSuperClass();
1909
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001910 Result += "\nstatic struct _objc_class _OBJC_METACLASS_";
1911 Result += CDecl->getName();
1912 Result += " __attribute__ ((section (\"__OBJC, __meta_class\")))= "
1913 "{\n\t(struct _objc_class *)\"";
1914 Result += (RootClass ? RootClass->getName() : CDecl->getName());
1915 Result += "\"";
1916
1917 if (SuperClass) {
1918 Result += ", \"";
1919 Result += SuperClass->getName();
1920 Result += "\", \"";
1921 Result += CDecl->getName();
1922 Result += "\"";
1923 }
1924 else {
1925 Result += ", 0, \"";
1926 Result += CDecl->getName();
1927 Result += "\"";
1928 }
Fariborz Jahanian0f013d12007-10-23 00:02:02 +00001929 // TODO: 'ivars' field for root class is currently set to 0.
1930 // 'info' field is initialized to CLS_META(2) for metaclass
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001931 Result += ", 0,2, sizeof(struct _objc_class), 0";
1932 if (CDecl->getNumClassMethods() > 0) {
1933 Result += "\n\t, &_OBJC_CLASS_METHODS_";
1934 Result += CDecl->getName();
1935 Result += "\n";
1936 }
Fariborz Jahanian0f013d12007-10-23 00:02:02 +00001937 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001938 Result += ", 0\n";
1939 if (CDecl->getNumIntfRefProtocols() > 0) {
1940 Result += "\t,0, &_OBJC_CLASS_PROTOCOLS_";
1941 Result += CDecl->getName();
1942 Result += ",0,0\n";
1943 }
Fariborz Jahanian0cb4d922007-10-24 20:54:23 +00001944 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001945 Result += "\t,0,0,0,0\n";
1946 Result += "};\n";
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00001947
1948 // class metadata generation.
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001949 Result += "\nstatic struct _objc_class _OBJC_CLASS_";
1950 Result += CDecl->getName();
1951 Result += " __attribute__ ((section (\"__OBJC, __class\")))= "
1952 "{\n\t&_OBJC_METACLASS_";
1953 Result += CDecl->getName();
1954 if (SuperClass) {
1955 Result += ", \"";
1956 Result += SuperClass->getName();
1957 Result += "\", \"";
1958 Result += CDecl->getName();
1959 Result += "\"";
1960 }
1961 else {
1962 Result += ", 0, \"";
1963 Result += CDecl->getName();
1964 Result += "\"";
1965 }
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00001966 // 'info' field is initialized to CLS_CLASS(1) for class
Fariborz Jahanianab3ec252007-10-26 23:09:28 +00001967 Result += ", 0,1";
1968 if (!ObjcSynthesizedStructs.count(CDecl))
1969 Result += ",0";
1970 else {
1971 // class has size. Must synthesize its size.
Fariborz Jahanian9447e462007-11-05 17:47:33 +00001972 Result += ",sizeof(struct ";
Fariborz Jahanianab3ec252007-10-26 23:09:28 +00001973 Result += CDecl->getName();
1974 Result += ")";
1975 }
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001976 if (NumIvars > 0) {
1977 Result += ", &_OBJC_INSTANCE_VARIABLES_";
1978 Result += CDecl->getName();
1979 Result += "\n\t";
1980 }
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00001981 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001982 Result += ",0";
1983 if (IDecl->getNumInstanceMethods() > 0) {
1984 Result += ", &_OBJC_INSTANCE_METHODS_";
1985 Result += CDecl->getName();
1986 Result += ", 0\n\t";
1987 }
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00001988 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001989 Result += ",0,0";
1990 if (CDecl->getNumIntfRefProtocols() > 0) {
1991 Result += ", &_OBJC_CLASS_PROTOCOLS_";
1992 Result += CDecl->getName();
1993 Result += ", 0,0\n";
1994 }
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00001995 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00001996 Result += ",0,0,0\n";
1997 Result += "};\n";
Fariborz Jahanian0f013d12007-10-23 00:02:02 +00001998}
Fariborz Jahanian45d52f72007-10-18 22:09:03 +00001999
Fariborz Jahanian8c664912007-11-13 19:21:13 +00002000/// RewriteImplementations - This routine rewrites all method implementations
2001/// and emits meta-data.
2002
2003void RewriteTest::RewriteImplementations(std::string &Result) {
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00002004 int ClsDefCount = ClassImplementation.size();
2005 int CatDefCount = CategoryImplementation.size();
Fariborz Jahanian8c664912007-11-13 19:21:13 +00002006
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00002007 if (ClsDefCount == 0 && CatDefCount == 0)
2008 return;
Fariborz Jahanian8c664912007-11-13 19:21:13 +00002009 // Rewrite implemented methods
2010 for (int i = 0; i < ClsDefCount; i++)
2011 RewriteImplementationDecl(ClassImplementation[i]);
Fariborz Jahanian45d52f72007-10-18 22:09:03 +00002012
Fariborz Jahanian0136e372007-11-13 20:04:28 +00002013 for (int i = 0; i < CatDefCount; i++)
2014 RewriteImplementationDecl(CategoryImplementation[i]);
2015
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00002016 // This is needed for use of offsetof
2017 Result += "#include <stddef.h>\n";
Fariborz Jahanian8c664912007-11-13 19:21:13 +00002018
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002019 // For each implemented class, write out all its meta data.
Fariborz Jahanian45d52f72007-10-18 22:09:03 +00002020 for (int i = 0; i < ClsDefCount; i++)
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002021 RewriteObjcClassMetaData(ClassImplementation[i], Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002022
2023 // For each implemented category, write out all its meta data.
2024 for (int i = 0; i < CatDefCount; i++)
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002025 RewriteObjcCategoryImplDecl(CategoryImplementation[i], Result);
Fariborz Jahanian45d52f72007-10-18 22:09:03 +00002026
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00002027 // Write objc_symtab metadata
2028 /*
2029 struct _objc_symtab
2030 {
2031 long sel_ref_cnt;
2032 SEL *refs;
2033 short cls_def_cnt;
2034 short cat_def_cnt;
2035 void *defs[cls_def_cnt + cat_def_cnt];
2036 };
2037 */
2038
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002039 Result += "\nstruct _objc_symtab {\n";
2040 Result += "\tlong sel_ref_cnt;\n";
2041 Result += "\tSEL *refs;\n";
2042 Result += "\tshort cls_def_cnt;\n";
2043 Result += "\tshort cat_def_cnt;\n";
2044 Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n";
2045 Result += "};\n\n";
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00002046
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002047 Result += "static struct _objc_symtab "
2048 "_OBJC_SYMBOLS __attribute__((section (\"__OBJC, __symbols\")))= {\n";
2049 Result += "\t0, 0, " + utostr(ClsDefCount)
2050 + ", " + utostr(CatDefCount) + "\n";
2051 for (int i = 0; i < ClsDefCount; i++) {
2052 Result += "\t,&_OBJC_CLASS_";
2053 Result += ClassImplementation[i]->getName();
2054 Result += "\n";
2055 }
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00002056
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002057 for (int i = 0; i < CatDefCount; i++) {
2058 Result += "\t,&_OBJC_CATEGORY_";
2059 Result += CategoryImplementation[i]->getClassInterface()->getName();
2060 Result += "_";
2061 Result += CategoryImplementation[i]->getName();
2062 Result += "\n";
2063 }
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00002064
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002065 Result += "};\n\n";
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00002066
2067 // Write objc_module metadata
2068
2069 /*
2070 struct _objc_module {
2071 long version;
2072 long size;
2073 const char *name;
2074 struct _objc_symtab *symtab;
2075 }
2076 */
2077
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002078 Result += "\nstruct _objc_module {\n";
2079 Result += "\tlong version;\n";
2080 Result += "\tlong size;\n";
2081 Result += "\tconst char *name;\n";
2082 Result += "\tstruct _objc_symtab *symtab;\n";
2083 Result += "};\n\n";
2084 Result += "static struct _objc_module "
2085 "_OBJC_MODULES __attribute__ ((section (\"__OBJC, __module_info\")))= {\n";
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00002086 Result += "\t" + utostr(OBJC_ABI_VERSION) +
2087 ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002088 Result += "};\n\n";
Fariborz Jahanian8c664912007-11-13 19:21:13 +00002089
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00002090}
Chris Lattner6fe8b272007-10-16 22:36:42 +00002091