blob: ff9bf2f9243d0bbb44b5f0b8b47a981646184da6 [file] [log] [blame]
Chris Lattner77cd2a02007-10-11 00:43:27 +00001//===--- RewriteTest.cpp - Playground for the code rewriter ---------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Chris Lattner and is distributed under the
6// University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Hacks and fun related to the code rewriter.
11//
12//===----------------------------------------------------------------------===//
13
14#include "ASTConsumers.h"
Chris Lattner8a12c272007-10-11 18:38:32 +000015#include "clang/Rewrite/Rewriter.h"
Chris Lattner77cd2a02007-10-11 00:43:27 +000016#include "clang/AST/AST.h"
17#include "clang/AST/ASTConsumer.h"
Chris Lattner8a12c272007-10-11 18:38:32 +000018#include "clang/Basic/SourceManager.h"
Steve Naroffebf2b562007-10-23 23:50:29 +000019#include "clang/Basic/IdentifierTable.h"
Chris Lattner158ecb92007-10-25 17:07:24 +000020#include "llvm/ADT/StringExtras.h"
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +000021#include "llvm/ADT/SmallPtrSet.h"
Steve Naroff2feac5e2007-10-30 03:43:13 +000022#include "clang/Lex/Lexer.h"
Chris Lattner77cd2a02007-10-11 00:43:27 +000023using namespace clang;
Chris Lattner158ecb92007-10-25 17:07:24 +000024using llvm::utostr;
Chris Lattner77cd2a02007-10-11 00:43:27 +000025
Chris Lattner77cd2a02007-10-11 00:43:27 +000026namespace {
Chris Lattner8a12c272007-10-11 18:38:32 +000027 class RewriteTest : public ASTConsumer {
Chris Lattner2c64b7b2007-10-16 21:07:07 +000028 Rewriter Rewrite;
Chris Lattner01c57482007-10-17 22:35:30 +000029 ASTContext *Context;
Chris Lattner77cd2a02007-10-11 00:43:27 +000030 SourceManager *SM;
Chris Lattner8a12c272007-10-11 18:38:32 +000031 unsigned MainFileID;
Chris Lattner2c64b7b2007-10-16 21:07:07 +000032 SourceLocation LastIncLoc;
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +000033 llvm::SmallVector<ObjcImplementationDecl *, 8> ClassImplementation;
34 llvm::SmallVector<ObjcCategoryImplDecl *, 8> CategoryImplementation;
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +000035 llvm::SmallPtrSet<ObjcInterfaceDecl*, 8> ObjcSynthesizedStructs;
Steve Naroff8749be52007-10-31 22:11:35 +000036 llvm::SmallPtrSet<ObjcInterfaceDecl*, 8> ObjcForwardDecls;
Fariborz Jahanianb7908b52007-11-13 21:02:00 +000037 llvm::DenseMap<ObjcMethodDecl*, std::string> MethodInternalNames;
Steve Naroffebf2b562007-10-23 23:50:29 +000038
39 FunctionDecl *MsgSendFunctionDecl;
40 FunctionDecl *GetClassFunctionDecl;
Steve Naroff934f2762007-10-24 22:48:43 +000041 FunctionDecl *SelGetUidFunctionDecl;
Steve Naroff96984642007-11-08 14:30:50 +000042 FunctionDecl *CFStringFunctionDecl;
Steve Naroffebf2b562007-10-23 23:50:29 +000043
Steve Naroffbeaf2992007-11-03 11:27:19 +000044 // ObjC string constant support.
45 FileVarDecl *ConstantStringClassReference;
46 RecordDecl *NSStringRecord;
Steve Naroffab972d32007-11-04 22:37:50 +000047
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +000048 static const int OBJC_ABI_VERSION =7 ;
Chris Lattner77cd2a02007-10-11 00:43:27 +000049 public:
Chris Lattner01c57482007-10-17 22:35:30 +000050 void Initialize(ASTContext &context, unsigned mainFileID) {
51 Context = &context;
52 SM = &Context->SourceMgr;
Chris Lattner8a12c272007-10-11 18:38:32 +000053 MainFileID = mainFileID;
Steve Naroffebf2b562007-10-23 23:50:29 +000054 MsgSendFunctionDecl = 0;
Steve Naroffc0006092007-10-24 01:09:48 +000055 GetClassFunctionDecl = 0;
Steve Naroff934f2762007-10-24 22:48:43 +000056 SelGetUidFunctionDecl = 0;
Steve Naroff96984642007-11-08 14:30:50 +000057 CFStringFunctionDecl = 0;
Steve Naroffbeaf2992007-11-03 11:27:19 +000058 ConstantStringClassReference = 0;
59 NSStringRecord = 0;
Chris Lattner01c57482007-10-17 22:35:30 +000060 Rewrite.setSourceMgr(Context->SourceMgr);
Steve Naroffe3abbf52007-11-05 14:55:35 +000061 // declaring objc_selector outside the parameter list removes a silly
62 // scope related warning...
Steve Naroff21867b12007-11-07 18:43:40 +000063 const char *s = "struct objc_selector; struct objc_class;\n"
Steve Naroffe3abbf52007-11-05 14:55:35 +000064 "extern struct objc_object *objc_msgSend"
Steve Naroffab972d32007-11-04 22:37:50 +000065 "(struct objc_object *, struct objc_selector *, ...);\n"
66 "extern struct objc_object *objc_getClass"
Steve Naroff21867b12007-11-07 18:43:40 +000067 "(const char *);\n"
68 "extern void objc_exception_throw(struct objc_object *);\n"
69 "extern void objc_exception_try_enter(void *);\n"
70 "extern void objc_exception_try_exit(void *);\n"
71 "extern struct objc_object *objc_exception_extract(void *);\n"
72 "extern int objc_exception_match"
73 "(struct objc_class *, struct objc_object *, ...);\n";
74
Steve Naroffab972d32007-11-04 22:37:50 +000075 Rewrite.InsertText(SourceLocation::getFileLoc(mainFileID, 0),
76 s, strlen(s));
Chris Lattner77cd2a02007-10-11 00:43:27 +000077 }
Chris Lattner8a12c272007-10-11 18:38:32 +000078
Chris Lattnerf04da132007-10-24 17:06:59 +000079 // Top Level Driver code.
80 virtual void HandleTopLevelDecl(Decl *D);
Chris Lattner2c64b7b2007-10-16 21:07:07 +000081 void HandleDeclInMainFile(Decl *D);
Chris Lattnerf04da132007-10-24 17:06:59 +000082 ~RewriteTest();
83
84 // Syntactic Rewriting.
Steve Naroffab972d32007-11-04 22:37:50 +000085 void RewritePrologue(SourceLocation Loc);
Chris Lattner2c64b7b2007-10-16 21:07:07 +000086 void RewriteInclude(SourceLocation Loc);
Chris Lattnerf04da132007-10-24 17:06:59 +000087 void RewriteTabs();
88 void RewriteForwardClassDecl(ObjcClassDecl *Dcl);
Steve Naroffbef11852007-10-26 20:53:56 +000089 void RewriteInterfaceDecl(ObjcInterfaceDecl *Dcl);
Fariborz Jahanian66d6b292007-11-13 20:04:28 +000090 void RewriteImplementationDecl(NamedDecl *Dcl);
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +000091 void RewriteObjcMethodDecl(ObjcMethodDecl *MDecl, std::string &ResultStr);
Steve Naroff423cb562007-10-30 13:30:57 +000092 void RewriteCategoryDecl(ObjcCategoryDecl *Dcl);
Steve Naroff752d6ef2007-10-30 16:42:30 +000093 void RewriteProtocolDecl(ObjcProtocolDecl *Dcl);
Steve Naroff423cb562007-10-30 13:30:57 +000094 void RewriteMethods(int nMethods, ObjcMethodDecl **Methods);
Fariborz Jahanian957cf652007-11-07 00:09:37 +000095 void RewriteProperties(int nProperties, ObjcPropertyDecl **Properties);
Steve Naroff09b266e2007-10-30 23:14:51 +000096 void RewriteFunctionDecl(FunctionDecl *FD);
Steve Naroffd5255f52007-11-01 13:24:47 +000097 void RewriteObjcQualifiedInterfaceTypes(
98 const FunctionTypeProto *proto, FunctionDecl *FD);
99 bool needToScanForQualifiers(QualType T);
Chris Lattner311ff022007-10-16 22:36:42 +0000100
Chris Lattnerf04da132007-10-24 17:06:59 +0000101 // Expression Rewriting.
Steve Narofff3473a72007-11-09 15:20:18 +0000102 Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S);
Chris Lattnere64b7772007-10-24 16:57:36 +0000103 Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
Steve Naroffb42f8412007-11-05 14:50:49 +0000104 Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp);
Chris Lattnere64b7772007-10-24 16:57:36 +0000105 Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
Steve Naroffbeaf2992007-11-03 11:27:19 +0000106 Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp);
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000107 Stmt *RewriteObjcTryStmt(ObjcAtTryStmt *S);
108 Stmt *RewriteObjcCatchStmt(ObjcAtCatchStmt *S);
109 Stmt *RewriteObjcFinallyStmt(ObjcAtFinallyStmt *S);
Steve Naroff2bd03922007-11-07 15:32:26 +0000110 Stmt *RewriteObjcThrowStmt(ObjcAtThrowStmt *S);
Steve Naroff934f2762007-10-24 22:48:43 +0000111 CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD,
112 Expr **args, unsigned nargs);
Steve Naroff09b266e2007-10-30 23:14:51 +0000113 void SynthMsgSendFunctionDecl();
114 void SynthGetClassFunctionDecl();
Steve Naroff96984642007-11-08 14:30:50 +0000115 void SynthCFStringFunctionDecl();
116
Chris Lattnerf04da132007-10-24 17:06:59 +0000117 // Metadata emission.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000118 void RewriteObjcClassMetaData(ObjcImplementationDecl *IDecl,
119 std::string &Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000120
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000121 void RewriteObjcCategoryImplDecl(ObjcCategoryImplDecl *CDecl,
122 std::string &Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000123
Steve Naroff0416fb92007-11-11 17:19:15 +0000124 void RewriteObjcMethodsMetaData(ObjcMethodDecl *const*Methods,
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000125 int NumMethods,
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +0000126 bool IsInstanceMethod,
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000127 const char *prefix,
Chris Lattner158ecb92007-10-25 17:07:24 +0000128 const char *ClassName,
129 std::string &Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000130
131 void RewriteObjcProtocolsMetaData(ObjcProtocolDecl **Protocols,
132 int NumProtocols,
133 const char *prefix,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000134 const char *ClassName,
135 std::string &Result);
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000136 void SynthesizeObjcInternalStruct(ObjcInterfaceDecl *CDecl,
137 std::string &Result);
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000138 void SynthesizeIvarOffsetComputation(ObjcImplementationDecl *IDecl,
139 ObjcIvarDecl *ivar,
140 std::string &Result);
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +0000141 void RewriteImplementations(std::string &Result);
Chris Lattner77cd2a02007-10-11 00:43:27 +0000142 };
143}
144
Chris Lattner8a12c272007-10-11 18:38:32 +0000145ASTConsumer *clang::CreateCodeRewriterTest() { return new RewriteTest(); }
Chris Lattner77cd2a02007-10-11 00:43:27 +0000146
Chris Lattnerf04da132007-10-24 17:06:59 +0000147//===----------------------------------------------------------------------===//
148// Top Level Driver Code
149//===----------------------------------------------------------------------===//
150
Chris Lattner8a12c272007-10-11 18:38:32 +0000151void RewriteTest::HandleTopLevelDecl(Decl *D) {
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000152 // Two cases: either the decl could be in the main file, or it could be in a
153 // #included file. If the former, rewrite it now. If the later, check to see
154 // if we rewrote the #include/#import.
155 SourceLocation Loc = D->getLocation();
156 Loc = SM->getLogicalLoc(Loc);
157
158 // If this is for a builtin, ignore it.
159 if (Loc.isInvalid()) return;
160
Steve Naroffebf2b562007-10-23 23:50:29 +0000161 // Look for built-in declarations that we need to refer during the rewrite.
162 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Steve Naroff09b266e2007-10-30 23:14:51 +0000163 RewriteFunctionDecl(FD);
Steve Naroffbeaf2992007-11-03 11:27:19 +0000164 } else if (FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
165 // declared in <Foundation/NSString.h>
166 if (strcmp(FVD->getName(), "_NSConstantStringClassReference") == 0) {
167 ConstantStringClassReference = FVD;
168 return;
169 }
Steve Naroffbef11852007-10-26 20:53:56 +0000170 } else if (ObjcInterfaceDecl *MD = dyn_cast<ObjcInterfaceDecl>(D)) {
171 RewriteInterfaceDecl(MD);
Steve Naroff423cb562007-10-30 13:30:57 +0000172 } else if (ObjcCategoryDecl *CD = dyn_cast<ObjcCategoryDecl>(D)) {
173 RewriteCategoryDecl(CD);
Steve Naroff752d6ef2007-10-30 16:42:30 +0000174 } else if (ObjcProtocolDecl *PD = dyn_cast<ObjcProtocolDecl>(D)) {
175 RewriteProtocolDecl(PD);
Steve Naroffebf2b562007-10-23 23:50:29 +0000176 }
Chris Lattnerf04da132007-10-24 17:06:59 +0000177 // If we have a decl in the main file, see if we should rewrite it.
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000178 if (SM->getDecomposedFileLoc(Loc).first == MainFileID)
179 return HandleDeclInMainFile(D);
180
Chris Lattnerf04da132007-10-24 17:06:59 +0000181 // Otherwise, see if there is a #import in the main file that should be
182 // rewritten.
Steve Naroff32174822007-11-09 12:50:28 +0000183 //RewriteInclude(Loc);
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000184}
185
Chris Lattnerf04da132007-10-24 17:06:59 +0000186/// HandleDeclInMainFile - This is called for each top-level decl defined in the
187/// main file of the input.
188void RewriteTest::HandleDeclInMainFile(Decl *D) {
189 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
190 if (Stmt *Body = FD->getBody())
Steve Narofff3473a72007-11-09 15:20:18 +0000191 FD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
Chris Lattnerf04da132007-10-24 17:06:59 +0000192
193 if (ObjcImplementationDecl *CI = dyn_cast<ObjcImplementationDecl>(D))
194 ClassImplementation.push_back(CI);
195 else if (ObjcCategoryImplDecl *CI = dyn_cast<ObjcCategoryImplDecl>(D))
196 CategoryImplementation.push_back(CI);
197 else if (ObjcClassDecl *CD = dyn_cast<ObjcClassDecl>(D))
198 RewriteForwardClassDecl(CD);
Steve Narofff3473a72007-11-09 15:20:18 +0000199 else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
200 if (VD->getInit())
201 RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
202 }
Chris Lattnerf04da132007-10-24 17:06:59 +0000203 // Nothing yet.
204}
205
206RewriteTest::~RewriteTest() {
207 // Get the top-level buffer that this corresponds to.
Chris Lattner74a0c772007-11-08 04:27:23 +0000208
209 // Rewrite tabs if we care.
210 //RewriteTabs();
Chris Lattnerf04da132007-10-24 17:06:59 +0000211
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000212 // Rewrite Objective-c meta data*
213 std::string ResultStr;
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +0000214 RewriteImplementations(ResultStr);
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000215
Chris Lattnerf04da132007-10-24 17:06:59 +0000216 // Get the buffer corresponding to MainFileID. If we haven't changed it, then
217 // we are done.
218 if (const RewriteBuffer *RewriteBuf =
219 Rewrite.getRewriteBufferFor(MainFileID)) {
Steve Naroffbeaf2992007-11-03 11:27:19 +0000220 //printf("Changed:\n");
Chris Lattnerf04da132007-10-24 17:06:59 +0000221 std::string S(RewriteBuf->begin(), RewriteBuf->end());
222 printf("%s\n", S.c_str());
223 } else {
224 printf("No changes\n");
225 }
Fariborz Jahanian4402d812007-11-07 18:40:28 +0000226 // Emit metadata.
227 printf("%s", ResultStr.c_str());
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000228}
229
Chris Lattnerf04da132007-10-24 17:06:59 +0000230//===----------------------------------------------------------------------===//
231// Syntactic (non-AST) Rewriting Code
232//===----------------------------------------------------------------------===//
233
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000234void RewriteTest::RewriteInclude(SourceLocation Loc) {
235 // Rip up the #include stack to the main file.
236 SourceLocation IncLoc = Loc, NextLoc = Loc;
237 do {
238 IncLoc = Loc;
239 Loc = SM->getLogicalLoc(NextLoc);
240 NextLoc = SM->getIncludeLoc(Loc);
241 } while (!NextLoc.isInvalid());
242
243 // Loc is now the location of the #include filename "foo" or <foo/bar.h>.
244 // IncLoc indicates the header that was included if it is useful.
245 IncLoc = SM->getLogicalLoc(IncLoc);
246 if (SM->getDecomposedFileLoc(Loc).first != MainFileID ||
247 Loc == LastIncLoc)
248 return;
249 LastIncLoc = Loc;
250
251 unsigned IncCol = SM->getColumnNumber(Loc);
252 SourceLocation LineStartLoc = Loc.getFileLocWithOffset(-IncCol+1);
253
254 // Replace the #import with #include.
255 Rewrite.ReplaceText(LineStartLoc, IncCol-1, "#include ", strlen("#include "));
256}
257
Chris Lattnerf04da132007-10-24 17:06:59 +0000258void RewriteTest::RewriteTabs() {
259 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
260 const char *MainBufStart = MainBuf.first;
261 const char *MainBufEnd = MainBuf.second;
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +0000262
Chris Lattnerf04da132007-10-24 17:06:59 +0000263 // Loop over the whole file, looking for tabs.
264 for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) {
265 if (*BufPtr != '\t')
266 continue;
267
268 // Okay, we found a tab. This tab will turn into at least one character,
269 // but it depends on which 'virtual column' it is in. Compute that now.
270 unsigned VCol = 0;
271 while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' &&
272 BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r')
273 ++VCol;
274
275 // Okay, now that we know the virtual column, we know how many spaces to
276 // insert. We assume 8-character tab-stops.
277 unsigned Spaces = 8-(VCol & 7);
278
279 // Get the location of the tab.
280 SourceLocation TabLoc =
281 SourceLocation::getFileLoc(MainFileID, BufPtr-MainBufStart);
282
283 // Rewrite the single tab character into a sequence of spaces.
284 Rewrite.ReplaceText(TabLoc, 1, " ", Spaces);
285 }
Chris Lattner8a12c272007-10-11 18:38:32 +0000286}
287
288
Chris Lattnerf04da132007-10-24 17:06:59 +0000289void RewriteTest::RewriteForwardClassDecl(ObjcClassDecl *ClassDecl) {
290 int numDecls = ClassDecl->getNumForwardDecls();
291 ObjcInterfaceDecl **ForwardDecls = ClassDecl->getForwardDecls();
292
293 // Get the start location and compute the semi location.
294 SourceLocation startLoc = ClassDecl->getLocation();
295 const char *startBuf = SM->getCharacterData(startLoc);
296 const char *semiPtr = strchr(startBuf, ';');
297
298 // Translate to typedef's that forward reference structs with the same name
299 // as the class. As a convenience, we include the original declaration
300 // as a comment.
301 std::string typedefString;
302 typedefString += "// ";
Steve Naroff934f2762007-10-24 22:48:43 +0000303 typedefString.append(startBuf, semiPtr-startBuf+1);
304 typedefString += "\n";
305 for (int i = 0; i < numDecls; i++) {
306 ObjcInterfaceDecl *ForwardDecl = ForwardDecls[i];
Steve Naroff8749be52007-10-31 22:11:35 +0000307 if (ObjcForwardDecls.count(ForwardDecl))
308 continue;
Steve Naroff32174822007-11-09 12:50:28 +0000309 typedefString += "#ifndef _REWRITER_typedef_";
310 typedefString += ForwardDecl->getName();
311 typedefString += "\n";
312 typedefString += "#define _REWRITER_typedef_";
313 typedefString += ForwardDecl->getName();
314 typedefString += "\n";
Steve Naroff352336b2007-11-05 14:36:37 +0000315 typedefString += "typedef struct objc_object ";
Steve Naroff934f2762007-10-24 22:48:43 +0000316 typedefString += ForwardDecl->getName();
Steve Naroff32174822007-11-09 12:50:28 +0000317 typedefString += ";\n#endif\n";
Steve Naroff8749be52007-10-31 22:11:35 +0000318 // Mark this typedef as having been generated.
319 if (!ObjcForwardDecls.insert(ForwardDecl))
Fariborz Jahanianaff56d02007-10-31 22:57:04 +0000320 assert(false && "typedef already output");
Steve Naroff934f2762007-10-24 22:48:43 +0000321 }
322
323 // Replace the @class with typedefs corresponding to the classes.
324 Rewrite.ReplaceText(startLoc, semiPtr-startBuf+1,
325 typedefString.c_str(), typedefString.size());
Chris Lattnerf04da132007-10-24 17:06:59 +0000326}
327
Steve Naroff423cb562007-10-30 13:30:57 +0000328void RewriteTest::RewriteMethods(int nMethods, ObjcMethodDecl **Methods) {
329 for (int i = 0; i < nMethods; i++) {
330 ObjcMethodDecl *Method = Methods[i];
331 SourceLocation Loc = Method->getLocStart();
332
Chris Lattner28d1fe82007-11-08 04:41:51 +0000333 Rewrite.InsertText(Loc, "// ", 3);
Steve Naroff423cb562007-10-30 13:30:57 +0000334
335 // FIXME: handle methods that are declared across multiple lines.
336 }
337}
338
Fariborz Jahanian957cf652007-11-07 00:09:37 +0000339void RewriteTest::RewriteProperties(int nProperties, ObjcPropertyDecl **Properties)
340{
341 for (int i = 0; i < nProperties; i++) {
342 ObjcPropertyDecl *Property = Properties[i];
343 SourceLocation Loc = Property->getLocation();
344
345 Rewrite.ReplaceText(Loc, 0, "// ", 3);
346
347 // FIXME: handle properties that are declared across multiple lines.
348 }
349}
350
Steve Naroff423cb562007-10-30 13:30:57 +0000351void RewriteTest::RewriteCategoryDecl(ObjcCategoryDecl *CatDecl) {
352 SourceLocation LocStart = CatDecl->getLocStart();
353
354 // FIXME: handle category headers that are declared across multiple lines.
355 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
356
357 RewriteMethods(CatDecl->getNumInstanceMethods(),
358 CatDecl->getInstanceMethods());
359 RewriteMethods(CatDecl->getNumClassMethods(),
360 CatDecl->getClassMethods());
361 // Lastly, comment out the @end.
362 Rewrite.ReplaceText(CatDecl->getAtEndLoc(), 0, "// ", 3);
363}
364
Steve Naroff752d6ef2007-10-30 16:42:30 +0000365void RewriteTest::RewriteProtocolDecl(ObjcProtocolDecl *PDecl) {
366 SourceLocation LocStart = PDecl->getLocStart();
367
368 // FIXME: handle protocol headers that are declared across multiple lines.
369 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
370
371 RewriteMethods(PDecl->getNumInstanceMethods(),
372 PDecl->getInstanceMethods());
373 RewriteMethods(PDecl->getNumClassMethods(),
374 PDecl->getClassMethods());
375 // Lastly, comment out the @end.
376 Rewrite.ReplaceText(PDecl->getAtEndLoc(), 0, "// ", 3);
377}
378
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000379void RewriteTest::RewriteObjcMethodDecl(ObjcMethodDecl *OMD,
380 std::string &ResultStr) {
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +0000381 static bool includeObjc = false;
382 if (!includeObjc) {
383 ResultStr += "#include <Objc/objc.h>\n";
384 includeObjc = true;
385 }
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000386 ResultStr += "\nstatic ";
387 ResultStr += OMD->getResultType().getAsString();
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000388 ResultStr += "\n";
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000389
390 // Unique method name
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000391 std::string NameStr;
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000392
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000393 if (OMD->isInstance())
394 NameStr += "_I_";
395 else
396 NameStr += "_C_";
397
398 NameStr += OMD->getClassInterface()->getName();
399 NameStr += "_";
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000400
401 NamedDecl *MethodContext = OMD->getMethodContext();
402 if (ObjcCategoryImplDecl *CID =
403 dyn_cast<ObjcCategoryImplDecl>(MethodContext)) {
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000404 NameStr += CID->getName();
405 NameStr += "_";
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000406 }
407 // Append selector names, replacing ':' with '_'
408 const char *selName = OMD->getSelector().getName().c_str();
409 if (!strchr(selName, ':'))
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000410 NameStr += OMD->getSelector().getName();
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000411 else {
412 std::string selString = OMD->getSelector().getName();
413 int len = selString.size();
414 for (int i = 0; i < len; i++)
415 if (selString[i] == ':')
416 selString[i] = '_';
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000417 NameStr += selString;
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000418 }
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000419 // Remember this name for metadata emission
420 MethodInternalNames[OMD] = NameStr;
421 ResultStr += NameStr;
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000422
423 // Rewrite arguments
424 ResultStr += "(";
425
426 // invisible arguments
427 if (OMD->isInstance()) {
428 QualType selfTy = Context->getObjcInterfaceType(OMD->getClassInterface());
429 selfTy = Context->getPointerType(selfTy);
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000430 if (ObjcSynthesizedStructs.count(OMD->getClassInterface()))
431 ResultStr += "struct ";
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000432 ResultStr += selfTy.getAsString();
433 }
434 else
435 ResultStr += Context->getObjcIdType().getAsString();
436
437 ResultStr += " self, ";
438 ResultStr += Context->getObjcSelType().getAsString();
439 ResultStr += " _cmd";
440
441 // Method arguments.
442 for (int i = 0; i < OMD->getNumParams(); i++) {
443 ParmVarDecl *PDecl = OMD->getParamDecl(i);
444 ResultStr += ", ";
445 ResultStr += PDecl->getType().getAsString();
446 ResultStr += " ";
447 ResultStr += PDecl->getName();
448 }
449 ResultStr += ")";
450
451}
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000452void RewriteTest::RewriteImplementationDecl(NamedDecl *OID) {
453 ObjcImplementationDecl *IMD = dyn_cast<ObjcImplementationDecl>(OID);
454 ObjcCategoryImplDecl *CID = dyn_cast<ObjcCategoryImplDecl>(OID);
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000455
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000456 if (IMD)
457 Rewrite.InsertText(IMD->getLocStart(), "// ", 3);
458 else
459 Rewrite.InsertText(CID->getLocStart(), "// ", 3);
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000460
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000461 int numMethods = IMD ? IMD->getNumInstanceMethods()
462 : CID->getNumInstanceMethods();
463
464 for (int i = 0; i < numMethods; i++) {
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000465 std::string ResultStr;
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000466 ObjcMethodDecl *OMD;
467 if (IMD)
468 OMD = IMD->getInstanceMethods()[i];
469 else
470 OMD = CID->getInstanceMethods()[i];
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000471 RewriteObjcMethodDecl(OMD, ResultStr);
472 SourceLocation LocStart = OMD->getLocStart();
473 SourceLocation LocEnd = OMD->getBody()->getLocStart();
474
475 const char *startBuf = SM->getCharacterData(LocStart);
476 const char *endBuf = SM->getCharacterData(LocEnd);
477 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
478 ResultStr.c_str(), ResultStr.size());
479 }
480
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000481 numMethods = IMD ? IMD->getNumClassMethods() : CID->getNumClassMethods();
482 for (int i = 0; i < numMethods; i++) {
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000483 std::string ResultStr;
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000484 ObjcMethodDecl *OMD;
485 if (IMD)
486 OMD = IMD->getClassMethods()[i];
487 else
488 OMD = CID->getClassMethods()[i];
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000489 RewriteObjcMethodDecl(OMD, ResultStr);
490 SourceLocation LocStart = OMD->getLocStart();
491 SourceLocation LocEnd = OMD->getBody()->getLocStart();
492
493 const char *startBuf = SM->getCharacterData(LocStart);
494 const char *endBuf = SM->getCharacterData(LocEnd);
495 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
496 ResultStr.c_str(), ResultStr.size());
497 }
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000498 if (IMD)
499 Rewrite.InsertText(IMD->getLocEnd(), "// ", 3);
500 else
501 Rewrite.InsertText(CID->getLocEnd(), "// ", 3);
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000502}
503
Steve Naroffbef11852007-10-26 20:53:56 +0000504void RewriteTest::RewriteInterfaceDecl(ObjcInterfaceDecl *ClassDecl) {
Steve Narofff908a872007-10-30 02:23:23 +0000505
506 SourceLocation LocStart = ClassDecl->getLocStart();
507 SourceLocation LocEnd = ClassDecl->getLocEnd();
508
509 const char *startBuf = SM->getCharacterData(LocStart);
510 const char *endBuf = SM->getCharacterData(LocEnd);
511
Steve Naroff2feac5e2007-10-30 03:43:13 +0000512 endBuf += Lexer::MeasureTokenLength(LocEnd, *SM);
Steve Narofff908a872007-10-30 02:23:23 +0000513
514 std::string ResultStr;
Steve Naroff6c6a2db2007-11-01 03:35:41 +0000515 if (!ObjcForwardDecls.count(ClassDecl)) {
516 // we haven't seen a forward decl - generate a typedef.
Steve Naroff32174822007-11-09 12:50:28 +0000517 ResultStr += "#ifndef _REWRITER_typedef_";
518 ResultStr += ClassDecl->getName();
519 ResultStr += "\n";
520 ResultStr += "#define _REWRITER_typedef_";
521 ResultStr += ClassDecl->getName();
522 ResultStr += "\n";
Steve Naroff352336b2007-11-05 14:36:37 +0000523 ResultStr += "typedef struct objc_object ";
Steve Naroff6c6a2db2007-11-01 03:35:41 +0000524 ResultStr += ClassDecl->getName();
Steve Naroff32174822007-11-09 12:50:28 +0000525 ResultStr += ";\n#endif\n";
Steve Naroff6c6a2db2007-11-01 03:35:41 +0000526
527 // Mark this typedef as having been generated.
528 ObjcForwardDecls.insert(ClassDecl);
529 }
Steve Narofff908a872007-10-30 02:23:23 +0000530 SynthesizeObjcInternalStruct(ClassDecl, ResultStr);
531
Steve Naroff2feac5e2007-10-30 03:43:13 +0000532 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
Steve Narofff908a872007-10-30 02:23:23 +0000533 ResultStr.c_str(), ResultStr.size());
Fariborz Jahanian957cf652007-11-07 00:09:37 +0000534 RewriteProperties(ClassDecl->getNumPropertyDecl(),
535 ClassDecl->getPropertyDecl());
Steve Naroff423cb562007-10-30 13:30:57 +0000536 RewriteMethods(ClassDecl->getNumInstanceMethods(),
537 ClassDecl->getInstanceMethods());
538 RewriteMethods(ClassDecl->getNumClassMethods(),
539 ClassDecl->getClassMethods());
Steve Naroffbef11852007-10-26 20:53:56 +0000540
Steve Naroff2feac5e2007-10-30 03:43:13 +0000541 // Lastly, comment out the @end.
542 Rewrite.ReplaceText(ClassDecl->getAtEndLoc(), 0, "// ", 3);
Steve Naroffbef11852007-10-26 20:53:56 +0000543}
544
Chris Lattnerf04da132007-10-24 17:06:59 +0000545//===----------------------------------------------------------------------===//
546// Function Body / Expression rewriting
547//===----------------------------------------------------------------------===//
548
Steve Narofff3473a72007-11-09 15:20:18 +0000549Stmt *RewriteTest::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
Chris Lattner311ff022007-10-16 22:36:42 +0000550 // Otherwise, just rewrite all children.
551 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
552 CI != E; ++CI)
Steve Naroff75730982007-11-07 04:08:17 +0000553 if (*CI) {
Steve Narofff3473a72007-11-09 15:20:18 +0000554 Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(*CI);
Steve Naroff75730982007-11-07 04:08:17 +0000555 if (newStmt)
556 *CI = newStmt;
557 }
Steve Naroffebf2b562007-10-23 23:50:29 +0000558
559 // Handle specific things.
560 if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
561 return RewriteAtEncode(AtEncode);
Steve Naroffb42f8412007-11-05 14:50:49 +0000562
563 if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S))
564 return RewriteAtSelector(AtSelector);
Steve Naroffbeaf2992007-11-03 11:27:19 +0000565
566 if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S))
567 return RewriteObjCStringLiteral(AtString);
Steve Naroffebf2b562007-10-23 23:50:29 +0000568
Steve Naroff934f2762007-10-24 22:48:43 +0000569 if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {
570 // Before we rewrite it, put the original message expression in a comment.
571 SourceLocation startLoc = MessExpr->getLocStart();
572 SourceLocation endLoc = MessExpr->getLocEnd();
573
574 const char *startBuf = SM->getCharacterData(startLoc);
575 const char *endBuf = SM->getCharacterData(endLoc);
576
577 std::string messString;
578 messString += "// ";
579 messString.append(startBuf, endBuf-startBuf+1);
580 messString += "\n";
Steve Naroffbef11852007-10-26 20:53:56 +0000581
Steve Naroff934f2762007-10-24 22:48:43 +0000582 // FIXME: Missing definition of Rewrite.InsertText(clang::SourceLocation, char const*, unsigned int).
583 // Rewrite.InsertText(startLoc, messString.c_str(), messString.size());
584 // Tried this, but it didn't work either...
Steve Naroff752d6ef2007-10-30 16:42:30 +0000585 // Rewrite.ReplaceText(startLoc, 0, messString.c_str(), messString.size());
Steve Naroffebf2b562007-10-23 23:50:29 +0000586 return RewriteMessageExpr(MessExpr);
Steve Naroff934f2762007-10-24 22:48:43 +0000587 }
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000588
589 if (ObjcAtTryStmt *StmtTry = dyn_cast<ObjcAtTryStmt>(S))
590 return RewriteObjcTryStmt(StmtTry);
Steve Naroff2bd03922007-11-07 15:32:26 +0000591
592 if (ObjcAtThrowStmt *StmtThrow = dyn_cast<ObjcAtThrowStmt>(S))
593 return RewriteObjcThrowStmt(StmtThrow);
594
Chris Lattnere64b7772007-10-24 16:57:36 +0000595 // Return this stmt unmodified.
596 return S;
Chris Lattner311ff022007-10-16 22:36:42 +0000597}
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +0000598
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000599Stmt *RewriteTest::RewriteObjcTryStmt(ObjcAtTryStmt *S) {
Steve Naroff75730982007-11-07 04:08:17 +0000600 // Get the start location and compute the semi location.
601 SourceLocation startLoc = S->getLocStart();
602 const char *startBuf = SM->getCharacterData(startLoc);
603
604 assert((*startBuf == '@') && "bogus @try location");
605
606 std::string buf;
607 // declare a new scope with two variables, _stack and _rethrow.
608 buf = "/* @try scope begin */ { struct _objc_exception_data {\n";
609 buf += "int buf[18/*32-bit i386*/];\n";
610 buf += "char *pointers[4];} _stack;\n";
611 buf += "id volatile _rethrow = 0;\n";
612 buf += "objc_exception_try_enter(&_stack);\n";
Steve Naroff21867b12007-11-07 18:43:40 +0000613 buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";
Steve Naroff75730982007-11-07 04:08:17 +0000614
615 Rewrite.ReplaceText(startLoc, 4, buf.c_str(), buf.size());
616
617 startLoc = S->getTryBody()->getLocEnd();
618 startBuf = SM->getCharacterData(startLoc);
619
620 assert((*startBuf == '}') && "bogus @try block");
621
622 SourceLocation lastCurlyLoc = startLoc;
623
624 startLoc = startLoc.getFileLocWithOffset(1);
625 buf = " /* @catch begin */ else {\n";
626 buf += " id _caught = objc_exception_extract(&_stack);\n";
627 buf += " objc_exception_try_enter (&_stack);\n";
Steve Naroff21867b12007-11-07 18:43:40 +0000628 buf += " if (_setjmp(_stack.buf))\n";
Steve Naroff75730982007-11-07 04:08:17 +0000629 buf += " _rethrow = objc_exception_extract(&_stack);\n";
630 buf += " else { /* @catch continue */";
631
Chris Lattner28d1fe82007-11-08 04:41:51 +0000632 Rewrite.InsertText(startLoc, buf.c_str(), buf.size());
Steve Naroff75730982007-11-07 04:08:17 +0000633
634 bool sawIdTypedCatch = false;
635 Stmt *lastCatchBody = 0;
636 ObjcAtCatchStmt *catchList = S->getCatchStmts();
637 while (catchList) {
638 Stmt *catchStmt = catchList->getCatchParamStmt();
639
640 if (catchList == S->getCatchStmts())
641 buf = "if ("; // we are generating code for the first catch clause
642 else
643 buf = "else if (";
644 startLoc = catchList->getLocStart();
645 startBuf = SM->getCharacterData(startLoc);
646
647 assert((*startBuf == '@') && "bogus @catch location");
648
649 const char *lParenLoc = strchr(startBuf, '(');
650
651 if (DeclStmt *declStmt = dyn_cast<DeclStmt>(catchStmt)) {
652 QualType t = dyn_cast<ValueDecl>(declStmt->getDecl())->getType();
653 if (t == Context->getObjcIdType()) {
654 buf += "1) { ";
655 Rewrite.ReplaceText(startLoc, lParenLoc-startBuf+1,
656 buf.c_str(), buf.size());
657 sawIdTypedCatch = true;
658 } else if (const PointerType *pType = t->getAsPointerType()) {
659 ObjcInterfaceType *cls; // Should be a pointer to a class.
660
661 cls = dyn_cast<ObjcInterfaceType>(pType->getPointeeType().getTypePtr());
662 if (cls) {
Steve Naroff21867b12007-11-07 18:43:40 +0000663 buf += "objc_exception_match((struct objc_class *)objc_getClass(\"";
Steve Naroff75730982007-11-07 04:08:17 +0000664 buf += cls->getDecl()->getName();
Steve Naroff21867b12007-11-07 18:43:40 +0000665 buf += "\"), (struct objc_object *)_caught)) { ";
Steve Naroff75730982007-11-07 04:08:17 +0000666 Rewrite.ReplaceText(startLoc, lParenLoc-startBuf+1,
667 buf.c_str(), buf.size());
668 }
669 }
670 // Now rewrite the body...
671 lastCatchBody = catchList->getCatchBody();
672 SourceLocation rParenLoc = catchList->getRParenLoc();
673 SourceLocation bodyLoc = lastCatchBody->getLocStart();
674 const char *bodyBuf = SM->getCharacterData(bodyLoc);
675 const char *rParenBuf = SM->getCharacterData(rParenLoc);
676 assert((*rParenBuf == ')') && "bogus @catch paren location");
677 assert((*bodyBuf == '{') && "bogus @catch body location");
678
679 buf = " = _caught;";
680 // Here we replace ") {" with "= _caught;" (which initializes and
681 // declares the @catch parameter).
682 Rewrite.ReplaceText(rParenLoc, bodyBuf-rParenBuf+1,
683 buf.c_str(), buf.size());
Steve Naroff2bd03922007-11-07 15:32:26 +0000684 } else if (!isa<NullStmt>(catchStmt)) {
Steve Naroff75730982007-11-07 04:08:17 +0000685 assert(false && "@catch rewrite bug");
Steve Naroff2bd03922007-11-07 15:32:26 +0000686 }
Steve Naroff75730982007-11-07 04:08:17 +0000687 catchList = catchList->getNextCatchStmt();
688 }
689 // Complete the catch list...
690 if (lastCatchBody) {
691 SourceLocation bodyLoc = lastCatchBody->getLocEnd();
692 const char *bodyBuf = SM->getCharacterData(bodyLoc);
693 assert((*bodyBuf == '}') && "bogus @catch body location");
694 bodyLoc = bodyLoc.getFileLocWithOffset(1);
695 buf = " } } /* @catch end */\n";
696
Chris Lattner28d1fe82007-11-08 04:41:51 +0000697 Rewrite.InsertText(bodyLoc, buf.c_str(), buf.size());
Steve Naroff75730982007-11-07 04:08:17 +0000698
699 // Set lastCurlyLoc
700 lastCurlyLoc = lastCatchBody->getLocEnd();
701 }
702 if (ObjcAtFinallyStmt *finalStmt = S->getFinallyStmt()) {
703 startLoc = finalStmt->getLocStart();
704 startBuf = SM->getCharacterData(startLoc);
705 assert((*startBuf == '@') && "bogus @finally start");
706
707 buf = "/* @finally */";
708 Rewrite.ReplaceText(startLoc, 8, buf.c_str(), buf.size());
709
710 Stmt *body = finalStmt->getFinallyBody();
711 SourceLocation startLoc = body->getLocStart();
712 SourceLocation endLoc = body->getLocEnd();
713 const char *startBuf = SM->getCharacterData(startLoc);
714 const char *endBuf = SM->getCharacterData(endLoc);
715 assert((*startBuf == '{') && "bogus @finally body location");
716 assert((*endBuf == '}') && "bogus @finally body location");
717
718 startLoc = startLoc.getFileLocWithOffset(1);
719 buf = " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
Chris Lattner28d1fe82007-11-08 04:41:51 +0000720 Rewrite.InsertText(startLoc, buf.c_str(), buf.size());
Steve Naroff75730982007-11-07 04:08:17 +0000721 endLoc = endLoc.getFileLocWithOffset(-1);
722 buf = " if (_rethrow) objc_exception_throw(_rethrow);\n";
Chris Lattner28d1fe82007-11-08 04:41:51 +0000723 Rewrite.InsertText(endLoc, buf.c_str(), buf.size());
Steve Naroff75730982007-11-07 04:08:17 +0000724
725 // Set lastCurlyLoc
726 lastCurlyLoc = body->getLocEnd();
727 }
728 // Now emit the final closing curly brace...
729 lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1);
730 buf = " } /* @try scope end */\n";
Chris Lattner28d1fe82007-11-08 04:41:51 +0000731 Rewrite.InsertText(lastCurlyLoc, buf.c_str(), buf.size());
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000732 return 0;
733}
734
735Stmt *RewriteTest::RewriteObjcCatchStmt(ObjcAtCatchStmt *S) {
736 return 0;
737}
738
739Stmt *RewriteTest::RewriteObjcFinallyStmt(ObjcAtFinallyStmt *S) {
740 return 0;
741}
742
Steve Naroff2bd03922007-11-07 15:32:26 +0000743// This can't be done with Rewrite.ReplaceStmt(S, ThrowExpr), since
744// the throw expression is typically a message expression that's already
745// been rewritten! (which implies the SourceLocation's are invalid).
746Stmt *RewriteTest::RewriteObjcThrowStmt(ObjcAtThrowStmt *S) {
747 // Get the start location and compute the semi location.
748 SourceLocation startLoc = S->getLocStart();
749 const char *startBuf = SM->getCharacterData(startLoc);
750
751 assert((*startBuf == '@') && "bogus @throw location");
752
753 std::string buf;
754 /* void objc_exception_throw(id) __attribute__((noreturn)); */
755 buf = "objc_exception_throw(";
756 Rewrite.ReplaceText(startLoc, 6, buf.c_str(), buf.size());
757 const char *semiBuf = strchr(startBuf, ';');
758 assert((*semiBuf == ';') && "@throw: can't find ';'");
759 SourceLocation semiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf);
760 buf = ");";
761 Rewrite.ReplaceText(semiLoc, 1, buf.c_str(), buf.size());
762 return 0;
763}
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000764
Chris Lattnere64b7772007-10-24 16:57:36 +0000765Stmt *RewriteTest::RewriteAtEncode(ObjCEncodeExpr *Exp) {
Chris Lattner01c57482007-10-17 22:35:30 +0000766 // Create a new string expression.
767 QualType StrType = Context->getPointerType(Context->CharTy);
Anders Carlsson85f9bce2007-10-29 05:01:08 +0000768 std::string StrEncoding;
769 Context->getObjcEncodingForType(Exp->getEncodedType(), StrEncoding);
770 Expr *Replacement = new StringLiteral(StrEncoding.c_str(),
771 StrEncoding.length(), false, StrType,
Chris Lattner01c57482007-10-17 22:35:30 +0000772 SourceLocation(), SourceLocation());
773 Rewrite.ReplaceStmt(Exp, Replacement);
Chris Lattnere64b7772007-10-24 16:57:36 +0000774 delete Exp;
775 return Replacement;
Chris Lattner311ff022007-10-16 22:36:42 +0000776}
777
Steve Naroffb42f8412007-11-05 14:50:49 +0000778Stmt *RewriteTest::RewriteAtSelector(ObjCSelectorExpr *Exp) {
779 assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");
780 // Create a call to sel_registerName("selName").
781 llvm::SmallVector<Expr*, 8> SelExprs;
782 QualType argType = Context->getPointerType(Context->CharTy);
783 SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
784 Exp->getSelector().getName().size(),
785 false, argType, SourceLocation(),
786 SourceLocation()));
787 CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
788 &SelExprs[0], SelExprs.size());
789 Rewrite.ReplaceStmt(Exp, SelExp);
790 delete Exp;
791 return SelExp;
792}
793
Steve Naroff934f2762007-10-24 22:48:43 +0000794CallExpr *RewriteTest::SynthesizeCallToFunctionDecl(
795 FunctionDecl *FD, Expr **args, unsigned nargs) {
Steve Naroffebf2b562007-10-23 23:50:29 +0000796 // Get the type, we will need to reference it in a couple spots.
Steve Naroff934f2762007-10-24 22:48:43 +0000797 QualType msgSendType = FD->getType();
Steve Naroffebf2b562007-10-23 23:50:29 +0000798
799 // Create a reference to the objc_msgSend() declaration.
Steve Naroff934f2762007-10-24 22:48:43 +0000800 DeclRefExpr *DRE = new DeclRefExpr(FD, msgSendType, SourceLocation());
Steve Naroffebf2b562007-10-23 23:50:29 +0000801
802 // Now, we cast the reference to a pointer to the objc_msgSend type.
Chris Lattnerf04da132007-10-24 17:06:59 +0000803 QualType pToFunc = Context->getPointerType(msgSendType);
Steve Naroffebf2b562007-10-23 23:50:29 +0000804 ImplicitCastExpr *ICE = new ImplicitCastExpr(pToFunc, DRE);
805
806 const FunctionType *FT = msgSendType->getAsFunctionType();
Chris Lattnere64b7772007-10-24 16:57:36 +0000807
Steve Naroff934f2762007-10-24 22:48:43 +0000808 return new CallExpr(ICE, args, nargs, FT->getResultType(), SourceLocation());
809}
810
Steve Naroffd5255f52007-11-01 13:24:47 +0000811static bool scanForProtocolRefs(const char *startBuf, const char *endBuf,
812 const char *&startRef, const char *&endRef) {
813 while (startBuf < endBuf) {
814 if (*startBuf == '<')
815 startRef = startBuf; // mark the start.
816 if (*startBuf == '>') {
Steve Naroff32174822007-11-09 12:50:28 +0000817 if (startRef && *startRef == '<') {
818 endRef = startBuf; // mark the end.
819 return true;
820 }
821 return false;
Steve Naroffd5255f52007-11-01 13:24:47 +0000822 }
823 startBuf++;
824 }
825 return false;
826}
827
828bool RewriteTest::needToScanForQualifiers(QualType T) {
829 // FIXME: we don't currently represent "id <Protocol>" in the type system.
830 if (T == Context->getObjcIdType())
831 return true;
832
833 if (const PointerType *pType = T->getAsPointerType()) {
Steve Naroff9165ad32007-10-31 04:38:33 +0000834 Type *pointeeType = pType->getPointeeType().getTypePtr();
835 if (isa<ObjcQualifiedInterfaceType>(pointeeType))
836 return true; // we have "Class <Protocol> *".
837 }
Steve Naroffd5255f52007-11-01 13:24:47 +0000838 return false;
839}
840
841void RewriteTest::RewriteObjcQualifiedInterfaceTypes(
842 const FunctionTypeProto *proto, FunctionDecl *FD) {
843
844 if (needToScanForQualifiers(proto->getResultType())) {
845 // Since types are unique, we need to scan the buffer.
846 SourceLocation Loc = FD->getLocation();
847
848 const char *endBuf = SM->getCharacterData(Loc);
849 const char *startBuf = endBuf;
850 while (*startBuf != ';')
851 startBuf--; // scan backward (from the decl location) for return type.
852 const char *startRef = 0, *endRef = 0;
853 if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
854 // Get the locations of the startRef, endRef.
855 SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-endBuf);
856 SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-endBuf+1);
857 // Comment out the protocol references.
Chris Lattner28d1fe82007-11-08 04:41:51 +0000858 Rewrite.InsertText(LessLoc, "/*", 2);
859 Rewrite.InsertText(GreaterLoc, "*/", 2);
Steve Naroff9165ad32007-10-31 04:38:33 +0000860 }
861 }
Steve Naroffd5255f52007-11-01 13:24:47 +0000862 // Now check arguments.
863 for (unsigned i = 0; i < proto->getNumArgs(); i++) {
864 if (needToScanForQualifiers(proto->getArgType(i))) {
865 // Since types are unique, we need to scan the buffer.
866 SourceLocation Loc = FD->getLocation();
867
868 const char *startBuf = SM->getCharacterData(Loc);
869 const char *endBuf = startBuf;
870 while (*endBuf != ';')
871 endBuf++; // scan forward (from the decl location) for argument types.
872 const char *startRef = 0, *endRef = 0;
873 if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
874 // Get the locations of the startRef, endRef.
875 SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-startBuf);
876 SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-startBuf+1);
877 // Comment out the protocol references.
Chris Lattner28d1fe82007-11-08 04:41:51 +0000878 Rewrite.InsertText(LessLoc, "/*", 2);
879 Rewrite.InsertText(GreaterLoc, "*/", 2);
Steve Naroffd5255f52007-11-01 13:24:47 +0000880 }
881 }
882 }
Steve Naroff9165ad32007-10-31 04:38:33 +0000883}
884
Steve Naroff09b266e2007-10-30 23:14:51 +0000885void RewriteTest::RewriteFunctionDecl(FunctionDecl *FD) {
886 // declared in <objc/objc.h>
Steve Naroffbeaf2992007-11-03 11:27:19 +0000887 if (strcmp(FD->getName(), "sel_registerName") == 0) {
Steve Naroff09b266e2007-10-30 23:14:51 +0000888 SelGetUidFunctionDecl = FD;
Steve Naroff9165ad32007-10-31 04:38:33 +0000889 return;
890 }
891 // Check for ObjC 'id' and class types that have been adorned with protocol
892 // information (id<p>, C<p>*). The protocol references need to be rewritten!
893 const FunctionType *funcType = FD->getType()->getAsFunctionType();
894 assert(funcType && "missing function type");
Steve Naroffd5255f52007-11-01 13:24:47 +0000895 if (const FunctionTypeProto *proto = dyn_cast<FunctionTypeProto>(funcType))
896 RewriteObjcQualifiedInterfaceTypes(proto, FD);
Steve Naroff09b266e2007-10-30 23:14:51 +0000897}
898
899// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
900void RewriteTest::SynthMsgSendFunctionDecl() {
901 IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend");
902 llvm::SmallVector<QualType, 16> ArgTys;
903 QualType argT = Context->getObjcIdType();
904 assert(!argT.isNull() && "Can't find 'id' type");
905 ArgTys.push_back(argT);
906 argT = Context->getObjcSelType();
907 assert(!argT.isNull() && "Can't find 'SEL' type");
908 ArgTys.push_back(argT);
909 QualType msgSendType = Context->getFunctionType(Context->getObjcIdType(),
910 &ArgTys[0], ArgTys.size(),
911 true /*isVariadic*/);
912 MsgSendFunctionDecl = new FunctionDecl(SourceLocation(),
913 msgSendIdent, msgSendType,
914 FunctionDecl::Extern, false, 0);
915}
916
917// SynthGetClassFunctionDecl - id objc_getClass(const char *name);
918void RewriteTest::SynthGetClassFunctionDecl() {
919 IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass");
920 llvm::SmallVector<QualType, 16> ArgTys;
921 ArgTys.push_back(Context->getPointerType(
922 Context->CharTy.getQualifiedType(QualType::Const)));
923 QualType getClassType = Context->getFunctionType(Context->getObjcIdType(),
924 &ArgTys[0], ArgTys.size(),
925 false /*isVariadic*/);
926 GetClassFunctionDecl = new FunctionDecl(SourceLocation(),
927 getClassIdent, getClassType,
928 FunctionDecl::Extern, false, 0);
929}
930
Steve Naroff96984642007-11-08 14:30:50 +0000931// SynthCFStringFunctionDecl - id __builtin___CFStringMakeConstantString(const char *name);
932void RewriteTest::SynthCFStringFunctionDecl() {
933 IdentifierInfo *getClassIdent = &Context->Idents.get("__builtin___CFStringMakeConstantString");
934 llvm::SmallVector<QualType, 16> ArgTys;
935 ArgTys.push_back(Context->getPointerType(
936 Context->CharTy.getQualifiedType(QualType::Const)));
937 QualType getClassType = Context->getFunctionType(Context->getObjcIdType(),
938 &ArgTys[0], ArgTys.size(),
939 false /*isVariadic*/);
940 CFStringFunctionDecl = new FunctionDecl(SourceLocation(),
941 getClassIdent, getClassType,
942 FunctionDecl::Extern, false, 0);
943}
944
Steve Naroffbeaf2992007-11-03 11:27:19 +0000945Stmt *RewriteTest::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
Steve Naroff96984642007-11-08 14:30:50 +0000946#if 1
947 // This rewrite is specific to GCC, which has builtin support for CFString.
948 if (!CFStringFunctionDecl)
949 SynthCFStringFunctionDecl();
950 // Create a call to __builtin___CFStringMakeConstantString("cstr").
951 llvm::SmallVector<Expr*, 8> StrExpr;
952 StrExpr.push_back(Exp->getString());
953 CallExpr *call = SynthesizeCallToFunctionDecl(CFStringFunctionDecl,
954 &StrExpr[0], StrExpr.size());
955 // cast to NSConstantString *
956 CastExpr *cast = new CastExpr(Exp->getType(), call, SourceLocation());
957 Rewrite.ReplaceStmt(Exp, cast);
958 delete Exp;
959 return cast;
960#else
Steve Naroffbeaf2992007-11-03 11:27:19 +0000961 assert(ConstantStringClassReference && "Can't find constant string reference");
962 llvm::SmallVector<Expr*, 4> InitExprs;
963
964 // Synthesize "(Class)&_NSConstantStringClassReference"
965 DeclRefExpr *ClsRef = new DeclRefExpr(ConstantStringClassReference,
966 ConstantStringClassReference->getType(),
967 SourceLocation());
968 QualType expType = Context->getPointerType(ClsRef->getType());
969 UnaryOperator *Unop = new UnaryOperator(ClsRef, UnaryOperator::AddrOf,
970 expType, SourceLocation());
971 CastExpr *cast = new CastExpr(Context->getObjcClassType(), Unop,
972 SourceLocation());
973 InitExprs.push_back(cast); // set the 'isa'.
974 InitExprs.push_back(Exp->getString()); // set "char *bytes".
975 unsigned IntSize = static_cast<unsigned>(
976 Context->getTypeSize(Context->IntTy, Exp->getLocStart()));
977 llvm::APInt IntVal(IntSize, Exp->getString()->getByteLength());
978 IntegerLiteral *len = new IntegerLiteral(IntVal, Context->IntTy,
979 Exp->getLocStart());
980 InitExprs.push_back(len); // set "int numBytes".
981
982 // struct NSConstantString
983 QualType CFConstantStrType = Context->getCFConstantStringType();
984 // (struct NSConstantString) { <exprs from above> }
985 InitListExpr *ILE = new InitListExpr(SourceLocation(),
986 &InitExprs[0], InitExprs.size(),
987 SourceLocation());
988 CompoundLiteralExpr *StrRep = new CompoundLiteralExpr(CFConstantStrType, ILE);
989 // struct NSConstantString *
990 expType = Context->getPointerType(StrRep->getType());
991 Unop = new UnaryOperator(StrRep, UnaryOperator::AddrOf, expType,
992 SourceLocation());
Steve Naroff352336b2007-11-05 14:36:37 +0000993 // cast to NSConstantString *
994 cast = new CastExpr(Exp->getType(), Unop, SourceLocation());
Steve Naroffbeaf2992007-11-03 11:27:19 +0000995 Rewrite.ReplaceStmt(Exp, cast);
996 delete Exp;
Steve Naroff352336b2007-11-05 14:36:37 +0000997 return cast;
Steve Naroff96984642007-11-08 14:30:50 +0000998#endif
Steve Naroffbeaf2992007-11-03 11:27:19 +0000999}
1000
Steve Naroff934f2762007-10-24 22:48:43 +00001001Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) {
Steve Naroffbeaf2992007-11-03 11:27:19 +00001002 assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");
Steve Naroff09b266e2007-10-30 23:14:51 +00001003 if (!MsgSendFunctionDecl)
1004 SynthMsgSendFunctionDecl();
1005 if (!GetClassFunctionDecl)
1006 SynthGetClassFunctionDecl();
Steve Naroff934f2762007-10-24 22:48:43 +00001007
1008 // Synthesize a call to objc_msgSend().
1009 llvm::SmallVector<Expr*, 8> MsgExprs;
1010 IdentifierInfo *clsName = Exp->getClassName();
1011
1012 // Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend().
1013 if (clsName) { // class message.
1014 llvm::SmallVector<Expr*, 8> ClsExprs;
1015 QualType argType = Context->getPointerType(Context->CharTy);
1016 ClsExprs.push_back(new StringLiteral(clsName->getName(),
1017 clsName->getLength(),
1018 false, argType, SourceLocation(),
1019 SourceLocation()));
1020 CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
1021 &ClsExprs[0], ClsExprs.size());
1022 MsgExprs.push_back(Cls);
1023 } else // instance message.
1024 MsgExprs.push_back(Exp->getReceiver());
1025
Steve Naroffbeaf2992007-11-03 11:27:19 +00001026 // Create a call to sel_registerName("selName"), it will be the 2nd argument.
Steve Naroff934f2762007-10-24 22:48:43 +00001027 llvm::SmallVector<Expr*, 8> SelExprs;
1028 QualType argType = Context->getPointerType(Context->CharTy);
1029 SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
1030 Exp->getSelector().getName().size(),
1031 false, argType, SourceLocation(),
1032 SourceLocation()));
1033 CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
1034 &SelExprs[0], SelExprs.size());
1035 MsgExprs.push_back(SelExp);
1036
1037 // Now push any user supplied arguments.
1038 for (unsigned i = 0; i < Exp->getNumArgs(); i++) {
1039 MsgExprs.push_back(Exp->getArg(i));
1040 // We've transferred the ownership to MsgExprs. Null out the argument in
1041 // the original expression, since we will delete it below.
1042 Exp->setArg(i, 0);
1043 }
Steve Naroffab972d32007-11-04 22:37:50 +00001044 // Generate the funky cast.
1045 CastExpr *cast;
1046 llvm::SmallVector<QualType, 8> ArgTypes;
1047 QualType returnType;
1048
1049 // Push 'id' and 'SEL', the 2 implicit arguments.
1050 ArgTypes.push_back(Context->getObjcIdType());
1051 ArgTypes.push_back(Context->getObjcSelType());
1052 if (ObjcMethodDecl *mDecl = Exp->getMethodDecl()) {
1053 // Push any user argument types.
Steve Naroff352336b2007-11-05 14:36:37 +00001054 for (int i = 0; i < mDecl->getNumParams(); i++) {
1055 QualType t = mDecl->getParamDecl(i)->getType();
1056 if (t == Context->getObjcClassType())
1057 t = Context->getObjcIdType(); // Convert "Class"->"id"
1058 ArgTypes.push_back(t);
1059 }
Steve Naroffab972d32007-11-04 22:37:50 +00001060 returnType = mDecl->getResultType();
1061 } else {
1062 returnType = Context->getObjcIdType();
1063 }
1064 // Get the type, we will need to reference it in a couple spots.
1065 QualType msgSendType = MsgSendFunctionDecl->getType();
1066
1067 // Create a reference to the objc_msgSend() declaration.
1068 DeclRefExpr *DRE = new DeclRefExpr(MsgSendFunctionDecl, msgSendType, SourceLocation());
1069
1070 // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid).
1071 // If we don't do this cast, we get the following bizarre warning/note:
1072 // xx.m:13: warning: function called through a non-compatible type
1073 // xx.m:13: note: if this code is reached, the program will abort
1074 cast = new CastExpr(Context->getPointerType(Context->VoidTy), DRE,
1075 SourceLocation());
1076
1077 // Now do the "normal" pointer to function cast.
1078 QualType castType = Context->getFunctionType(returnType,
1079 &ArgTypes[0], ArgTypes.size(),
1080 false/*FIXME:variadic*/);
1081 castType = Context->getPointerType(castType);
1082 cast = new CastExpr(castType, cast, SourceLocation());
1083
1084 // Don't forget the parens to enforce the proper binding.
1085 ParenExpr *PE = new ParenExpr(SourceLocation(), SourceLocation(), cast);
1086
1087 const FunctionType *FT = msgSendType->getAsFunctionType();
1088 CallExpr *CE = new CallExpr(PE, &MsgExprs[0], MsgExprs.size(),
1089 FT->getResultType(), SourceLocation());
Steve Naroff934f2762007-10-24 22:48:43 +00001090 // Now do the actual rewrite.
Steve Naroffab972d32007-11-04 22:37:50 +00001091 Rewrite.ReplaceStmt(Exp, CE);
Steve Naroff934f2762007-10-24 22:48:43 +00001092
Chris Lattnere64b7772007-10-24 16:57:36 +00001093 delete Exp;
Steve Naroffab972d32007-11-04 22:37:50 +00001094 return CE;
Steve Naroffebf2b562007-10-23 23:50:29 +00001095}
1096
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001097/// SynthesizeObjcInternalStruct - Rewrite one internal struct corresponding to
1098/// an objective-c class with ivars.
1099void RewriteTest::SynthesizeObjcInternalStruct(ObjcInterfaceDecl *CDecl,
1100 std::string &Result) {
1101 assert(CDecl && "Class missing in SynthesizeObjcInternalStruct");
1102 assert(CDecl->getName() && "Name missing in SynthesizeObjcInternalStruct");
Fariborz Jahanian212b7682007-10-31 23:08:24 +00001103 // Do not synthesize more than once.
1104 if (ObjcSynthesizedStructs.count(CDecl))
1105 return;
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001106 ObjcInterfaceDecl *RCDecl = CDecl->getSuperClass();
1107 if (RCDecl && !ObjcSynthesizedStructs.count(RCDecl)) {
1108 // Do it for the root
1109 SynthesizeObjcInternalStruct(RCDecl, Result);
1110 }
1111
Steve Naroff03300712007-11-12 13:56:41 +00001112 int NumIvars = CDecl->getNumInstanceVariables();
Fariborz Jahanianaff56d02007-10-31 22:57:04 +00001113 // If no ivars and no root or if its root, directly or indirectly,
Fariborz Jahanianf1de0ca2007-10-31 23:53:01 +00001114 // have no ivars (thus not synthesized) then no need to synthesize this class.
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001115 if (NumIvars <= 0 && (!RCDecl || !ObjcSynthesizedStructs.count(RCDecl)))
1116 return;
1117
Steve Naroff04960052007-11-01 17:12:31 +00001118 Result += "\nstruct ";
1119 Result += CDecl->getName();
1120 if (RCDecl && ObjcSynthesizedStructs.count(RCDecl)) {
1121 Result += " {\n struct ";
1122 Result += RCDecl->getName();
1123 Result += " _";
1124 Result += RCDecl->getName();
1125 Result += ";\n";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001126 }
Fariborz Jahanianfdc08a02007-10-31 17:29:28 +00001127 else
1128 Result += " {";
Steve Naroff8749be52007-10-31 22:11:35 +00001129
Fariborz Jahanianfdc08a02007-10-31 17:29:28 +00001130 if (NumIvars > 0) {
1131 SourceLocation LocStart = CDecl->getLocStart();
1132 SourceLocation LocEnd = CDecl->getLocEnd();
1133
1134 const char *startBuf = SM->getCharacterData(LocStart);
1135 const char *endBuf = SM->getCharacterData(LocEnd);
1136 startBuf = strchr(startBuf, '{');
1137 assert((startBuf && endBuf)
1138 && "SynthesizeObjcInternalStruct - malformed @interface");
1139 startBuf++; // past '{'
1140 while (startBuf < endBuf) {
1141 if (*startBuf == '@') {
1142 startBuf = strchr(startBuf, 'p');
1143 // FIXME: presence of @public, etc. inside comment results in
1144 // this transformation as well, which is still correct c-code.
1145 if (!strncmp(startBuf, "public", strlen("public"))) {
1146 startBuf += strlen("public");
1147 Result += "/* @public */";
1148 }
1149 else if (!strncmp(startBuf, "private", strlen("private"))) {
1150 startBuf += strlen("private");
1151 Result += "/* @private */";
1152 }
1153 else if (!strncmp(startBuf, "protected", strlen("protected"))) {
1154 startBuf += strlen("protected");
1155 Result += "/* @protected */";
1156 }
1157 }
1158 Result += *startBuf++;
1159 }
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001160 }
Fariborz Jahanianfdc08a02007-10-31 17:29:28 +00001161
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001162 Result += "};\n";
1163 // Mark this struct as having been generated.
1164 if (!ObjcSynthesizedStructs.insert(CDecl))
Fariborz Jahanianaff56d02007-10-31 22:57:04 +00001165 assert(false && "struct already synthesize- SynthesizeObjcInternalStruct");
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001166}
1167
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001168// RewriteObjcMethodsMetaData - Rewrite methods metadata for instance or
1169/// class methods.
Steve Naroff0416fb92007-11-11 17:19:15 +00001170void RewriteTest::RewriteObjcMethodsMetaData(ObjcMethodDecl *const*Methods,
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001171 int NumMethods,
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +00001172 bool IsInstanceMethod,
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001173 const char *prefix,
Chris Lattner158ecb92007-10-25 17:07:24 +00001174 const char *ClassName,
1175 std::string &Result) {
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001176 static bool objc_impl_method = false;
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001177 if (NumMethods > 0 && !objc_impl_method) {
1178 /* struct _objc_method {
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001179 SEL _cmd;
1180 char *method_types;
1181 void *_imp;
1182 }
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001183 */
Chris Lattner158ecb92007-10-25 17:07:24 +00001184 Result += "\nstruct _objc_method {\n";
1185 Result += "\tSEL _cmd;\n";
1186 Result += "\tchar *method_types;\n";
1187 Result += "\tvoid *_imp;\n";
1188 Result += "};\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001189
1190 /* struct _objc_method_list {
1191 struct _objc_method_list *next_method;
1192 int method_count;
1193 struct _objc_method method_list[];
1194 }
1195 */
1196 Result += "\nstruct _objc_method_list {\n";
1197 Result += "\tstruct _objc_method_list *next_method;\n";
1198 Result += "\tint method_count;\n";
1199 Result += "\tstruct _objc_method method_list[];\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001200 objc_impl_method = true;
Fariborz Jahanian776d6ff2007-10-19 00:36:46 +00001201 }
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001202 // Build _objc_method_list for class's methods if needed
1203 if (NumMethods > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001204 Result += "\nstatic struct _objc_method_list _OBJC_";
Chris Lattner158ecb92007-10-25 17:07:24 +00001205 Result += prefix;
1206 Result += IsInstanceMethod ? "INSTANCE" : "CLASS";
1207 Result += "_METHODS_";
1208 Result += ClassName;
1209 Result += " __attribute__ ((section (\"__OBJC, __";
1210 Result += IsInstanceMethod ? "inst" : "cls";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001211 Result += "_meth\")))= ";
1212 Result += "{\n\t0, " + utostr(NumMethods) + "\n";
1213
1214 Result += "\t,{{(SEL)\"";
1215 Result += Methods[0]->getSelector().getName().c_str();
Fariborz Jahanian33e1d642007-10-29 22:57:28 +00001216 std::string MethodTypeString;
1217 Context->getObjcEncodingForMethodDecl(Methods[0], MethodTypeString);
1218 Result += "\", \"";
1219 Result += MethodTypeString;
Fariborz Jahanianb7908b52007-11-13 21:02:00 +00001220 Result += "\", ";
1221 Result += MethodInternalNames[Methods[0]];
1222 Result += "}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001223 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001224 Result += "\t ,{(SEL)\"";
1225 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanian33e1d642007-10-29 22:57:28 +00001226 std::string MethodTypeString;
1227 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
1228 Result += "\", \"";
1229 Result += MethodTypeString;
Fariborz Jahanianb7908b52007-11-13 21:02:00 +00001230 Result += "\", ";
1231 Result += MethodInternalNames[Methods[i]];
1232 Result += "}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001233 }
1234 Result += "\t }\n};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001235 }
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001236}
1237
1238/// RewriteObjcProtocolsMetaData - Rewrite protocols meta-data.
1239void RewriteTest::RewriteObjcProtocolsMetaData(ObjcProtocolDecl **Protocols,
1240 int NumProtocols,
1241 const char *prefix,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001242 const char *ClassName,
1243 std::string &Result) {
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001244 static bool objc_protocol_methods = false;
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001245 if (NumProtocols > 0) {
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001246 for (int i = 0; i < NumProtocols; i++) {
1247 ObjcProtocolDecl *PDecl = Protocols[i];
1248 // Output struct protocol_methods holder of method selector and type.
1249 if (!objc_protocol_methods &&
1250 (PDecl->getNumInstanceMethods() > 0
1251 || PDecl->getNumClassMethods() > 0)) {
1252 /* struct protocol_methods {
1253 SEL _cmd;
1254 char *method_types;
1255 }
1256 */
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001257 Result += "\nstruct protocol_methods {\n";
1258 Result += "\tSEL _cmd;\n";
1259 Result += "\tchar *method_types;\n";
1260 Result += "};\n";
1261
1262 /* struct _objc_protocol_method_list {
1263 int protocol_method_count;
1264 struct protocol_methods protocols[];
1265 }
1266 */
1267 Result += "\nstruct _objc_protocol_method_list {\n";
1268 Result += "\tint protocol_method_count;\n";
1269 Result += "\tstruct protocol_methods protocols[];\n};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001270 objc_protocol_methods = true;
1271 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001272
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001273 // Output instance methods declared in this protocol.
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001274 int NumMethods = PDecl->getNumInstanceMethods();
1275 if (NumMethods > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001276 Result += "\nstatic struct _objc_protocol_method_list "
1277 "_OBJC_PROTOCOL_INSTANCE_METHODS_";
1278 Result += PDecl->getName();
1279 Result += " __attribute__ ((section (\"__OBJC, __cat_inst_meth\")))= "
1280 "{\n\t" + utostr(NumMethods) + "\n";
1281
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001282 ObjcMethodDecl **Methods = PDecl->getInstanceMethods();
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001283 Result += "\t,{{(SEL)\"";
1284 Result += Methods[0]->getSelector().getName().c_str();
1285 Result += "\", \"\"}\n";
1286
1287 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001288 Result += "\t ,{(SEL)\"";
1289 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanian33e1d642007-10-29 22:57:28 +00001290 std::string MethodTypeString;
1291 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
1292 Result += "\", \"";
1293 Result += MethodTypeString;
1294 Result += "\"}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001295 }
1296 Result += "\t }\n};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001297 }
1298
1299 // Output class methods declared in this protocol.
1300 NumMethods = PDecl->getNumClassMethods();
1301 if (NumMethods > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001302 Result += "\nstatic struct _objc_protocol_method_list "
1303 "_OBJC_PROTOCOL_CLASS_METHODS_";
1304 Result += PDecl->getName();
1305 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
1306 "{\n\t";
1307 Result += utostr(NumMethods);
1308 Result += "\n";
1309
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001310 ObjcMethodDecl **Methods = PDecl->getClassMethods();
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001311 Result += "\t,{{(SEL)\"";
1312 Result += Methods[0]->getSelector().getName().c_str();
1313 Result += "\", \"\"}\n";
1314
1315 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001316 Result += "\t ,{(SEL)\"";
1317 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanian33e1d642007-10-29 22:57:28 +00001318 std::string MethodTypeString;
1319 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
1320 Result += "\", \"";
1321 Result += MethodTypeString;
1322 Result += "\"}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001323 }
1324 Result += "\t }\n};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001325 }
1326 // Output:
1327 /* struct _objc_protocol {
1328 // Objective-C 1.0 extensions
1329 struct _objc_protocol_extension *isa;
1330 char *protocol_name;
1331 struct _objc_protocol **protocol_list;
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001332 struct _objc_protocol_method_list *instance_methods;
1333 struct _objc_protocol_method_list *class_methods;
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001334 };
1335 */
1336 static bool objc_protocol = false;
1337 if (!objc_protocol) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001338 Result += "\nstruct _objc_protocol {\n";
1339 Result += "\tstruct _objc_protocol_extension *isa;\n";
1340 Result += "\tchar *protocol_name;\n";
1341 Result += "\tstruct _objc_protocol **protocol_list;\n";
1342 Result += "\tstruct _objc_protocol_method_list *instance_methods;\n";
1343 Result += "\tstruct _objc_protocol_method_list *class_methods;\n";
1344 Result += "};\n";
1345
1346 /* struct _objc_protocol_list {
1347 struct _objc_protocol_list *next;
1348 int protocol_count;
1349 struct _objc_protocol *class_protocols[];
1350 }
1351 */
1352 Result += "\nstruct _objc_protocol_list {\n";
1353 Result += "\tstruct _objc_protocol_list *next;\n";
1354 Result += "\tint protocol_count;\n";
1355 Result += "\tstruct _objc_protocol *class_protocols[];\n";
1356 Result += "};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001357 objc_protocol = true;
1358 }
1359
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001360 Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_";
1361 Result += PDecl->getName();
1362 Result += " __attribute__ ((section (\"__OBJC, __protocol\")))= "
1363 "{\n\t0, \"";
1364 Result += PDecl->getName();
1365 Result += "\", 0, ";
1366 if (PDecl->getInstanceMethods() > 0) {
1367 Result += "&_OBJC_PROTOCOL_INSTANCE_METHODS_";
1368 Result += PDecl->getName();
1369 Result += ", ";
1370 }
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001371 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001372 Result += "0, ";
1373 if (PDecl->getClassMethods() > 0) {
1374 Result += "&_OBJC_PROTOCOL_CLASS_METHODS_";
1375 Result += PDecl->getName();
1376 Result += "\n";
1377 }
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001378 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001379 Result += "0\n";
1380 Result += "};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001381 }
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001382 // Output the top lovel protocol meta-data for the class.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001383 Result += "\nstatic struct _objc_protocol_list _OBJC_";
1384 Result += prefix;
1385 Result += "_PROTOCOLS_";
1386 Result += ClassName;
1387 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
1388 "{\n\t0, ";
1389 Result += utostr(NumProtocols);
1390 Result += "\n";
1391
1392 Result += "\t,{&_OBJC_PROTOCOL_";
1393 Result += Protocols[0]->getName();
1394 Result += " \n";
1395
1396 for (int i = 1; i < NumProtocols; i++) {
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001397 ObjcProtocolDecl *PDecl = Protocols[i];
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001398 Result += "\t ,&_OBJC_PROTOCOL_";
1399 Result += PDecl->getName();
1400 Result += "\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001401 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001402 Result += "\t }\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001403 }
1404}
1405
1406/// RewriteObjcCategoryImplDecl - Rewrite metadata for each category
1407/// implementation.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001408void RewriteTest::RewriteObjcCategoryImplDecl(ObjcCategoryImplDecl *IDecl,
1409 std::string &Result) {
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001410 ObjcInterfaceDecl *ClassDecl = IDecl->getClassInterface();
1411 // Find category declaration for this implementation.
1412 ObjcCategoryDecl *CDecl;
1413 for (CDecl = ClassDecl->getCategoryList(); CDecl;
1414 CDecl = CDecl->getNextClassCategory())
1415 if (CDecl->getIdentifier() == IDecl->getIdentifier())
1416 break;
Fariborz Jahanianbac97d42007-11-13 22:09:49 +00001417
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001418 char *FullCategoryName = (char*)alloca(
1419 strlen(ClassDecl->getName()) + strlen(IDecl->getName()) + 2);
1420 sprintf(FullCategoryName, "%s_%s", ClassDecl->getName(), IDecl->getName());
1421
1422 // Build _objc_method_list for class's instance methods if needed
1423 RewriteObjcMethodsMetaData(IDecl->getInstanceMethods(),
1424 IDecl->getNumInstanceMethods(),
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +00001425 true,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001426 "CATEGORY_", FullCategoryName, Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001427
1428 // Build _objc_method_list for class's class methods if needed
1429 RewriteObjcMethodsMetaData(IDecl->getClassMethods(),
1430 IDecl->getNumClassMethods(),
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +00001431 false,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001432 "CATEGORY_", FullCategoryName, Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001433
1434 // Protocols referenced in class declaration?
Fariborz Jahanianbac97d42007-11-13 22:09:49 +00001435 // Null CDecl is case of a category implementation with no category interface
1436 if (CDecl)
1437 RewriteObjcProtocolsMetaData(CDecl->getReferencedProtocols(),
1438 CDecl->getNumReferencedProtocols(),
1439 "CATEGORY",
1440 FullCategoryName, Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001441
1442 /* struct _objc_category {
1443 char *category_name;
1444 char *class_name;
1445 struct _objc_method_list *instance_methods;
1446 struct _objc_method_list *class_methods;
1447 struct _objc_protocol_list *protocols;
1448 // Objective-C 1.0 extensions
1449 uint32_t size; // sizeof (struct _objc_category)
1450 struct _objc_property_list *instance_properties; // category's own
1451 // @property decl.
1452 };
1453 */
1454
1455 static bool objc_category = false;
1456 if (!objc_category) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001457 Result += "\nstruct _objc_category {\n";
1458 Result += "\tchar *category_name;\n";
1459 Result += "\tchar *class_name;\n";
1460 Result += "\tstruct _objc_method_list *instance_methods;\n";
1461 Result += "\tstruct _objc_method_list *class_methods;\n";
1462 Result += "\tstruct _objc_protocol_list *protocols;\n";
1463 Result += "\tunsigned int size;\n";
1464 Result += "\tstruct _objc_property_list *instance_properties;\n";
1465 Result += "};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001466 objc_category = true;
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001467 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001468 Result += "\nstatic struct _objc_category _OBJC_CATEGORY_";
1469 Result += FullCategoryName;
1470 Result += " __attribute__ ((section (\"__OBJC, __category\")))= {\n\t\"";
1471 Result += IDecl->getName();
1472 Result += "\"\n\t, \"";
1473 Result += ClassDecl->getName();
1474 Result += "\"\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001475
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001476 if (IDecl->getNumInstanceMethods() > 0) {
1477 Result += "\t, (struct _objc_method_list *)"
1478 "&_OBJC_CATEGORY_INSTANCE_METHODS_";
1479 Result += FullCategoryName;
1480 Result += "\n";
1481 }
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001482 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001483 Result += "\t, 0\n";
1484 if (IDecl->getNumClassMethods() > 0) {
1485 Result += "\t, (struct _objc_method_list *)"
1486 "&_OBJC_CATEGORY_CLASS_METHODS_";
1487 Result += FullCategoryName;
1488 Result += "\n";
1489 }
1490 else
1491 Result += "\t, 0\n";
1492
Fariborz Jahanianbac97d42007-11-13 22:09:49 +00001493 if (CDecl && CDecl->getNumReferencedProtocols() > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001494 Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";
1495 Result += FullCategoryName;
1496 Result += "\n";
1497 }
1498 else
1499 Result += "\t, 0\n";
1500 Result += "\t, sizeof(struct _objc_category), 0\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001501}
1502
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001503/// SynthesizeIvarOffsetComputation - This rutine synthesizes computation of
1504/// ivar offset.
1505void RewriteTest::SynthesizeIvarOffsetComputation(ObjcImplementationDecl *IDecl,
1506 ObjcIvarDecl *ivar,
1507 std::string &Result) {
Fariborz Jahanian909f02a2007-11-05 17:47:33 +00001508 Result += "offsetof(struct ";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001509 Result += IDecl->getName();
1510 Result += ", ";
1511 Result += ivar->getName();
1512 Result += ")";
1513}
1514
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001515//===----------------------------------------------------------------------===//
1516// Meta Data Emission
1517//===----------------------------------------------------------------------===//
1518
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001519void RewriteTest::RewriteObjcClassMetaData(ObjcImplementationDecl *IDecl,
1520 std::string &Result) {
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001521 ObjcInterfaceDecl *CDecl = IDecl->getClassInterface();
1522
1523 // Build _objc_ivar_list metadata for classes ivars if needed
1524 int NumIvars = IDecl->getImplDeclNumIvars() > 0
1525 ? IDecl->getImplDeclNumIvars()
Steve Naroff03300712007-11-12 13:56:41 +00001526 : (CDecl ? CDecl->getNumInstanceVariables() : 0);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001527
Fariborz Jahanian4d733d32007-10-26 23:09:28 +00001528 SynthesizeObjcInternalStruct(CDecl, Result);
1529
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001530 if (NumIvars > 0) {
1531 static bool objc_ivar = false;
1532 if (!objc_ivar) {
1533 /* struct _objc_ivar {
1534 char *ivar_name;
1535 char *ivar_type;
1536 int ivar_offset;
1537 };
1538 */
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001539 Result += "\nstruct _objc_ivar {\n";
1540 Result += "\tchar *ivar_name;\n";
1541 Result += "\tchar *ivar_type;\n";
1542 Result += "\tint ivar_offset;\n";
1543 Result += "};\n";
1544
1545 /* struct _objc_ivar_list {
1546 int ivar_count;
1547 struct _objc_ivar ivar_list[];
1548 };
1549 */
1550 Result += "\nstruct _objc_ivar_list {\n";
1551 Result += "\tint ivar_count;\n";
1552 Result += "\tstruct _objc_ivar ivar_list[];\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001553 objc_ivar = true;
1554 }
1555
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001556 Result += "\nstatic struct _objc_ivar_list _OBJC_INSTANCE_VARIABLES_";
1557 Result += IDecl->getName();
1558 Result += " __attribute__ ((section (\"__OBJC, __instance_vars\")))= "
1559 "{\n\t";
1560 Result += utostr(NumIvars);
1561 Result += "\n";
1562
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001563 ObjcIvarDecl **Ivars = IDecl->getImplDeclIVars()
1564 ? IDecl->getImplDeclIVars()
Steve Naroff03300712007-11-12 13:56:41 +00001565 : CDecl->getInstanceVariables();
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001566 Result += "\t,{{\"";
1567 Result += Ivars[0]->getName();
Fariborz Jahanian160eb652007-10-29 17:16:25 +00001568 Result += "\", \"";
1569 std::string StrEncoding;
1570 Context->getObjcEncodingForType(Ivars[0]->getType(), StrEncoding);
1571 Result += StrEncoding;
1572 Result += "\", ";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001573 SynthesizeIvarOffsetComputation(IDecl, Ivars[0], Result);
1574 Result += "}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001575 for (int i = 1; i < NumIvars; i++) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001576 Result += "\t ,{\"";
1577 Result += Ivars[i]->getName();
Fariborz Jahanian160eb652007-10-29 17:16:25 +00001578 Result += "\", \"";
1579 std::string StrEncoding;
1580 Context->getObjcEncodingForType(Ivars[i]->getType(), StrEncoding);
1581 Result += StrEncoding;
1582 Result += "\", ";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001583 SynthesizeIvarOffsetComputation(IDecl, Ivars[i], Result);
1584 Result += "}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001585 }
1586
1587 Result += "\t }\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001588 }
1589
1590 // Build _objc_method_list for class's instance methods if needed
1591 RewriteObjcMethodsMetaData(IDecl->getInstanceMethods(),
1592 IDecl->getNumInstanceMethods(),
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001593 true,
1594 "", IDecl->getName(), Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001595
1596 // Build _objc_method_list for class's class methods if needed
1597 RewriteObjcMethodsMetaData(IDecl->getClassMethods(),
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +00001598 IDecl->getNumClassMethods(),
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001599 false,
1600 "", IDecl->getName(), Result);
1601
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001602 // Protocols referenced in class declaration?
1603 RewriteObjcProtocolsMetaData(CDecl->getReferencedProtocols(),
1604 CDecl->getNumIntfRefProtocols(),
1605 "CLASS",
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001606 CDecl->getName(), Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001607
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001608
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001609 // Declaration of class/meta-class metadata
1610 /* struct _objc_class {
1611 struct _objc_class *isa; // or const char *root_class_name when metadata
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001612 const char *super_class_name;
1613 char *name;
1614 long version;
1615 long info;
1616 long instance_size;
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001617 struct _objc_ivar_list *ivars;
1618 struct _objc_method_list *methods;
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001619 struct objc_cache *cache;
1620 struct objc_protocol_list *protocols;
1621 const char *ivar_layout;
1622 struct _objc_class_ext *ext;
1623 };
1624 */
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001625 static bool objc_class = false;
1626 if (!objc_class) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001627 Result += "\nstruct _objc_class {\n";
1628 Result += "\tstruct _objc_class *isa;\n";
1629 Result += "\tconst char *super_class_name;\n";
1630 Result += "\tchar *name;\n";
1631 Result += "\tlong version;\n";
1632 Result += "\tlong info;\n";
1633 Result += "\tlong instance_size;\n";
1634 Result += "\tstruct _objc_ivar_list *ivars;\n";
1635 Result += "\tstruct _objc_method_list *methods;\n";
1636 Result += "\tstruct objc_cache *cache;\n";
1637 Result += "\tstruct _objc_protocol_list *protocols;\n";
1638 Result += "\tconst char *ivar_layout;\n";
1639 Result += "\tstruct _objc_class_ext *ext;\n";
1640 Result += "};\n";
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001641 objc_class = true;
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001642 }
1643
1644 // Meta-class metadata generation.
1645 ObjcInterfaceDecl *RootClass = 0;
1646 ObjcInterfaceDecl *SuperClass = CDecl->getSuperClass();
1647 while (SuperClass) {
1648 RootClass = SuperClass;
1649 SuperClass = SuperClass->getSuperClass();
1650 }
1651 SuperClass = CDecl->getSuperClass();
1652
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001653 Result += "\nstatic struct _objc_class _OBJC_METACLASS_";
1654 Result += CDecl->getName();
1655 Result += " __attribute__ ((section (\"__OBJC, __meta_class\")))= "
1656 "{\n\t(struct _objc_class *)\"";
1657 Result += (RootClass ? RootClass->getName() : CDecl->getName());
1658 Result += "\"";
1659
1660 if (SuperClass) {
1661 Result += ", \"";
1662 Result += SuperClass->getName();
1663 Result += "\", \"";
1664 Result += CDecl->getName();
1665 Result += "\"";
1666 }
1667 else {
1668 Result += ", 0, \"";
1669 Result += CDecl->getName();
1670 Result += "\"";
1671 }
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001672 // TODO: 'ivars' field for root class is currently set to 0.
1673 // 'info' field is initialized to CLS_META(2) for metaclass
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001674 Result += ", 0,2, sizeof(struct _objc_class), 0";
1675 if (CDecl->getNumClassMethods() > 0) {
1676 Result += "\n\t, &_OBJC_CLASS_METHODS_";
1677 Result += CDecl->getName();
1678 Result += "\n";
1679 }
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001680 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001681 Result += ", 0\n";
1682 if (CDecl->getNumIntfRefProtocols() > 0) {
1683 Result += "\t,0, &_OBJC_CLASS_PROTOCOLS_";
1684 Result += CDecl->getName();
1685 Result += ",0,0\n";
1686 }
Fariborz Jahanian454cb012007-10-24 20:54:23 +00001687 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001688 Result += "\t,0,0,0,0\n";
1689 Result += "};\n";
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001690
1691 // class metadata generation.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001692 Result += "\nstatic struct _objc_class _OBJC_CLASS_";
1693 Result += CDecl->getName();
1694 Result += " __attribute__ ((section (\"__OBJC, __class\")))= "
1695 "{\n\t&_OBJC_METACLASS_";
1696 Result += CDecl->getName();
1697 if (SuperClass) {
1698 Result += ", \"";
1699 Result += SuperClass->getName();
1700 Result += "\", \"";
1701 Result += CDecl->getName();
1702 Result += "\"";
1703 }
1704 else {
1705 Result += ", 0, \"";
1706 Result += CDecl->getName();
1707 Result += "\"";
1708 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001709 // 'info' field is initialized to CLS_CLASS(1) for class
Fariborz Jahanian4d733d32007-10-26 23:09:28 +00001710 Result += ", 0,1";
1711 if (!ObjcSynthesizedStructs.count(CDecl))
1712 Result += ",0";
1713 else {
1714 // class has size. Must synthesize its size.
Fariborz Jahanian909f02a2007-11-05 17:47:33 +00001715 Result += ",sizeof(struct ";
Fariborz Jahanian4d733d32007-10-26 23:09:28 +00001716 Result += CDecl->getName();
1717 Result += ")";
1718 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001719 if (NumIvars > 0) {
1720 Result += ", &_OBJC_INSTANCE_VARIABLES_";
1721 Result += CDecl->getName();
1722 Result += "\n\t";
1723 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001724 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001725 Result += ",0";
1726 if (IDecl->getNumInstanceMethods() > 0) {
1727 Result += ", &_OBJC_INSTANCE_METHODS_";
1728 Result += CDecl->getName();
1729 Result += ", 0\n\t";
1730 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001731 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001732 Result += ",0,0";
1733 if (CDecl->getNumIntfRefProtocols() > 0) {
1734 Result += ", &_OBJC_CLASS_PROTOCOLS_";
1735 Result += CDecl->getName();
1736 Result += ", 0,0\n";
1737 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001738 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001739 Result += ",0,0,0\n";
1740 Result += "};\n";
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001741}
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00001742
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +00001743/// RewriteImplementations - This routine rewrites all method implementations
1744/// and emits meta-data.
1745
1746void RewriteTest::RewriteImplementations(std::string &Result) {
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001747 int ClsDefCount = ClassImplementation.size();
1748 int CatDefCount = CategoryImplementation.size();
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +00001749
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001750 if (ClsDefCount == 0 && CatDefCount == 0)
1751 return;
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +00001752 // Rewrite implemented methods
1753 for (int i = 0; i < ClsDefCount; i++)
1754 RewriteImplementationDecl(ClassImplementation[i]);
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00001755
Fariborz Jahanian66d6b292007-11-13 20:04:28 +00001756 for (int i = 0; i < CatDefCount; i++)
1757 RewriteImplementationDecl(CategoryImplementation[i]);
1758
Fariborz Jahanian454cb012007-10-24 20:54:23 +00001759 // TODO: This is temporary until we decide how to access objc types in a
1760 // c program
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001761 Result += "#include <Objc/objc.h>\n";
1762 // This is needed for use of offsetof
1763 Result += "#include <stddef.h>\n";
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +00001764
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001765 // For each implemented class, write out all its meta data.
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00001766 for (int i = 0; i < ClsDefCount; i++)
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001767 RewriteObjcClassMetaData(ClassImplementation[i], Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001768
1769 // For each implemented category, write out all its meta data.
1770 for (int i = 0; i < CatDefCount; i++)
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001771 RewriteObjcCategoryImplDecl(CategoryImplementation[i], Result);
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00001772
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001773 // Write objc_symtab metadata
1774 /*
1775 struct _objc_symtab
1776 {
1777 long sel_ref_cnt;
1778 SEL *refs;
1779 short cls_def_cnt;
1780 short cat_def_cnt;
1781 void *defs[cls_def_cnt + cat_def_cnt];
1782 };
1783 */
1784
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001785 Result += "\nstruct _objc_symtab {\n";
1786 Result += "\tlong sel_ref_cnt;\n";
1787 Result += "\tSEL *refs;\n";
1788 Result += "\tshort cls_def_cnt;\n";
1789 Result += "\tshort cat_def_cnt;\n";
1790 Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n";
1791 Result += "};\n\n";
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001792
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001793 Result += "static struct _objc_symtab "
1794 "_OBJC_SYMBOLS __attribute__((section (\"__OBJC, __symbols\")))= {\n";
1795 Result += "\t0, 0, " + utostr(ClsDefCount)
1796 + ", " + utostr(CatDefCount) + "\n";
1797 for (int i = 0; i < ClsDefCount; i++) {
1798 Result += "\t,&_OBJC_CLASS_";
1799 Result += ClassImplementation[i]->getName();
1800 Result += "\n";
1801 }
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001802
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001803 for (int i = 0; i < CatDefCount; i++) {
1804 Result += "\t,&_OBJC_CATEGORY_";
1805 Result += CategoryImplementation[i]->getClassInterface()->getName();
1806 Result += "_";
1807 Result += CategoryImplementation[i]->getName();
1808 Result += "\n";
1809 }
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001810
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001811 Result += "};\n\n";
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001812
1813 // Write objc_module metadata
1814
1815 /*
1816 struct _objc_module {
1817 long version;
1818 long size;
1819 const char *name;
1820 struct _objc_symtab *symtab;
1821 }
1822 */
1823
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001824 Result += "\nstruct _objc_module {\n";
1825 Result += "\tlong version;\n";
1826 Result += "\tlong size;\n";
1827 Result += "\tconst char *name;\n";
1828 Result += "\tstruct _objc_symtab *symtab;\n";
1829 Result += "};\n\n";
1830 Result += "static struct _objc_module "
1831 "_OBJC_MODULES __attribute__ ((section (\"__OBJC, __module_info\")))= {\n";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001832 Result += "\t" + utostr(OBJC_ABI_VERSION) +
1833 ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001834 Result += "};\n\n";
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +00001835
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001836}
Chris Lattner311ff022007-10-16 22:36:42 +00001837