blob: 4c7bd9c9d9dddfe9a7a865137e7ee06a322eee90 [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"
Fariborz Jahanian95673922007-11-14 22:26:25 +000073 "(struct objc_class *, struct objc_object *, ...);\n"
74 "#include <Objc/objc.h>\n";
Steve Naroff21867b12007-11-07 18:43:40 +000075
Steve Naroffab972d32007-11-04 22:37:50 +000076 Rewrite.InsertText(SourceLocation::getFileLoc(mainFileID, 0),
77 s, strlen(s));
Chris Lattner77cd2a02007-10-11 00:43:27 +000078 }
Chris Lattner8a12c272007-10-11 18:38:32 +000079
Chris Lattnerf04da132007-10-24 17:06:59 +000080 // Top Level Driver code.
81 virtual void HandleTopLevelDecl(Decl *D);
Chris Lattner2c64b7b2007-10-16 21:07:07 +000082 void HandleDeclInMainFile(Decl *D);
Chris Lattnerf04da132007-10-24 17:06:59 +000083 ~RewriteTest();
84
85 // Syntactic Rewriting.
Steve Naroffab972d32007-11-04 22:37:50 +000086 void RewritePrologue(SourceLocation Loc);
Chris Lattner2c64b7b2007-10-16 21:07:07 +000087 void RewriteInclude(SourceLocation Loc);
Chris Lattnerf04da132007-10-24 17:06:59 +000088 void RewriteTabs();
89 void RewriteForwardClassDecl(ObjcClassDecl *Dcl);
Steve Naroffbef11852007-10-26 20:53:56 +000090 void RewriteInterfaceDecl(ObjcInterfaceDecl *Dcl);
Fariborz Jahanian66d6b292007-11-13 20:04:28 +000091 void RewriteImplementationDecl(NamedDecl *Dcl);
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +000092 void RewriteObjcMethodDecl(ObjcMethodDecl *MDecl, std::string &ResultStr);
Steve Naroff423cb562007-10-30 13:30:57 +000093 void RewriteCategoryDecl(ObjcCategoryDecl *Dcl);
Steve Naroff752d6ef2007-10-30 16:42:30 +000094 void RewriteProtocolDecl(ObjcProtocolDecl *Dcl);
Fariborz Jahaniand175ddf2007-11-14 00:42:16 +000095 void RewriteForwardProtocolDecl(ObjcForwardProtocolDecl *Dcl);
Steve Naroff71c0a952007-11-13 23:01:27 +000096 void RewriteMethodDeclarations(int nMethods, ObjcMethodDecl **Methods);
Fariborz Jahanian957cf652007-11-07 00:09:37 +000097 void RewriteProperties(int nProperties, ObjcPropertyDecl **Properties);
Steve Naroff09b266e2007-10-30 23:14:51 +000098 void RewriteFunctionDecl(FunctionDecl *FD);
Steve Naroffd5255f52007-11-01 13:24:47 +000099 void RewriteObjcQualifiedInterfaceTypes(
100 const FunctionTypeProto *proto, FunctionDecl *FD);
101 bool needToScanForQualifiers(QualType T);
Chris Lattner311ff022007-10-16 22:36:42 +0000102
Chris Lattnerf04da132007-10-24 17:06:59 +0000103 // Expression Rewriting.
Steve Narofff3473a72007-11-09 15:20:18 +0000104 Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S);
Chris Lattnere64b7772007-10-24 16:57:36 +0000105 Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
Steve Naroff7e3411b2007-11-15 02:58:25 +0000106 Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV);
Steve Naroffb42f8412007-11-05 14:50:49 +0000107 Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp);
Chris Lattnere64b7772007-10-24 16:57:36 +0000108 Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
Steve Naroffbeaf2992007-11-03 11:27:19 +0000109 Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp);
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000110 Stmt *RewriteObjcTryStmt(ObjcAtTryStmt *S);
111 Stmt *RewriteObjcCatchStmt(ObjcAtCatchStmt *S);
112 Stmt *RewriteObjcFinallyStmt(ObjcAtFinallyStmt *S);
Steve Naroff2bd03922007-11-07 15:32:26 +0000113 Stmt *RewriteObjcThrowStmt(ObjcAtThrowStmt *S);
Steve Naroff934f2762007-10-24 22:48:43 +0000114 CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD,
115 Expr **args, unsigned nargs);
Steve Naroff09b266e2007-10-30 23:14:51 +0000116 void SynthMsgSendFunctionDecl();
117 void SynthGetClassFunctionDecl();
Steve Naroff96984642007-11-08 14:30:50 +0000118 void SynthCFStringFunctionDecl();
119
Chris Lattnerf04da132007-10-24 17:06:59 +0000120 // Metadata emission.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000121 void RewriteObjcClassMetaData(ObjcImplementationDecl *IDecl,
122 std::string &Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000123
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000124 void RewriteObjcCategoryImplDecl(ObjcCategoryImplDecl *CDecl,
125 std::string &Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000126
Steve Naroff0416fb92007-11-11 17:19:15 +0000127 void RewriteObjcMethodsMetaData(ObjcMethodDecl *const*Methods,
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000128 int NumMethods,
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +0000129 bool IsInstanceMethod,
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000130 const char *prefix,
Chris Lattner158ecb92007-10-25 17:07:24 +0000131 const char *ClassName,
132 std::string &Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +0000133
134 void RewriteObjcProtocolsMetaData(ObjcProtocolDecl **Protocols,
135 int NumProtocols,
136 const char *prefix,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +0000137 const char *ClassName,
138 std::string &Result);
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000139 void SynthesizeObjcInternalStruct(ObjcInterfaceDecl *CDecl,
140 std::string &Result);
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000141 void SynthesizeIvarOffsetComputation(ObjcImplementationDecl *IDecl,
142 ObjcIvarDecl *ivar,
143 std::string &Result);
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +0000144 void RewriteImplementations(std::string &Result);
Chris Lattner77cd2a02007-10-11 00:43:27 +0000145 };
146}
147
Chris Lattner8a12c272007-10-11 18:38:32 +0000148ASTConsumer *clang::CreateCodeRewriterTest() { return new RewriteTest(); }
Chris Lattner77cd2a02007-10-11 00:43:27 +0000149
Chris Lattnerf04da132007-10-24 17:06:59 +0000150//===----------------------------------------------------------------------===//
151// Top Level Driver Code
152//===----------------------------------------------------------------------===//
153
Chris Lattner8a12c272007-10-11 18:38:32 +0000154void RewriteTest::HandleTopLevelDecl(Decl *D) {
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000155 // Two cases: either the decl could be in the main file, or it could be in a
156 // #included file. If the former, rewrite it now. If the later, check to see
157 // if we rewrote the #include/#import.
158 SourceLocation Loc = D->getLocation();
159 Loc = SM->getLogicalLoc(Loc);
160
161 // If this is for a builtin, ignore it.
162 if (Loc.isInvalid()) return;
163
Steve Naroffebf2b562007-10-23 23:50:29 +0000164 // Look for built-in declarations that we need to refer during the rewrite.
165 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Steve Naroff09b266e2007-10-30 23:14:51 +0000166 RewriteFunctionDecl(FD);
Steve Naroffbeaf2992007-11-03 11:27:19 +0000167 } else if (FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
168 // declared in <Foundation/NSString.h>
169 if (strcmp(FVD->getName(), "_NSConstantStringClassReference") == 0) {
170 ConstantStringClassReference = FVD;
171 return;
172 }
Steve Naroffbef11852007-10-26 20:53:56 +0000173 } else if (ObjcInterfaceDecl *MD = dyn_cast<ObjcInterfaceDecl>(D)) {
174 RewriteInterfaceDecl(MD);
Steve Naroff423cb562007-10-30 13:30:57 +0000175 } else if (ObjcCategoryDecl *CD = dyn_cast<ObjcCategoryDecl>(D)) {
176 RewriteCategoryDecl(CD);
Steve Naroff752d6ef2007-10-30 16:42:30 +0000177 } else if (ObjcProtocolDecl *PD = dyn_cast<ObjcProtocolDecl>(D)) {
178 RewriteProtocolDecl(PD);
Fariborz Jahaniand175ddf2007-11-14 00:42:16 +0000179 } else if (ObjcForwardProtocolDecl *FP =
180 dyn_cast<ObjcForwardProtocolDecl>(D)){
181 RewriteForwardProtocolDecl(FP);
Steve Naroffebf2b562007-10-23 23:50:29 +0000182 }
Chris Lattnerf04da132007-10-24 17:06:59 +0000183 // If we have a decl in the main file, see if we should rewrite it.
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000184 if (SM->getDecomposedFileLoc(Loc).first == MainFileID)
185 return HandleDeclInMainFile(D);
186
Chris Lattnerf04da132007-10-24 17:06:59 +0000187 // Otherwise, see if there is a #import in the main file that should be
188 // rewritten.
Steve Naroff32174822007-11-09 12:50:28 +0000189 //RewriteInclude(Loc);
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000190}
191
Chris Lattnerf04da132007-10-24 17:06:59 +0000192/// HandleDeclInMainFile - This is called for each top-level decl defined in the
193/// main file of the input.
194void RewriteTest::HandleDeclInMainFile(Decl *D) {
195 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
196 if (Stmt *Body = FD->getBody())
Steve Narofff3473a72007-11-09 15:20:18 +0000197 FD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
Steve Naroff71c0a952007-11-13 23:01:27 +0000198
199 if (ObjcMethodDecl *MD = dyn_cast<ObjcMethodDecl>(D)) {
200 if (Stmt *Body = MD->getBody())
201 MD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
202 }
Chris Lattnerf04da132007-10-24 17:06:59 +0000203 if (ObjcImplementationDecl *CI = dyn_cast<ObjcImplementationDecl>(D))
204 ClassImplementation.push_back(CI);
205 else if (ObjcCategoryImplDecl *CI = dyn_cast<ObjcCategoryImplDecl>(D))
206 CategoryImplementation.push_back(CI);
207 else if (ObjcClassDecl *CD = dyn_cast<ObjcClassDecl>(D))
208 RewriteForwardClassDecl(CD);
Steve Narofff3473a72007-11-09 15:20:18 +0000209 else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
210 if (VD->getInit())
211 RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
212 }
Chris Lattnerf04da132007-10-24 17:06:59 +0000213 // Nothing yet.
214}
215
216RewriteTest::~RewriteTest() {
217 // Get the top-level buffer that this corresponds to.
Chris Lattner74a0c772007-11-08 04:27:23 +0000218
219 // Rewrite tabs if we care.
220 //RewriteTabs();
Chris Lattnerf04da132007-10-24 17:06:59 +0000221
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000222 // Rewrite Objective-c meta data*
223 std::string ResultStr;
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +0000224 RewriteImplementations(ResultStr);
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000225
Chris Lattnerf04da132007-10-24 17:06:59 +0000226 // Get the buffer corresponding to MainFileID. If we haven't changed it, then
227 // we are done.
228 if (const RewriteBuffer *RewriteBuf =
229 Rewrite.getRewriteBufferFor(MainFileID)) {
Steve Naroffbeaf2992007-11-03 11:27:19 +0000230 //printf("Changed:\n");
Chris Lattnerf04da132007-10-24 17:06:59 +0000231 std::string S(RewriteBuf->begin(), RewriteBuf->end());
232 printf("%s\n", S.c_str());
233 } else {
234 printf("No changes\n");
235 }
Fariborz Jahanian4402d812007-11-07 18:40:28 +0000236 // Emit metadata.
237 printf("%s", ResultStr.c_str());
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +0000238}
239
Chris Lattnerf04da132007-10-24 17:06:59 +0000240//===----------------------------------------------------------------------===//
241// Syntactic (non-AST) Rewriting Code
242//===----------------------------------------------------------------------===//
243
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000244void RewriteTest::RewriteInclude(SourceLocation Loc) {
245 // Rip up the #include stack to the main file.
246 SourceLocation IncLoc = Loc, NextLoc = Loc;
247 do {
248 IncLoc = Loc;
249 Loc = SM->getLogicalLoc(NextLoc);
250 NextLoc = SM->getIncludeLoc(Loc);
251 } while (!NextLoc.isInvalid());
252
253 // Loc is now the location of the #include filename "foo" or <foo/bar.h>.
254 // IncLoc indicates the header that was included if it is useful.
255 IncLoc = SM->getLogicalLoc(IncLoc);
256 if (SM->getDecomposedFileLoc(Loc).first != MainFileID ||
257 Loc == LastIncLoc)
258 return;
259 LastIncLoc = Loc;
260
261 unsigned IncCol = SM->getColumnNumber(Loc);
262 SourceLocation LineStartLoc = Loc.getFileLocWithOffset(-IncCol+1);
263
264 // Replace the #import with #include.
265 Rewrite.ReplaceText(LineStartLoc, IncCol-1, "#include ", strlen("#include "));
266}
267
Chris Lattnerf04da132007-10-24 17:06:59 +0000268void RewriteTest::RewriteTabs() {
269 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
270 const char *MainBufStart = MainBuf.first;
271 const char *MainBufEnd = MainBuf.second;
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +0000272
Chris Lattnerf04da132007-10-24 17:06:59 +0000273 // Loop over the whole file, looking for tabs.
274 for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) {
275 if (*BufPtr != '\t')
276 continue;
277
278 // Okay, we found a tab. This tab will turn into at least one character,
279 // but it depends on which 'virtual column' it is in. Compute that now.
280 unsigned VCol = 0;
281 while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' &&
282 BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r')
283 ++VCol;
284
285 // Okay, now that we know the virtual column, we know how many spaces to
286 // insert. We assume 8-character tab-stops.
287 unsigned Spaces = 8-(VCol & 7);
288
289 // Get the location of the tab.
290 SourceLocation TabLoc =
291 SourceLocation::getFileLoc(MainFileID, BufPtr-MainBufStart);
292
293 // Rewrite the single tab character into a sequence of spaces.
294 Rewrite.ReplaceText(TabLoc, 1, " ", Spaces);
295 }
Chris Lattner8a12c272007-10-11 18:38:32 +0000296}
297
298
Chris Lattnerf04da132007-10-24 17:06:59 +0000299void RewriteTest::RewriteForwardClassDecl(ObjcClassDecl *ClassDecl) {
300 int numDecls = ClassDecl->getNumForwardDecls();
301 ObjcInterfaceDecl **ForwardDecls = ClassDecl->getForwardDecls();
302
303 // Get the start location and compute the semi location.
304 SourceLocation startLoc = ClassDecl->getLocation();
305 const char *startBuf = SM->getCharacterData(startLoc);
306 const char *semiPtr = strchr(startBuf, ';');
307
308 // Translate to typedef's that forward reference structs with the same name
309 // as the class. As a convenience, we include the original declaration
310 // as a comment.
311 std::string typedefString;
312 typedefString += "// ";
Steve Naroff934f2762007-10-24 22:48:43 +0000313 typedefString.append(startBuf, semiPtr-startBuf+1);
314 typedefString += "\n";
315 for (int i = 0; i < numDecls; i++) {
316 ObjcInterfaceDecl *ForwardDecl = ForwardDecls[i];
Steve Naroff32174822007-11-09 12:50:28 +0000317 typedefString += "#ifndef _REWRITER_typedef_";
318 typedefString += ForwardDecl->getName();
319 typedefString += "\n";
320 typedefString += "#define _REWRITER_typedef_";
321 typedefString += ForwardDecl->getName();
322 typedefString += "\n";
Steve Naroff352336b2007-11-05 14:36:37 +0000323 typedefString += "typedef struct objc_object ";
Steve Naroff934f2762007-10-24 22:48:43 +0000324 typedefString += ForwardDecl->getName();
Steve Naroff32174822007-11-09 12:50:28 +0000325 typedefString += ";\n#endif\n";
Steve Naroff934f2762007-10-24 22:48:43 +0000326 }
327
328 // Replace the @class with typedefs corresponding to the classes.
329 Rewrite.ReplaceText(startLoc, semiPtr-startBuf+1,
330 typedefString.c_str(), typedefString.size());
Chris Lattnerf04da132007-10-24 17:06:59 +0000331}
332
Steve Naroff71c0a952007-11-13 23:01:27 +0000333void RewriteTest::RewriteMethodDeclarations(int nMethods, ObjcMethodDecl **Methods) {
Steve Naroff423cb562007-10-30 13:30:57 +0000334 for (int i = 0; i < nMethods; i++) {
335 ObjcMethodDecl *Method = Methods[i];
Steve Naroff1d098f62007-11-14 14:34:23 +0000336 SourceLocation LocStart = Method->getLocStart();
337 SourceLocation LocEnd = Method->getLocEnd();
Steve Naroff423cb562007-10-30 13:30:57 +0000338
Steve Naroff1d098f62007-11-14 14:34:23 +0000339 if (SM->getLineNumber(LocEnd) > SM->getLineNumber(LocStart)) {
340 Rewrite.InsertText(LocStart, "/* ", 3);
341 Rewrite.ReplaceText(LocEnd, 1, ";*/ ", 4);
342 } else {
343 Rewrite.InsertText(LocStart, "// ", 3);
344 }
Steve Naroff423cb562007-10-30 13:30:57 +0000345 }
346}
347
Fariborz Jahanian957cf652007-11-07 00:09:37 +0000348void RewriteTest::RewriteProperties(int nProperties, ObjcPropertyDecl **Properties)
349{
350 for (int i = 0; i < nProperties; i++) {
351 ObjcPropertyDecl *Property = Properties[i];
352 SourceLocation Loc = Property->getLocation();
353
354 Rewrite.ReplaceText(Loc, 0, "// ", 3);
355
356 // FIXME: handle properties that are declared across multiple lines.
357 }
358}
359
Steve Naroff423cb562007-10-30 13:30:57 +0000360void RewriteTest::RewriteCategoryDecl(ObjcCategoryDecl *CatDecl) {
361 SourceLocation LocStart = CatDecl->getLocStart();
362
363 // FIXME: handle category headers that are declared across multiple lines.
364 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
365
Steve Naroff71c0a952007-11-13 23:01:27 +0000366 RewriteMethodDeclarations(CatDecl->getNumInstanceMethods(),
367 CatDecl->getInstanceMethods());
368 RewriteMethodDeclarations(CatDecl->getNumClassMethods(),
369 CatDecl->getClassMethods());
Steve Naroff423cb562007-10-30 13:30:57 +0000370 // Lastly, comment out the @end.
371 Rewrite.ReplaceText(CatDecl->getAtEndLoc(), 0, "// ", 3);
372}
373
Steve Naroff752d6ef2007-10-30 16:42:30 +0000374void RewriteTest::RewriteProtocolDecl(ObjcProtocolDecl *PDecl) {
Fariborz Jahanianb82b3ea2007-11-14 01:37:46 +0000375 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
Fariborz Jahanianb82b3ea2007-11-14 01:37:46 +0000376
Steve Naroff752d6ef2007-10-30 16:42:30 +0000377 SourceLocation LocStart = PDecl->getLocStart();
378
379 // FIXME: handle protocol headers that are declared across multiple lines.
380 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
381
Steve Naroff71c0a952007-11-13 23:01:27 +0000382 RewriteMethodDeclarations(PDecl->getNumInstanceMethods(),
383 PDecl->getInstanceMethods());
384 RewriteMethodDeclarations(PDecl->getNumClassMethods(),
385 PDecl->getClassMethods());
Steve Naroff752d6ef2007-10-30 16:42:30 +0000386 // Lastly, comment out the @end.
Fariborz Jahanianb82b3ea2007-11-14 01:37:46 +0000387 SourceLocation LocEnd = PDecl->getAtEndLoc();
388 Rewrite.ReplaceText(LocEnd, 0, "// ", 3);
Steve Naroff8cc764c2007-11-14 15:03:57 +0000389
Fariborz Jahanianb82b3ea2007-11-14 01:37:46 +0000390 // Must comment out @optional/@required
391 const char *startBuf = SM->getCharacterData(LocStart);
392 const char *endBuf = SM->getCharacterData(LocEnd);
393 for (const char *p = startBuf; p < endBuf; p++) {
394 if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) {
395 std::string CommentedOptional = "/* @optional */";
Steve Naroff8cc764c2007-11-14 15:03:57 +0000396 SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
Fariborz Jahanianb82b3ea2007-11-14 01:37:46 +0000397 Rewrite.ReplaceText(OptionalLoc, strlen("@optional"),
398 CommentedOptional.c_str(), CommentedOptional.size());
399
400 }
401 else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) {
402 std::string CommentedRequired = "/* @required */";
Steve Naroff8cc764c2007-11-14 15:03:57 +0000403 SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
Fariborz Jahanianb82b3ea2007-11-14 01:37:46 +0000404 Rewrite.ReplaceText(OptionalLoc, strlen("@required"),
405 CommentedRequired.c_str(), CommentedRequired.size());
406
407 }
408 }
Steve Naroff752d6ef2007-10-30 16:42:30 +0000409}
410
Fariborz Jahaniand175ddf2007-11-14 00:42:16 +0000411void RewriteTest::RewriteForwardProtocolDecl(ObjcForwardProtocolDecl *PDecl) {
412 SourceLocation LocStart = PDecl->getLocation();
Steve Naroffb7fa9922007-11-14 03:37:28 +0000413 if (LocStart.isInvalid())
414 assert(false && "Invalid SourceLocation");
Fariborz Jahaniand175ddf2007-11-14 00:42:16 +0000415 // FIXME: handle forward protocol that are declared across multiple lines.
416 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
417}
418
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000419void RewriteTest::RewriteObjcMethodDecl(ObjcMethodDecl *OMD,
420 std::string &ResultStr) {
421 ResultStr += "\nstatic ";
422 ResultStr += OMD->getResultType().getAsString();
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000423 ResultStr += "\n";
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000424
425 // Unique method name
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000426 std::string NameStr;
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000427
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000428 if (OMD->isInstance())
429 NameStr += "_I_";
430 else
431 NameStr += "_C_";
432
433 NameStr += OMD->getClassInterface()->getName();
434 NameStr += "_";
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000435
436 NamedDecl *MethodContext = OMD->getMethodContext();
437 if (ObjcCategoryImplDecl *CID =
438 dyn_cast<ObjcCategoryImplDecl>(MethodContext)) {
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000439 NameStr += CID->getName();
440 NameStr += "_";
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000441 }
442 // Append selector names, replacing ':' with '_'
443 const char *selName = OMD->getSelector().getName().c_str();
444 if (!strchr(selName, ':'))
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000445 NameStr += OMD->getSelector().getName();
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000446 else {
447 std::string selString = OMD->getSelector().getName();
448 int len = selString.size();
449 for (int i = 0; i < len; i++)
450 if (selString[i] == ':')
451 selString[i] = '_';
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000452 NameStr += selString;
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000453 }
Fariborz Jahanianb7908b52007-11-13 21:02:00 +0000454 // Remember this name for metadata emission
455 MethodInternalNames[OMD] = NameStr;
456 ResultStr += NameStr;
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000457
458 // Rewrite arguments
459 ResultStr += "(";
460
461 // invisible arguments
462 if (OMD->isInstance()) {
463 QualType selfTy = Context->getObjcInterfaceType(OMD->getClassInterface());
464 selfTy = Context->getPointerType(selfTy);
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000465 if (ObjcSynthesizedStructs.count(OMD->getClassInterface()))
466 ResultStr += "struct ";
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000467 ResultStr += selfTy.getAsString();
468 }
469 else
470 ResultStr += Context->getObjcIdType().getAsString();
471
472 ResultStr += " self, ";
473 ResultStr += Context->getObjcSelType().getAsString();
474 ResultStr += " _cmd";
475
476 // Method arguments.
477 for (int i = 0; i < OMD->getNumParams(); i++) {
478 ParmVarDecl *PDecl = OMD->getParamDecl(i);
479 ResultStr += ", ";
480 ResultStr += PDecl->getType().getAsString();
481 ResultStr += " ";
482 ResultStr += PDecl->getName();
483 }
484 ResultStr += ")";
485
486}
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000487void RewriteTest::RewriteImplementationDecl(NamedDecl *OID) {
488 ObjcImplementationDecl *IMD = dyn_cast<ObjcImplementationDecl>(OID);
489 ObjcCategoryImplDecl *CID = dyn_cast<ObjcCategoryImplDecl>(OID);
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000490
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000491 if (IMD)
492 Rewrite.InsertText(IMD->getLocStart(), "// ", 3);
493 else
494 Rewrite.InsertText(CID->getLocStart(), "// ", 3);
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000495
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000496 int numMethods = IMD ? IMD->getNumInstanceMethods()
497 : CID->getNumInstanceMethods();
498
499 for (int i = 0; i < numMethods; i++) {
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000500 std::string ResultStr;
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000501 ObjcMethodDecl *OMD;
502 if (IMD)
503 OMD = IMD->getInstanceMethods()[i];
504 else
505 OMD = CID->getInstanceMethods()[i];
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000506 RewriteObjcMethodDecl(OMD, ResultStr);
507 SourceLocation LocStart = OMD->getLocStart();
508 SourceLocation LocEnd = OMD->getBody()->getLocStart();
509
510 const char *startBuf = SM->getCharacterData(LocStart);
511 const char *endBuf = SM->getCharacterData(LocEnd);
512 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
513 ResultStr.c_str(), ResultStr.size());
514 }
515
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000516 numMethods = IMD ? IMD->getNumClassMethods() : CID->getNumClassMethods();
517 for (int i = 0; i < numMethods; i++) {
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000518 std::string ResultStr;
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000519 ObjcMethodDecl *OMD;
520 if (IMD)
521 OMD = IMD->getClassMethods()[i];
522 else
523 OMD = CID->getClassMethods()[i];
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000524 RewriteObjcMethodDecl(OMD, ResultStr);
525 SourceLocation LocStart = OMD->getLocStart();
526 SourceLocation LocEnd = OMD->getBody()->getLocStart();
527
528 const char *startBuf = SM->getCharacterData(LocStart);
529 const char *endBuf = SM->getCharacterData(LocEnd);
530 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
531 ResultStr.c_str(), ResultStr.size());
532 }
Fariborz Jahanian66d6b292007-11-13 20:04:28 +0000533 if (IMD)
534 Rewrite.InsertText(IMD->getLocEnd(), "// ", 3);
535 else
536 Rewrite.InsertText(CID->getLocEnd(), "// ", 3);
Fariborz Jahanian48a0b6a2007-11-13 18:44:14 +0000537}
538
Steve Naroffbef11852007-10-26 20:53:56 +0000539void RewriteTest::RewriteInterfaceDecl(ObjcInterfaceDecl *ClassDecl) {
Steve Narofff908a872007-10-30 02:23:23 +0000540 std::string ResultStr;
Steve Naroff6c6a2db2007-11-01 03:35:41 +0000541 if (!ObjcForwardDecls.count(ClassDecl)) {
542 // we haven't seen a forward decl - generate a typedef.
Steve Naroff5086a8d2007-11-14 23:02:56 +0000543 ResultStr = "#ifndef _REWRITER_typedef_";
Steve Naroff32174822007-11-09 12:50:28 +0000544 ResultStr += ClassDecl->getName();
545 ResultStr += "\n";
546 ResultStr += "#define _REWRITER_typedef_";
547 ResultStr += ClassDecl->getName();
548 ResultStr += "\n";
Steve Naroff352336b2007-11-05 14:36:37 +0000549 ResultStr += "typedef struct objc_object ";
Steve Naroff6c6a2db2007-11-01 03:35:41 +0000550 ResultStr += ClassDecl->getName();
Steve Naroff32174822007-11-09 12:50:28 +0000551 ResultStr += ";\n#endif\n";
Steve Naroff6c6a2db2007-11-01 03:35:41 +0000552
553 // Mark this typedef as having been generated.
554 ObjcForwardDecls.insert(ClassDecl);
555 }
Steve Narofff908a872007-10-30 02:23:23 +0000556 SynthesizeObjcInternalStruct(ClassDecl, ResultStr);
557
Fariborz Jahanian957cf652007-11-07 00:09:37 +0000558 RewriteProperties(ClassDecl->getNumPropertyDecl(),
559 ClassDecl->getPropertyDecl());
Steve Naroff71c0a952007-11-13 23:01:27 +0000560 RewriteMethodDeclarations(ClassDecl->getNumInstanceMethods(),
561 ClassDecl->getInstanceMethods());
562 RewriteMethodDeclarations(ClassDecl->getNumClassMethods(),
563 ClassDecl->getClassMethods());
Steve Naroffbef11852007-10-26 20:53:56 +0000564
Steve Naroff2feac5e2007-10-30 03:43:13 +0000565 // Lastly, comment out the @end.
566 Rewrite.ReplaceText(ClassDecl->getAtEndLoc(), 0, "// ", 3);
Steve Naroffbef11852007-10-26 20:53:56 +0000567}
568
Steve Naroff7e3411b2007-11-15 02:58:25 +0000569Stmt *RewriteTest::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
570 ObjcIvarDecl *D = IV->getDecl();
571 if (IV->isFreeIvar()) {
572 Expr *Replacement = new MemberExpr(IV->getBase(), true, D,
573 IV->getLocation());
574 Rewrite.ReplaceStmt(IV, Replacement);
575 delete IV;
576 return Replacement;
577 }
578 else
579 return IV;
580}
581
Chris Lattnerf04da132007-10-24 17:06:59 +0000582//===----------------------------------------------------------------------===//
583// Function Body / Expression rewriting
584//===----------------------------------------------------------------------===//
585
Steve Narofff3473a72007-11-09 15:20:18 +0000586Stmt *RewriteTest::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
Chris Lattner311ff022007-10-16 22:36:42 +0000587 // Otherwise, just rewrite all children.
588 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
589 CI != E; ++CI)
Steve Naroff75730982007-11-07 04:08:17 +0000590 if (*CI) {
Steve Narofff3473a72007-11-09 15:20:18 +0000591 Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(*CI);
Steve Naroff75730982007-11-07 04:08:17 +0000592 if (newStmt)
593 *CI = newStmt;
594 }
Steve Naroffebf2b562007-10-23 23:50:29 +0000595
596 // Handle specific things.
597 if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
598 return RewriteAtEncode(AtEncode);
Steve Naroff7e3411b2007-11-15 02:58:25 +0000599
600 if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S))
601 return RewriteObjCIvarRefExpr(IvarRefExpr);
Steve Naroffb42f8412007-11-05 14:50:49 +0000602
603 if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S))
604 return RewriteAtSelector(AtSelector);
Steve Naroffbeaf2992007-11-03 11:27:19 +0000605
606 if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S))
607 return RewriteObjCStringLiteral(AtString);
Steve Naroffebf2b562007-10-23 23:50:29 +0000608
Steve Naroff934f2762007-10-24 22:48:43 +0000609 if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {
610 // Before we rewrite it, put the original message expression in a comment.
611 SourceLocation startLoc = MessExpr->getLocStart();
612 SourceLocation endLoc = MessExpr->getLocEnd();
613
614 const char *startBuf = SM->getCharacterData(startLoc);
615 const char *endBuf = SM->getCharacterData(endLoc);
616
617 std::string messString;
618 messString += "// ";
619 messString.append(startBuf, endBuf-startBuf+1);
620 messString += "\n";
Steve Naroffbef11852007-10-26 20:53:56 +0000621
Steve Naroff934f2762007-10-24 22:48:43 +0000622 // FIXME: Missing definition of Rewrite.InsertText(clang::SourceLocation, char const*, unsigned int).
623 // Rewrite.InsertText(startLoc, messString.c_str(), messString.size());
624 // Tried this, but it didn't work either...
Steve Naroff752d6ef2007-10-30 16:42:30 +0000625 // Rewrite.ReplaceText(startLoc, 0, messString.c_str(), messString.size());
Steve Naroffebf2b562007-10-23 23:50:29 +0000626 return RewriteMessageExpr(MessExpr);
Steve Naroff934f2762007-10-24 22:48:43 +0000627 }
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000628
629 if (ObjcAtTryStmt *StmtTry = dyn_cast<ObjcAtTryStmt>(S))
630 return RewriteObjcTryStmt(StmtTry);
Steve Naroff2bd03922007-11-07 15:32:26 +0000631
632 if (ObjcAtThrowStmt *StmtThrow = dyn_cast<ObjcAtThrowStmt>(S))
633 return RewriteObjcThrowStmt(StmtThrow);
634
Chris Lattnere64b7772007-10-24 16:57:36 +0000635 // Return this stmt unmodified.
636 return S;
Chris Lattner311ff022007-10-16 22:36:42 +0000637}
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +0000638
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000639Stmt *RewriteTest::RewriteObjcTryStmt(ObjcAtTryStmt *S) {
Steve Naroff75730982007-11-07 04:08:17 +0000640 // Get the start location and compute the semi location.
641 SourceLocation startLoc = S->getLocStart();
642 const char *startBuf = SM->getCharacterData(startLoc);
643
644 assert((*startBuf == '@') && "bogus @try location");
645
646 std::string buf;
647 // declare a new scope with two variables, _stack and _rethrow.
648 buf = "/* @try scope begin */ { struct _objc_exception_data {\n";
649 buf += "int buf[18/*32-bit i386*/];\n";
650 buf += "char *pointers[4];} _stack;\n";
651 buf += "id volatile _rethrow = 0;\n";
652 buf += "objc_exception_try_enter(&_stack);\n";
Steve Naroff21867b12007-11-07 18:43:40 +0000653 buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";
Steve Naroff75730982007-11-07 04:08:17 +0000654
655 Rewrite.ReplaceText(startLoc, 4, buf.c_str(), buf.size());
656
657 startLoc = S->getTryBody()->getLocEnd();
658 startBuf = SM->getCharacterData(startLoc);
659
660 assert((*startBuf == '}') && "bogus @try block");
661
662 SourceLocation lastCurlyLoc = startLoc;
663
664 startLoc = startLoc.getFileLocWithOffset(1);
665 buf = " /* @catch begin */ else {\n";
666 buf += " id _caught = objc_exception_extract(&_stack);\n";
667 buf += " objc_exception_try_enter (&_stack);\n";
Steve Naroff21867b12007-11-07 18:43:40 +0000668 buf += " if (_setjmp(_stack.buf))\n";
Steve Naroff75730982007-11-07 04:08:17 +0000669 buf += " _rethrow = objc_exception_extract(&_stack);\n";
670 buf += " else { /* @catch continue */";
671
Chris Lattner28d1fe82007-11-08 04:41:51 +0000672 Rewrite.InsertText(startLoc, buf.c_str(), buf.size());
Steve Naroff75730982007-11-07 04:08:17 +0000673
674 bool sawIdTypedCatch = false;
675 Stmt *lastCatchBody = 0;
676 ObjcAtCatchStmt *catchList = S->getCatchStmts();
677 while (catchList) {
678 Stmt *catchStmt = catchList->getCatchParamStmt();
679
680 if (catchList == S->getCatchStmts())
681 buf = "if ("; // we are generating code for the first catch clause
682 else
683 buf = "else if (";
684 startLoc = catchList->getLocStart();
685 startBuf = SM->getCharacterData(startLoc);
686
687 assert((*startBuf == '@') && "bogus @catch location");
688
689 const char *lParenLoc = strchr(startBuf, '(');
690
691 if (DeclStmt *declStmt = dyn_cast<DeclStmt>(catchStmt)) {
692 QualType t = dyn_cast<ValueDecl>(declStmt->getDecl())->getType();
693 if (t == Context->getObjcIdType()) {
694 buf += "1) { ";
695 Rewrite.ReplaceText(startLoc, lParenLoc-startBuf+1,
696 buf.c_str(), buf.size());
697 sawIdTypedCatch = true;
698 } else if (const PointerType *pType = t->getAsPointerType()) {
699 ObjcInterfaceType *cls; // Should be a pointer to a class.
700
701 cls = dyn_cast<ObjcInterfaceType>(pType->getPointeeType().getTypePtr());
702 if (cls) {
Steve Naroff21867b12007-11-07 18:43:40 +0000703 buf += "objc_exception_match((struct objc_class *)objc_getClass(\"";
Steve Naroff75730982007-11-07 04:08:17 +0000704 buf += cls->getDecl()->getName();
Steve Naroff21867b12007-11-07 18:43:40 +0000705 buf += "\"), (struct objc_object *)_caught)) { ";
Steve Naroff75730982007-11-07 04:08:17 +0000706 Rewrite.ReplaceText(startLoc, lParenLoc-startBuf+1,
707 buf.c_str(), buf.size());
708 }
709 }
710 // Now rewrite the body...
711 lastCatchBody = catchList->getCatchBody();
712 SourceLocation rParenLoc = catchList->getRParenLoc();
713 SourceLocation bodyLoc = lastCatchBody->getLocStart();
714 const char *bodyBuf = SM->getCharacterData(bodyLoc);
715 const char *rParenBuf = SM->getCharacterData(rParenLoc);
716 assert((*rParenBuf == ')') && "bogus @catch paren location");
717 assert((*bodyBuf == '{') && "bogus @catch body location");
718
719 buf = " = _caught;";
720 // Here we replace ") {" with "= _caught;" (which initializes and
721 // declares the @catch parameter).
722 Rewrite.ReplaceText(rParenLoc, bodyBuf-rParenBuf+1,
723 buf.c_str(), buf.size());
Steve Naroff2bd03922007-11-07 15:32:26 +0000724 } else if (!isa<NullStmt>(catchStmt)) {
Steve Naroff75730982007-11-07 04:08:17 +0000725 assert(false && "@catch rewrite bug");
Steve Naroff2bd03922007-11-07 15:32:26 +0000726 }
Steve Naroff75730982007-11-07 04:08:17 +0000727 catchList = catchList->getNextCatchStmt();
728 }
729 // Complete the catch list...
730 if (lastCatchBody) {
731 SourceLocation bodyLoc = lastCatchBody->getLocEnd();
732 const char *bodyBuf = SM->getCharacterData(bodyLoc);
733 assert((*bodyBuf == '}') && "bogus @catch body location");
734 bodyLoc = bodyLoc.getFileLocWithOffset(1);
735 buf = " } } /* @catch end */\n";
736
Chris Lattner28d1fe82007-11-08 04:41:51 +0000737 Rewrite.InsertText(bodyLoc, buf.c_str(), buf.size());
Steve Naroff75730982007-11-07 04:08:17 +0000738
739 // Set lastCurlyLoc
740 lastCurlyLoc = lastCatchBody->getLocEnd();
741 }
742 if (ObjcAtFinallyStmt *finalStmt = S->getFinallyStmt()) {
743 startLoc = finalStmt->getLocStart();
744 startBuf = SM->getCharacterData(startLoc);
745 assert((*startBuf == '@') && "bogus @finally start");
746
747 buf = "/* @finally */";
748 Rewrite.ReplaceText(startLoc, 8, buf.c_str(), buf.size());
749
750 Stmt *body = finalStmt->getFinallyBody();
751 SourceLocation startLoc = body->getLocStart();
752 SourceLocation endLoc = body->getLocEnd();
753 const char *startBuf = SM->getCharacterData(startLoc);
754 const char *endBuf = SM->getCharacterData(endLoc);
755 assert((*startBuf == '{') && "bogus @finally body location");
756 assert((*endBuf == '}') && "bogus @finally body location");
757
758 startLoc = startLoc.getFileLocWithOffset(1);
759 buf = " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
Chris Lattner28d1fe82007-11-08 04:41:51 +0000760 Rewrite.InsertText(startLoc, buf.c_str(), buf.size());
Steve Naroff75730982007-11-07 04:08:17 +0000761 endLoc = endLoc.getFileLocWithOffset(-1);
762 buf = " if (_rethrow) objc_exception_throw(_rethrow);\n";
Chris Lattner28d1fe82007-11-08 04:41:51 +0000763 Rewrite.InsertText(endLoc, buf.c_str(), buf.size());
Steve Naroff75730982007-11-07 04:08:17 +0000764
765 // Set lastCurlyLoc
766 lastCurlyLoc = body->getLocEnd();
767 }
768 // Now emit the final closing curly brace...
769 lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1);
770 buf = " } /* @try scope end */\n";
Chris Lattner28d1fe82007-11-08 04:41:51 +0000771 Rewrite.InsertText(lastCurlyLoc, buf.c_str(), buf.size());
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000772 return 0;
773}
774
775Stmt *RewriteTest::RewriteObjcCatchStmt(ObjcAtCatchStmt *S) {
776 return 0;
777}
778
779Stmt *RewriteTest::RewriteObjcFinallyStmt(ObjcAtFinallyStmt *S) {
780 return 0;
781}
782
Steve Naroff2bd03922007-11-07 15:32:26 +0000783// This can't be done with Rewrite.ReplaceStmt(S, ThrowExpr), since
784// the throw expression is typically a message expression that's already
785// been rewritten! (which implies the SourceLocation's are invalid).
786Stmt *RewriteTest::RewriteObjcThrowStmt(ObjcAtThrowStmt *S) {
787 // Get the start location and compute the semi location.
788 SourceLocation startLoc = S->getLocStart();
789 const char *startBuf = SM->getCharacterData(startLoc);
790
791 assert((*startBuf == '@') && "bogus @throw location");
792
793 std::string buf;
794 /* void objc_exception_throw(id) __attribute__((noreturn)); */
795 buf = "objc_exception_throw(";
796 Rewrite.ReplaceText(startLoc, 6, buf.c_str(), buf.size());
797 const char *semiBuf = strchr(startBuf, ';');
798 assert((*semiBuf == ';') && "@throw: can't find ';'");
799 SourceLocation semiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf);
800 buf = ");";
801 Rewrite.ReplaceText(semiLoc, 1, buf.c_str(), buf.size());
802 return 0;
803}
Fariborz Jahanian909f02a2007-11-05 17:47:33 +0000804
Chris Lattnere64b7772007-10-24 16:57:36 +0000805Stmt *RewriteTest::RewriteAtEncode(ObjCEncodeExpr *Exp) {
Chris Lattner01c57482007-10-17 22:35:30 +0000806 // Create a new string expression.
807 QualType StrType = Context->getPointerType(Context->CharTy);
Anders Carlsson85f9bce2007-10-29 05:01:08 +0000808 std::string StrEncoding;
809 Context->getObjcEncodingForType(Exp->getEncodedType(), StrEncoding);
810 Expr *Replacement = new StringLiteral(StrEncoding.c_str(),
811 StrEncoding.length(), false, StrType,
Chris Lattner01c57482007-10-17 22:35:30 +0000812 SourceLocation(), SourceLocation());
813 Rewrite.ReplaceStmt(Exp, Replacement);
Chris Lattnere64b7772007-10-24 16:57:36 +0000814 delete Exp;
815 return Replacement;
Chris Lattner311ff022007-10-16 22:36:42 +0000816}
817
Steve Naroffb42f8412007-11-05 14:50:49 +0000818Stmt *RewriteTest::RewriteAtSelector(ObjCSelectorExpr *Exp) {
819 assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");
820 // Create a call to sel_registerName("selName").
821 llvm::SmallVector<Expr*, 8> SelExprs;
822 QualType argType = Context->getPointerType(Context->CharTy);
823 SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
824 Exp->getSelector().getName().size(),
825 false, argType, SourceLocation(),
826 SourceLocation()));
827 CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
828 &SelExprs[0], SelExprs.size());
829 Rewrite.ReplaceStmt(Exp, SelExp);
830 delete Exp;
831 return SelExp;
832}
833
Steve Naroff934f2762007-10-24 22:48:43 +0000834CallExpr *RewriteTest::SynthesizeCallToFunctionDecl(
835 FunctionDecl *FD, Expr **args, unsigned nargs) {
Steve Naroffebf2b562007-10-23 23:50:29 +0000836 // Get the type, we will need to reference it in a couple spots.
Steve Naroff934f2762007-10-24 22:48:43 +0000837 QualType msgSendType = FD->getType();
Steve Naroffebf2b562007-10-23 23:50:29 +0000838
839 // Create a reference to the objc_msgSend() declaration.
Steve Naroff934f2762007-10-24 22:48:43 +0000840 DeclRefExpr *DRE = new DeclRefExpr(FD, msgSendType, SourceLocation());
Steve Naroffebf2b562007-10-23 23:50:29 +0000841
842 // Now, we cast the reference to a pointer to the objc_msgSend type.
Chris Lattnerf04da132007-10-24 17:06:59 +0000843 QualType pToFunc = Context->getPointerType(msgSendType);
Steve Naroffebf2b562007-10-23 23:50:29 +0000844 ImplicitCastExpr *ICE = new ImplicitCastExpr(pToFunc, DRE);
845
846 const FunctionType *FT = msgSendType->getAsFunctionType();
Chris Lattnere64b7772007-10-24 16:57:36 +0000847
Steve Naroff934f2762007-10-24 22:48:43 +0000848 return new CallExpr(ICE, args, nargs, FT->getResultType(), SourceLocation());
849}
850
Steve Naroffd5255f52007-11-01 13:24:47 +0000851static bool scanForProtocolRefs(const char *startBuf, const char *endBuf,
852 const char *&startRef, const char *&endRef) {
853 while (startBuf < endBuf) {
854 if (*startBuf == '<')
855 startRef = startBuf; // mark the start.
856 if (*startBuf == '>') {
Steve Naroff32174822007-11-09 12:50:28 +0000857 if (startRef && *startRef == '<') {
858 endRef = startBuf; // mark the end.
859 return true;
860 }
861 return false;
Steve Naroffd5255f52007-11-01 13:24:47 +0000862 }
863 startBuf++;
864 }
865 return false;
866}
867
868bool RewriteTest::needToScanForQualifiers(QualType T) {
869 // FIXME: we don't currently represent "id <Protocol>" in the type system.
870 if (T == Context->getObjcIdType())
871 return true;
872
873 if (const PointerType *pType = T->getAsPointerType()) {
Steve Naroff9165ad32007-10-31 04:38:33 +0000874 Type *pointeeType = pType->getPointeeType().getTypePtr();
875 if (isa<ObjcQualifiedInterfaceType>(pointeeType))
876 return true; // we have "Class <Protocol> *".
877 }
Steve Naroffd5255f52007-11-01 13:24:47 +0000878 return false;
879}
880
881void RewriteTest::RewriteObjcQualifiedInterfaceTypes(
882 const FunctionTypeProto *proto, FunctionDecl *FD) {
883
884 if (needToScanForQualifiers(proto->getResultType())) {
885 // Since types are unique, we need to scan the buffer.
886 SourceLocation Loc = FD->getLocation();
887
888 const char *endBuf = SM->getCharacterData(Loc);
889 const char *startBuf = endBuf;
890 while (*startBuf != ';')
891 startBuf--; // scan backward (from the decl location) for return type.
892 const char *startRef = 0, *endRef = 0;
893 if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
894 // Get the locations of the startRef, endRef.
895 SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-endBuf);
896 SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-endBuf+1);
897 // Comment out the protocol references.
Chris Lattner28d1fe82007-11-08 04:41:51 +0000898 Rewrite.InsertText(LessLoc, "/*", 2);
899 Rewrite.InsertText(GreaterLoc, "*/", 2);
Steve Naroff9165ad32007-10-31 04:38:33 +0000900 }
901 }
Steve Naroffd5255f52007-11-01 13:24:47 +0000902 // Now check arguments.
903 for (unsigned i = 0; i < proto->getNumArgs(); i++) {
904 if (needToScanForQualifiers(proto->getArgType(i))) {
905 // Since types are unique, we need to scan the buffer.
906 SourceLocation Loc = FD->getLocation();
907
908 const char *startBuf = SM->getCharacterData(Loc);
909 const char *endBuf = startBuf;
910 while (*endBuf != ';')
911 endBuf++; // scan forward (from the decl location) for argument types.
912 const char *startRef = 0, *endRef = 0;
913 if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
914 // Get the locations of the startRef, endRef.
915 SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-startBuf);
916 SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-startBuf+1);
917 // Comment out the protocol references.
Chris Lattner28d1fe82007-11-08 04:41:51 +0000918 Rewrite.InsertText(LessLoc, "/*", 2);
919 Rewrite.InsertText(GreaterLoc, "*/", 2);
Steve Naroffd5255f52007-11-01 13:24:47 +0000920 }
921 }
922 }
Steve Naroff9165ad32007-10-31 04:38:33 +0000923}
924
Steve Naroff09b266e2007-10-30 23:14:51 +0000925void RewriteTest::RewriteFunctionDecl(FunctionDecl *FD) {
926 // declared in <objc/objc.h>
Steve Naroffbeaf2992007-11-03 11:27:19 +0000927 if (strcmp(FD->getName(), "sel_registerName") == 0) {
Steve Naroff09b266e2007-10-30 23:14:51 +0000928 SelGetUidFunctionDecl = FD;
Steve Naroff9165ad32007-10-31 04:38:33 +0000929 return;
930 }
931 // Check for ObjC 'id' and class types that have been adorned with protocol
932 // information (id<p>, C<p>*). The protocol references need to be rewritten!
933 const FunctionType *funcType = FD->getType()->getAsFunctionType();
934 assert(funcType && "missing function type");
Steve Naroffd5255f52007-11-01 13:24:47 +0000935 if (const FunctionTypeProto *proto = dyn_cast<FunctionTypeProto>(funcType))
936 RewriteObjcQualifiedInterfaceTypes(proto, FD);
Steve Naroff09b266e2007-10-30 23:14:51 +0000937}
938
939// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
940void RewriteTest::SynthMsgSendFunctionDecl() {
941 IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend");
942 llvm::SmallVector<QualType, 16> ArgTys;
943 QualType argT = Context->getObjcIdType();
944 assert(!argT.isNull() && "Can't find 'id' type");
945 ArgTys.push_back(argT);
946 argT = Context->getObjcSelType();
947 assert(!argT.isNull() && "Can't find 'SEL' type");
948 ArgTys.push_back(argT);
949 QualType msgSendType = Context->getFunctionType(Context->getObjcIdType(),
950 &ArgTys[0], ArgTys.size(),
951 true /*isVariadic*/);
952 MsgSendFunctionDecl = new FunctionDecl(SourceLocation(),
953 msgSendIdent, msgSendType,
954 FunctionDecl::Extern, false, 0);
955}
956
957// SynthGetClassFunctionDecl - id objc_getClass(const char *name);
958void RewriteTest::SynthGetClassFunctionDecl() {
959 IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass");
960 llvm::SmallVector<QualType, 16> ArgTys;
961 ArgTys.push_back(Context->getPointerType(
962 Context->CharTy.getQualifiedType(QualType::Const)));
963 QualType getClassType = Context->getFunctionType(Context->getObjcIdType(),
964 &ArgTys[0], ArgTys.size(),
965 false /*isVariadic*/);
966 GetClassFunctionDecl = new FunctionDecl(SourceLocation(),
967 getClassIdent, getClassType,
968 FunctionDecl::Extern, false, 0);
969}
970
Steve Naroff96984642007-11-08 14:30:50 +0000971// SynthCFStringFunctionDecl - id __builtin___CFStringMakeConstantString(const char *name);
972void RewriteTest::SynthCFStringFunctionDecl() {
973 IdentifierInfo *getClassIdent = &Context->Idents.get("__builtin___CFStringMakeConstantString");
974 llvm::SmallVector<QualType, 16> ArgTys;
975 ArgTys.push_back(Context->getPointerType(
976 Context->CharTy.getQualifiedType(QualType::Const)));
977 QualType getClassType = Context->getFunctionType(Context->getObjcIdType(),
978 &ArgTys[0], ArgTys.size(),
979 false /*isVariadic*/);
980 CFStringFunctionDecl = new FunctionDecl(SourceLocation(),
981 getClassIdent, getClassType,
982 FunctionDecl::Extern, false, 0);
983}
984
Steve Naroffbeaf2992007-11-03 11:27:19 +0000985Stmt *RewriteTest::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
Steve Naroff96984642007-11-08 14:30:50 +0000986#if 1
987 // This rewrite is specific to GCC, which has builtin support for CFString.
988 if (!CFStringFunctionDecl)
989 SynthCFStringFunctionDecl();
990 // Create a call to __builtin___CFStringMakeConstantString("cstr").
991 llvm::SmallVector<Expr*, 8> StrExpr;
992 StrExpr.push_back(Exp->getString());
993 CallExpr *call = SynthesizeCallToFunctionDecl(CFStringFunctionDecl,
994 &StrExpr[0], StrExpr.size());
995 // cast to NSConstantString *
996 CastExpr *cast = new CastExpr(Exp->getType(), call, SourceLocation());
997 Rewrite.ReplaceStmt(Exp, cast);
998 delete Exp;
999 return cast;
1000#else
Steve Naroffbeaf2992007-11-03 11:27:19 +00001001 assert(ConstantStringClassReference && "Can't find constant string reference");
1002 llvm::SmallVector<Expr*, 4> InitExprs;
1003
1004 // Synthesize "(Class)&_NSConstantStringClassReference"
1005 DeclRefExpr *ClsRef = new DeclRefExpr(ConstantStringClassReference,
1006 ConstantStringClassReference->getType(),
1007 SourceLocation());
1008 QualType expType = Context->getPointerType(ClsRef->getType());
1009 UnaryOperator *Unop = new UnaryOperator(ClsRef, UnaryOperator::AddrOf,
1010 expType, SourceLocation());
1011 CastExpr *cast = new CastExpr(Context->getObjcClassType(), Unop,
1012 SourceLocation());
1013 InitExprs.push_back(cast); // set the 'isa'.
1014 InitExprs.push_back(Exp->getString()); // set "char *bytes".
1015 unsigned IntSize = static_cast<unsigned>(
1016 Context->getTypeSize(Context->IntTy, Exp->getLocStart()));
1017 llvm::APInt IntVal(IntSize, Exp->getString()->getByteLength());
1018 IntegerLiteral *len = new IntegerLiteral(IntVal, Context->IntTy,
1019 Exp->getLocStart());
1020 InitExprs.push_back(len); // set "int numBytes".
1021
1022 // struct NSConstantString
1023 QualType CFConstantStrType = Context->getCFConstantStringType();
1024 // (struct NSConstantString) { <exprs from above> }
1025 InitListExpr *ILE = new InitListExpr(SourceLocation(),
1026 &InitExprs[0], InitExprs.size(),
1027 SourceLocation());
1028 CompoundLiteralExpr *StrRep = new CompoundLiteralExpr(CFConstantStrType, ILE);
1029 // struct NSConstantString *
1030 expType = Context->getPointerType(StrRep->getType());
1031 Unop = new UnaryOperator(StrRep, UnaryOperator::AddrOf, expType,
1032 SourceLocation());
Steve Naroff352336b2007-11-05 14:36:37 +00001033 // cast to NSConstantString *
1034 cast = new CastExpr(Exp->getType(), Unop, SourceLocation());
Steve Naroffbeaf2992007-11-03 11:27:19 +00001035 Rewrite.ReplaceStmt(Exp, cast);
1036 delete Exp;
Steve Naroff352336b2007-11-05 14:36:37 +00001037 return cast;
Steve Naroff96984642007-11-08 14:30:50 +00001038#endif
Steve Naroffbeaf2992007-11-03 11:27:19 +00001039}
1040
Steve Naroff934f2762007-10-24 22:48:43 +00001041Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) {
Steve Naroffbeaf2992007-11-03 11:27:19 +00001042 assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");
Steve Naroff09b266e2007-10-30 23:14:51 +00001043 if (!MsgSendFunctionDecl)
1044 SynthMsgSendFunctionDecl();
1045 if (!GetClassFunctionDecl)
1046 SynthGetClassFunctionDecl();
Steve Naroff934f2762007-10-24 22:48:43 +00001047
1048 // Synthesize a call to objc_msgSend().
1049 llvm::SmallVector<Expr*, 8> MsgExprs;
1050 IdentifierInfo *clsName = Exp->getClassName();
1051
1052 // Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend().
1053 if (clsName) { // class message.
1054 llvm::SmallVector<Expr*, 8> ClsExprs;
1055 QualType argType = Context->getPointerType(Context->CharTy);
1056 ClsExprs.push_back(new StringLiteral(clsName->getName(),
1057 clsName->getLength(),
1058 false, argType, SourceLocation(),
1059 SourceLocation()));
1060 CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
1061 &ClsExprs[0], ClsExprs.size());
1062 MsgExprs.push_back(Cls);
Steve Naroff6568d4d2007-11-14 23:54:14 +00001063 } else { // instance message.
1064 Expr *recExpr = Exp->getReceiver();
Steve Naroff934f2762007-10-24 22:48:43 +00001065
Steve Naroff322f4d32007-11-15 00:00:21 +00001066 recExpr = new CastExpr(Context->getObjcIdType(), recExpr, SourceLocation());
Steve Naroff6568d4d2007-11-14 23:54:14 +00001067 MsgExprs.push_back(recExpr);
1068 }
Steve Naroffbeaf2992007-11-03 11:27:19 +00001069 // Create a call to sel_registerName("selName"), it will be the 2nd argument.
Steve Naroff934f2762007-10-24 22:48:43 +00001070 llvm::SmallVector<Expr*, 8> SelExprs;
1071 QualType argType = Context->getPointerType(Context->CharTy);
1072 SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
1073 Exp->getSelector().getName().size(),
1074 false, argType, SourceLocation(),
1075 SourceLocation()));
1076 CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
1077 &SelExprs[0], SelExprs.size());
1078 MsgExprs.push_back(SelExp);
1079
1080 // Now push any user supplied arguments.
1081 for (unsigned i = 0; i < Exp->getNumArgs(); i++) {
Steve Naroff6568d4d2007-11-14 23:54:14 +00001082 Expr *userExpr = Exp->getArg(i);
Steve Naroff7e3411b2007-11-15 02:58:25 +00001083 // Make all implicit casts explicit...ICE comes in handy:-)
1084 if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) {
1085 // Reuse the ICE type, it is exactly what the doctor ordered.
1086 userExpr = new CastExpr(ICE->getType(), userExpr, SourceLocation());
1087 }
Steve Naroff6568d4d2007-11-14 23:54:14 +00001088 MsgExprs.push_back(userExpr);
Steve Naroff934f2762007-10-24 22:48:43 +00001089 // We've transferred the ownership to MsgExprs. Null out the argument in
1090 // the original expression, since we will delete it below.
1091 Exp->setArg(i, 0);
1092 }
Steve Naroffab972d32007-11-04 22:37:50 +00001093 // Generate the funky cast.
1094 CastExpr *cast;
1095 llvm::SmallVector<QualType, 8> ArgTypes;
1096 QualType returnType;
1097
1098 // Push 'id' and 'SEL', the 2 implicit arguments.
1099 ArgTypes.push_back(Context->getObjcIdType());
1100 ArgTypes.push_back(Context->getObjcSelType());
1101 if (ObjcMethodDecl *mDecl = Exp->getMethodDecl()) {
1102 // Push any user argument types.
Steve Naroff352336b2007-11-05 14:36:37 +00001103 for (int i = 0; i < mDecl->getNumParams(); i++) {
1104 QualType t = mDecl->getParamDecl(i)->getType();
Steve Naroff352336b2007-11-05 14:36:37 +00001105 ArgTypes.push_back(t);
1106 }
Steve Naroffab972d32007-11-04 22:37:50 +00001107 returnType = mDecl->getResultType();
1108 } else {
1109 returnType = Context->getObjcIdType();
1110 }
1111 // Get the type, we will need to reference it in a couple spots.
1112 QualType msgSendType = MsgSendFunctionDecl->getType();
1113
1114 // Create a reference to the objc_msgSend() declaration.
1115 DeclRefExpr *DRE = new DeclRefExpr(MsgSendFunctionDecl, msgSendType, SourceLocation());
1116
1117 // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid).
1118 // If we don't do this cast, we get the following bizarre warning/note:
1119 // xx.m:13: warning: function called through a non-compatible type
1120 // xx.m:13: note: if this code is reached, the program will abort
1121 cast = new CastExpr(Context->getPointerType(Context->VoidTy), DRE,
1122 SourceLocation());
1123
1124 // Now do the "normal" pointer to function cast.
1125 QualType castType = Context->getFunctionType(returnType,
1126 &ArgTypes[0], ArgTypes.size(),
1127 false/*FIXME:variadic*/);
1128 castType = Context->getPointerType(castType);
1129 cast = new CastExpr(castType, cast, SourceLocation());
1130
1131 // Don't forget the parens to enforce the proper binding.
1132 ParenExpr *PE = new ParenExpr(SourceLocation(), SourceLocation(), cast);
1133
1134 const FunctionType *FT = msgSendType->getAsFunctionType();
1135 CallExpr *CE = new CallExpr(PE, &MsgExprs[0], MsgExprs.size(),
1136 FT->getResultType(), SourceLocation());
Steve Naroff934f2762007-10-24 22:48:43 +00001137 // Now do the actual rewrite.
Steve Naroffab972d32007-11-04 22:37:50 +00001138 Rewrite.ReplaceStmt(Exp, CE);
Steve Naroff934f2762007-10-24 22:48:43 +00001139
Chris Lattnere64b7772007-10-24 16:57:36 +00001140 delete Exp;
Steve Naroffab972d32007-11-04 22:37:50 +00001141 return CE;
Steve Naroffebf2b562007-10-23 23:50:29 +00001142}
1143
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001144/// SynthesizeObjcInternalStruct - Rewrite one internal struct corresponding to
1145/// an objective-c class with ivars.
1146void RewriteTest::SynthesizeObjcInternalStruct(ObjcInterfaceDecl *CDecl,
1147 std::string &Result) {
1148 assert(CDecl && "Class missing in SynthesizeObjcInternalStruct");
1149 assert(CDecl->getName() && "Name missing in SynthesizeObjcInternalStruct");
Fariborz Jahanian212b7682007-10-31 23:08:24 +00001150 // Do not synthesize more than once.
1151 if (ObjcSynthesizedStructs.count(CDecl))
1152 return;
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001153 ObjcInterfaceDecl *RCDecl = CDecl->getSuperClass();
1154 if (RCDecl && !ObjcSynthesizedStructs.count(RCDecl)) {
1155 // Do it for the root
1156 SynthesizeObjcInternalStruct(RCDecl, Result);
1157 }
1158
Steve Naroff03300712007-11-12 13:56:41 +00001159 int NumIvars = CDecl->getNumInstanceVariables();
Fariborz Jahanianaff56d02007-10-31 22:57:04 +00001160 // If no ivars and no root or if its root, directly or indirectly,
Fariborz Jahanianf1de0ca2007-10-31 23:53:01 +00001161 // have no ivars (thus not synthesized) then no need to synthesize this class.
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001162 if (NumIvars <= 0 && (!RCDecl || !ObjcSynthesizedStructs.count(RCDecl)))
1163 return;
Fariborz Jahanian95673922007-11-14 22:26:25 +00001164 // FIXME: This has potential of causing problem. If
1165 // SynthesizeObjcInternalStruct is ever called recursively.
Steve Narofffea763e82007-11-14 19:25:57 +00001166 Result += "\nstruct ";
1167 Result += CDecl->getName();
1168
1169 SourceLocation LocStart = CDecl->getLocStart();
1170 SourceLocation LocEnd = CDecl->getLocEnd();
1171
1172 const char *startBuf = SM->getCharacterData(LocStart);
1173 const char *endBuf = SM->getCharacterData(LocEnd);
1174
Fariborz Jahanianfdc08a02007-10-31 17:29:28 +00001175 if (NumIvars > 0) {
Steve Narofffea763e82007-11-14 19:25:57 +00001176 const char *cursor = strchr(startBuf, '{');
1177 assert((cursor && endBuf)
Fariborz Jahanianfdc08a02007-10-31 17:29:28 +00001178 && "SynthesizeObjcInternalStruct - malformed @interface");
Steve Narofffea763e82007-11-14 19:25:57 +00001179
1180 // rewrite the original header *without* disturbing the '{'
1181 Rewrite.ReplaceText(LocStart, cursor-startBuf-1,
1182 Result.c_str(), Result.size());
1183 if (RCDecl && ObjcSynthesizedStructs.count(RCDecl)) {
1184 Result = "\n struct ";
1185 Result += RCDecl->getName();
1186 Result += " _";
1187 Result += RCDecl->getName();
1188 Result += ";\n";
1189
1190 // insert the super class structure definition.
1191 SourceLocation OnePastCurly = LocStart.getFileLocWithOffset(cursor-startBuf+1);
1192 Rewrite.InsertText(OnePastCurly, Result.c_str(), Result.size());
1193 }
1194 cursor++; // past '{'
1195
1196 // Now comment out any visibility specifiers.
1197 while (cursor < endBuf) {
1198 if (*cursor == '@') {
1199 SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
Chris Lattnerdf6a51b2007-11-14 22:57:51 +00001200 // Skip whitespace.
1201 for (++cursor; cursor[0] == ' ' || cursor[0] == '\t'; ++cursor)
1202 /*scan*/;
1203
Fariborz Jahanianfdc08a02007-10-31 17:29:28 +00001204 // FIXME: presence of @public, etc. inside comment results in
1205 // this transformation as well, which is still correct c-code.
Steve Narofffea763e82007-11-14 19:25:57 +00001206 if (!strncmp(cursor, "public", strlen("public")) ||
1207 !strncmp(cursor, "private", strlen("private")) ||
Fariborz Jahanian95673922007-11-14 22:26:25 +00001208 !strncmp(cursor, "protected", strlen("protected")))
Steve Narofffea763e82007-11-14 19:25:57 +00001209 Rewrite.InsertText(atLoc, "// ", 3);
Fariborz Jahanianfdc08a02007-10-31 17:29:28 +00001210 }
Fariborz Jahanian95673922007-11-14 22:26:25 +00001211 // FIXME: If there are cases where '<' is used in ivar declaration part
1212 // of user code, then scan the ivar list and use needToScanForQualifiers
1213 // for type checking.
1214 else if (*cursor == '<') {
1215 SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
1216 Rewrite.InsertText(atLoc, "/* ", 3);
1217 cursor = strchr(cursor, '>');
1218 cursor++;
1219 atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
1220 Rewrite.InsertText(atLoc, " */", 3);
1221 }
Steve Narofffea763e82007-11-14 19:25:57 +00001222 cursor++;
Fariborz Jahanianfdc08a02007-10-31 17:29:28 +00001223 }
Steve Narofffea763e82007-11-14 19:25:57 +00001224 // Don't forget to add a ';'!!
1225 Rewrite.InsertText(LocEnd.getFileLocWithOffset(1), ";", 1);
1226 } else { // we don't have any instance variables - insert super struct.
1227 endBuf += Lexer::MeasureTokenLength(LocEnd, *SM);
1228 Result += " {\n struct ";
1229 Result += RCDecl->getName();
1230 Result += " _";
1231 Result += RCDecl->getName();
1232 Result += ";\n};\n";
1233 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
1234 Result.c_str(), Result.size());
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001235 }
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001236 // Mark this struct as having been generated.
1237 if (!ObjcSynthesizedStructs.insert(CDecl))
Fariborz Jahanianaff56d02007-10-31 22:57:04 +00001238 assert(false && "struct already synthesize- SynthesizeObjcInternalStruct");
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001239}
1240
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001241// RewriteObjcMethodsMetaData - Rewrite methods metadata for instance or
1242/// class methods.
Steve Naroff0416fb92007-11-11 17:19:15 +00001243void RewriteTest::RewriteObjcMethodsMetaData(ObjcMethodDecl *const*Methods,
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001244 int NumMethods,
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +00001245 bool IsInstanceMethod,
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001246 const char *prefix,
Chris Lattner158ecb92007-10-25 17:07:24 +00001247 const char *ClassName,
1248 std::string &Result) {
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001249 static bool objc_impl_method = false;
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001250 if (NumMethods > 0 && !objc_impl_method) {
1251 /* struct _objc_method {
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001252 SEL _cmd;
1253 char *method_types;
1254 void *_imp;
1255 }
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001256 */
Chris Lattner158ecb92007-10-25 17:07:24 +00001257 Result += "\nstruct _objc_method {\n";
1258 Result += "\tSEL _cmd;\n";
1259 Result += "\tchar *method_types;\n";
1260 Result += "\tvoid *_imp;\n";
1261 Result += "};\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001262
1263 /* struct _objc_method_list {
1264 struct _objc_method_list *next_method;
1265 int method_count;
1266 struct _objc_method method_list[];
1267 }
1268 */
1269 Result += "\nstruct _objc_method_list {\n";
1270 Result += "\tstruct _objc_method_list *next_method;\n";
1271 Result += "\tint method_count;\n";
1272 Result += "\tstruct _objc_method method_list[];\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001273 objc_impl_method = true;
Fariborz Jahanian776d6ff2007-10-19 00:36:46 +00001274 }
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001275 // Build _objc_method_list for class's methods if needed
1276 if (NumMethods > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001277 Result += "\nstatic struct _objc_method_list _OBJC_";
Chris Lattner158ecb92007-10-25 17:07:24 +00001278 Result += prefix;
1279 Result += IsInstanceMethod ? "INSTANCE" : "CLASS";
1280 Result += "_METHODS_";
1281 Result += ClassName;
1282 Result += " __attribute__ ((section (\"__OBJC, __";
1283 Result += IsInstanceMethod ? "inst" : "cls";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001284 Result += "_meth\")))= ";
1285 Result += "{\n\t0, " + utostr(NumMethods) + "\n";
1286
1287 Result += "\t,{{(SEL)\"";
1288 Result += Methods[0]->getSelector().getName().c_str();
Fariborz Jahanian33e1d642007-10-29 22:57:28 +00001289 std::string MethodTypeString;
1290 Context->getObjcEncodingForMethodDecl(Methods[0], MethodTypeString);
1291 Result += "\", \"";
1292 Result += MethodTypeString;
Fariborz Jahanianb7908b52007-11-13 21:02:00 +00001293 Result += "\", ";
1294 Result += MethodInternalNames[Methods[0]];
1295 Result += "}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001296 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001297 Result += "\t ,{(SEL)\"";
1298 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanian33e1d642007-10-29 22:57:28 +00001299 std::string MethodTypeString;
1300 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
1301 Result += "\", \"";
1302 Result += MethodTypeString;
Fariborz Jahanianb7908b52007-11-13 21:02:00 +00001303 Result += "\", ";
1304 Result += MethodInternalNames[Methods[i]];
1305 Result += "}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001306 }
1307 Result += "\t }\n};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001308 }
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001309}
1310
1311/// RewriteObjcProtocolsMetaData - Rewrite protocols meta-data.
1312void RewriteTest::RewriteObjcProtocolsMetaData(ObjcProtocolDecl **Protocols,
1313 int NumProtocols,
1314 const char *prefix,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001315 const char *ClassName,
1316 std::string &Result) {
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001317 static bool objc_protocol_methods = false;
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001318 if (NumProtocols > 0) {
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001319 for (int i = 0; i < NumProtocols; i++) {
1320 ObjcProtocolDecl *PDecl = Protocols[i];
1321 // Output struct protocol_methods holder of method selector and type.
1322 if (!objc_protocol_methods &&
1323 (PDecl->getNumInstanceMethods() > 0
1324 || PDecl->getNumClassMethods() > 0)) {
1325 /* struct protocol_methods {
1326 SEL _cmd;
1327 char *method_types;
1328 }
1329 */
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001330 Result += "\nstruct protocol_methods {\n";
1331 Result += "\tSEL _cmd;\n";
1332 Result += "\tchar *method_types;\n";
1333 Result += "};\n";
1334
1335 /* struct _objc_protocol_method_list {
1336 int protocol_method_count;
1337 struct protocol_methods protocols[];
1338 }
1339 */
1340 Result += "\nstruct _objc_protocol_method_list {\n";
1341 Result += "\tint protocol_method_count;\n";
1342 Result += "\tstruct protocol_methods protocols[];\n};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001343 objc_protocol_methods = true;
1344 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001345
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001346 // Output instance methods declared in this protocol.
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001347 int NumMethods = PDecl->getNumInstanceMethods();
1348 if (NumMethods > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001349 Result += "\nstatic struct _objc_protocol_method_list "
1350 "_OBJC_PROTOCOL_INSTANCE_METHODS_";
1351 Result += PDecl->getName();
1352 Result += " __attribute__ ((section (\"__OBJC, __cat_inst_meth\")))= "
1353 "{\n\t" + utostr(NumMethods) + "\n";
1354
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001355 ObjcMethodDecl **Methods = PDecl->getInstanceMethods();
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001356 Result += "\t,{{(SEL)\"";
1357 Result += Methods[0]->getSelector().getName().c_str();
1358 Result += "\", \"\"}\n";
1359
1360 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001361 Result += "\t ,{(SEL)\"";
1362 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanian33e1d642007-10-29 22:57:28 +00001363 std::string MethodTypeString;
1364 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
1365 Result += "\", \"";
1366 Result += MethodTypeString;
1367 Result += "\"}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001368 }
1369 Result += "\t }\n};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001370 }
1371
1372 // Output class methods declared in this protocol.
1373 NumMethods = PDecl->getNumClassMethods();
1374 if (NumMethods > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001375 Result += "\nstatic struct _objc_protocol_method_list "
1376 "_OBJC_PROTOCOL_CLASS_METHODS_";
1377 Result += PDecl->getName();
1378 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
1379 "{\n\t";
1380 Result += utostr(NumMethods);
1381 Result += "\n";
1382
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001383 ObjcMethodDecl **Methods = PDecl->getClassMethods();
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001384 Result += "\t,{{(SEL)\"";
1385 Result += Methods[0]->getSelector().getName().c_str();
1386 Result += "\", \"\"}\n";
1387
1388 for (int i = 1; i < NumMethods; i++) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001389 Result += "\t ,{(SEL)\"";
1390 Result += Methods[i]->getSelector().getName().c_str();
Fariborz Jahanian33e1d642007-10-29 22:57:28 +00001391 std::string MethodTypeString;
1392 Context->getObjcEncodingForMethodDecl(Methods[i], MethodTypeString);
1393 Result += "\", \"";
1394 Result += MethodTypeString;
1395 Result += "\"}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001396 }
1397 Result += "\t }\n};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001398 }
1399 // Output:
1400 /* struct _objc_protocol {
1401 // Objective-C 1.0 extensions
1402 struct _objc_protocol_extension *isa;
1403 char *protocol_name;
1404 struct _objc_protocol **protocol_list;
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001405 struct _objc_protocol_method_list *instance_methods;
1406 struct _objc_protocol_method_list *class_methods;
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001407 };
1408 */
1409 static bool objc_protocol = false;
1410 if (!objc_protocol) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001411 Result += "\nstruct _objc_protocol {\n";
1412 Result += "\tstruct _objc_protocol_extension *isa;\n";
1413 Result += "\tchar *protocol_name;\n";
1414 Result += "\tstruct _objc_protocol **protocol_list;\n";
1415 Result += "\tstruct _objc_protocol_method_list *instance_methods;\n";
1416 Result += "\tstruct _objc_protocol_method_list *class_methods;\n";
1417 Result += "};\n";
1418
1419 /* struct _objc_protocol_list {
1420 struct _objc_protocol_list *next;
1421 int protocol_count;
1422 struct _objc_protocol *class_protocols[];
1423 }
1424 */
1425 Result += "\nstruct _objc_protocol_list {\n";
1426 Result += "\tstruct _objc_protocol_list *next;\n";
1427 Result += "\tint protocol_count;\n";
1428 Result += "\tstruct _objc_protocol *class_protocols[];\n";
1429 Result += "};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001430 objc_protocol = true;
1431 }
1432
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001433 Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_";
1434 Result += PDecl->getName();
1435 Result += " __attribute__ ((section (\"__OBJC, __protocol\")))= "
1436 "{\n\t0, \"";
1437 Result += PDecl->getName();
1438 Result += "\", 0, ";
1439 if (PDecl->getInstanceMethods() > 0) {
1440 Result += "&_OBJC_PROTOCOL_INSTANCE_METHODS_";
1441 Result += PDecl->getName();
1442 Result += ", ";
1443 }
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001444 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001445 Result += "0, ";
1446 if (PDecl->getClassMethods() > 0) {
1447 Result += "&_OBJC_PROTOCOL_CLASS_METHODS_";
1448 Result += PDecl->getName();
1449 Result += "\n";
1450 }
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001451 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001452 Result += "0\n";
1453 Result += "};\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001454 }
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001455 // Output the top lovel protocol meta-data for the class.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001456 Result += "\nstatic struct _objc_protocol_list _OBJC_";
1457 Result += prefix;
1458 Result += "_PROTOCOLS_";
1459 Result += ClassName;
1460 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
1461 "{\n\t0, ";
1462 Result += utostr(NumProtocols);
1463 Result += "\n";
1464
1465 Result += "\t,{&_OBJC_PROTOCOL_";
1466 Result += Protocols[0]->getName();
1467 Result += " \n";
1468
1469 for (int i = 1; i < NumProtocols; i++) {
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001470 ObjcProtocolDecl *PDecl = Protocols[i];
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001471 Result += "\t ,&_OBJC_PROTOCOL_";
1472 Result += PDecl->getName();
1473 Result += "\n";
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001474 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001475 Result += "\t }\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001476 }
1477}
1478
1479/// RewriteObjcCategoryImplDecl - Rewrite metadata for each category
1480/// implementation.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001481void RewriteTest::RewriteObjcCategoryImplDecl(ObjcCategoryImplDecl *IDecl,
1482 std::string &Result) {
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001483 ObjcInterfaceDecl *ClassDecl = IDecl->getClassInterface();
1484 // Find category declaration for this implementation.
1485 ObjcCategoryDecl *CDecl;
1486 for (CDecl = ClassDecl->getCategoryList(); CDecl;
1487 CDecl = CDecl->getNextClassCategory())
1488 if (CDecl->getIdentifier() == IDecl->getIdentifier())
1489 break;
Fariborz Jahanianbac97d42007-11-13 22:09:49 +00001490
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001491 char *FullCategoryName = (char*)alloca(
1492 strlen(ClassDecl->getName()) + strlen(IDecl->getName()) + 2);
1493 sprintf(FullCategoryName, "%s_%s", ClassDecl->getName(), IDecl->getName());
1494
1495 // Build _objc_method_list for class's instance methods if needed
1496 RewriteObjcMethodsMetaData(IDecl->getInstanceMethods(),
1497 IDecl->getNumInstanceMethods(),
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +00001498 true,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001499 "CATEGORY_", FullCategoryName, Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001500
1501 // Build _objc_method_list for class's class methods if needed
1502 RewriteObjcMethodsMetaData(IDecl->getClassMethods(),
1503 IDecl->getNumClassMethods(),
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +00001504 false,
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001505 "CATEGORY_", FullCategoryName, Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001506
1507 // Protocols referenced in class declaration?
Fariborz Jahanianbac97d42007-11-13 22:09:49 +00001508 // Null CDecl is case of a category implementation with no category interface
1509 if (CDecl)
1510 RewriteObjcProtocolsMetaData(CDecl->getReferencedProtocols(),
1511 CDecl->getNumReferencedProtocols(),
1512 "CATEGORY",
1513 FullCategoryName, Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001514
1515 /* struct _objc_category {
1516 char *category_name;
1517 char *class_name;
1518 struct _objc_method_list *instance_methods;
1519 struct _objc_method_list *class_methods;
1520 struct _objc_protocol_list *protocols;
1521 // Objective-C 1.0 extensions
1522 uint32_t size; // sizeof (struct _objc_category)
1523 struct _objc_property_list *instance_properties; // category's own
1524 // @property decl.
1525 };
1526 */
1527
1528 static bool objc_category = false;
1529 if (!objc_category) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001530 Result += "\nstruct _objc_category {\n";
1531 Result += "\tchar *category_name;\n";
1532 Result += "\tchar *class_name;\n";
1533 Result += "\tstruct _objc_method_list *instance_methods;\n";
1534 Result += "\tstruct _objc_method_list *class_methods;\n";
1535 Result += "\tstruct _objc_protocol_list *protocols;\n";
1536 Result += "\tunsigned int size;\n";
1537 Result += "\tstruct _objc_property_list *instance_properties;\n";
1538 Result += "};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001539 objc_category = true;
Fariborz Jahaniane887c092007-10-22 21:41:37 +00001540 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001541 Result += "\nstatic struct _objc_category _OBJC_CATEGORY_";
1542 Result += FullCategoryName;
1543 Result += " __attribute__ ((section (\"__OBJC, __category\")))= {\n\t\"";
1544 Result += IDecl->getName();
1545 Result += "\"\n\t, \"";
1546 Result += ClassDecl->getName();
1547 Result += "\"\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001548
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001549 if (IDecl->getNumInstanceMethods() > 0) {
1550 Result += "\t, (struct _objc_method_list *)"
1551 "&_OBJC_CATEGORY_INSTANCE_METHODS_";
1552 Result += FullCategoryName;
1553 Result += "\n";
1554 }
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001555 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001556 Result += "\t, 0\n";
1557 if (IDecl->getNumClassMethods() > 0) {
1558 Result += "\t, (struct _objc_method_list *)"
1559 "&_OBJC_CATEGORY_CLASS_METHODS_";
1560 Result += FullCategoryName;
1561 Result += "\n";
1562 }
1563 else
1564 Result += "\t, 0\n";
1565
Fariborz Jahanianbac97d42007-11-13 22:09:49 +00001566 if (CDecl && CDecl->getNumReferencedProtocols() > 0) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001567 Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";
1568 Result += FullCategoryName;
1569 Result += "\n";
1570 }
1571 else
1572 Result += "\t, 0\n";
1573 Result += "\t, sizeof(struct _objc_category), 0\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001574}
1575
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001576/// SynthesizeIvarOffsetComputation - This rutine synthesizes computation of
1577/// ivar offset.
1578void RewriteTest::SynthesizeIvarOffsetComputation(ObjcImplementationDecl *IDecl,
1579 ObjcIvarDecl *ivar,
1580 std::string &Result) {
Fariborz Jahanian909f02a2007-11-05 17:47:33 +00001581 Result += "offsetof(struct ";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001582 Result += IDecl->getName();
1583 Result += ", ";
1584 Result += ivar->getName();
1585 Result += ")";
1586}
1587
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001588//===----------------------------------------------------------------------===//
1589// Meta Data Emission
1590//===----------------------------------------------------------------------===//
1591
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001592void RewriteTest::RewriteObjcClassMetaData(ObjcImplementationDecl *IDecl,
1593 std::string &Result) {
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001594 ObjcInterfaceDecl *CDecl = IDecl->getClassInterface();
1595
1596 // Build _objc_ivar_list metadata for classes ivars if needed
1597 int NumIvars = IDecl->getImplDeclNumIvars() > 0
1598 ? IDecl->getImplDeclNumIvars()
Steve Naroff03300712007-11-12 13:56:41 +00001599 : (CDecl ? CDecl->getNumInstanceVariables() : 0);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001600
Fariborz Jahanian4d733d32007-10-26 23:09:28 +00001601 SynthesizeObjcInternalStruct(CDecl, Result);
1602
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001603 if (NumIvars > 0) {
1604 static bool objc_ivar = false;
1605 if (!objc_ivar) {
1606 /* struct _objc_ivar {
1607 char *ivar_name;
1608 char *ivar_type;
1609 int ivar_offset;
1610 };
1611 */
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001612 Result += "\nstruct _objc_ivar {\n";
1613 Result += "\tchar *ivar_name;\n";
1614 Result += "\tchar *ivar_type;\n";
1615 Result += "\tint ivar_offset;\n";
1616 Result += "};\n";
1617
1618 /* struct _objc_ivar_list {
1619 int ivar_count;
1620 struct _objc_ivar ivar_list[];
1621 };
1622 */
1623 Result += "\nstruct _objc_ivar_list {\n";
1624 Result += "\tint ivar_count;\n";
1625 Result += "\tstruct _objc_ivar ivar_list[];\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001626 objc_ivar = true;
1627 }
1628
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001629 Result += "\nstatic struct _objc_ivar_list _OBJC_INSTANCE_VARIABLES_";
1630 Result += IDecl->getName();
1631 Result += " __attribute__ ((section (\"__OBJC, __instance_vars\")))= "
1632 "{\n\t";
1633 Result += utostr(NumIvars);
1634 Result += "\n";
1635
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001636 ObjcIvarDecl **Ivars = IDecl->getImplDeclIVars()
1637 ? IDecl->getImplDeclIVars()
Steve Naroff03300712007-11-12 13:56:41 +00001638 : CDecl->getInstanceVariables();
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001639 Result += "\t,{{\"";
1640 Result += Ivars[0]->getName();
Fariborz Jahanian160eb652007-10-29 17:16:25 +00001641 Result += "\", \"";
1642 std::string StrEncoding;
1643 Context->getObjcEncodingForType(Ivars[0]->getType(), StrEncoding);
1644 Result += StrEncoding;
1645 Result += "\", ";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001646 SynthesizeIvarOffsetComputation(IDecl, Ivars[0], Result);
1647 Result += "}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001648 for (int i = 1; i < NumIvars; i++) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001649 Result += "\t ,{\"";
1650 Result += Ivars[i]->getName();
Fariborz Jahanian160eb652007-10-29 17:16:25 +00001651 Result += "\", \"";
1652 std::string StrEncoding;
1653 Context->getObjcEncodingForType(Ivars[i]->getType(), StrEncoding);
1654 Result += StrEncoding;
1655 Result += "\", ";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001656 SynthesizeIvarOffsetComputation(IDecl, Ivars[i], Result);
1657 Result += "}\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001658 }
1659
1660 Result += "\t }\n};\n";
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001661 }
1662
1663 // Build _objc_method_list for class's instance methods if needed
1664 RewriteObjcMethodsMetaData(IDecl->getInstanceMethods(),
1665 IDecl->getNumInstanceMethods(),
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001666 true,
1667 "", IDecl->getName(), Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001668
1669 // Build _objc_method_list for class's class methods if needed
1670 RewriteObjcMethodsMetaData(IDecl->getClassMethods(),
Fariborz Jahanian8e991ba2007-10-25 00:14:44 +00001671 IDecl->getNumClassMethods(),
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001672 false,
1673 "", IDecl->getName(), Result);
1674
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001675 // Protocols referenced in class declaration?
1676 RewriteObjcProtocolsMetaData(CDecl->getReferencedProtocols(),
1677 CDecl->getNumIntfRefProtocols(),
1678 "CLASS",
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001679 CDecl->getName(), Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001680
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001681
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001682 // Declaration of class/meta-class metadata
1683 /* struct _objc_class {
1684 struct _objc_class *isa; // or const char *root_class_name when metadata
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001685 const char *super_class_name;
1686 char *name;
1687 long version;
1688 long info;
1689 long instance_size;
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001690 struct _objc_ivar_list *ivars;
1691 struct _objc_method_list *methods;
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001692 struct objc_cache *cache;
1693 struct objc_protocol_list *protocols;
1694 const char *ivar_layout;
1695 struct _objc_class_ext *ext;
1696 };
1697 */
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001698 static bool objc_class = false;
1699 if (!objc_class) {
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001700 Result += "\nstruct _objc_class {\n";
1701 Result += "\tstruct _objc_class *isa;\n";
1702 Result += "\tconst char *super_class_name;\n";
1703 Result += "\tchar *name;\n";
1704 Result += "\tlong version;\n";
1705 Result += "\tlong info;\n";
1706 Result += "\tlong instance_size;\n";
1707 Result += "\tstruct _objc_ivar_list *ivars;\n";
1708 Result += "\tstruct _objc_method_list *methods;\n";
1709 Result += "\tstruct objc_cache *cache;\n";
1710 Result += "\tstruct _objc_protocol_list *protocols;\n";
1711 Result += "\tconst char *ivar_layout;\n";
1712 Result += "\tstruct _objc_class_ext *ext;\n";
1713 Result += "};\n";
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001714 objc_class = true;
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001715 }
1716
1717 // Meta-class metadata generation.
1718 ObjcInterfaceDecl *RootClass = 0;
1719 ObjcInterfaceDecl *SuperClass = CDecl->getSuperClass();
1720 while (SuperClass) {
1721 RootClass = SuperClass;
1722 SuperClass = SuperClass->getSuperClass();
1723 }
1724 SuperClass = CDecl->getSuperClass();
1725
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001726 Result += "\nstatic struct _objc_class _OBJC_METACLASS_";
1727 Result += CDecl->getName();
1728 Result += " __attribute__ ((section (\"__OBJC, __meta_class\")))= "
1729 "{\n\t(struct _objc_class *)\"";
1730 Result += (RootClass ? RootClass->getName() : CDecl->getName());
1731 Result += "\"";
1732
1733 if (SuperClass) {
1734 Result += ", \"";
1735 Result += SuperClass->getName();
1736 Result += "\", \"";
1737 Result += CDecl->getName();
1738 Result += "\"";
1739 }
1740 else {
1741 Result += ", 0, \"";
1742 Result += CDecl->getName();
1743 Result += "\"";
1744 }
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001745 // TODO: 'ivars' field for root class is currently set to 0.
1746 // 'info' field is initialized to CLS_META(2) for metaclass
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001747 Result += ", 0,2, sizeof(struct _objc_class), 0";
1748 if (CDecl->getNumClassMethods() > 0) {
1749 Result += "\n\t, &_OBJC_CLASS_METHODS_";
1750 Result += CDecl->getName();
1751 Result += "\n";
1752 }
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001753 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001754 Result += ", 0\n";
1755 if (CDecl->getNumIntfRefProtocols() > 0) {
1756 Result += "\t,0, &_OBJC_CLASS_PROTOCOLS_";
1757 Result += CDecl->getName();
1758 Result += ",0,0\n";
1759 }
Fariborz Jahanian454cb012007-10-24 20:54:23 +00001760 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001761 Result += "\t,0,0,0,0\n";
1762 Result += "};\n";
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001763
1764 // class metadata generation.
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001765 Result += "\nstatic struct _objc_class _OBJC_CLASS_";
1766 Result += CDecl->getName();
1767 Result += " __attribute__ ((section (\"__OBJC, __class\")))= "
1768 "{\n\t&_OBJC_METACLASS_";
1769 Result += CDecl->getName();
1770 if (SuperClass) {
1771 Result += ", \"";
1772 Result += SuperClass->getName();
1773 Result += "\", \"";
1774 Result += CDecl->getName();
1775 Result += "\"";
1776 }
1777 else {
1778 Result += ", 0, \"";
1779 Result += CDecl->getName();
1780 Result += "\"";
1781 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001782 // 'info' field is initialized to CLS_CLASS(1) for class
Fariborz Jahanian4d733d32007-10-26 23:09:28 +00001783 Result += ", 0,1";
1784 if (!ObjcSynthesizedStructs.count(CDecl))
1785 Result += ",0";
1786 else {
1787 // class has size. Must synthesize its size.
Fariborz Jahanian909f02a2007-11-05 17:47:33 +00001788 Result += ",sizeof(struct ";
Fariborz Jahanian4d733d32007-10-26 23:09:28 +00001789 Result += CDecl->getName();
1790 Result += ")";
1791 }
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001792 if (NumIvars > 0) {
1793 Result += ", &_OBJC_INSTANCE_VARIABLES_";
1794 Result += CDecl->getName();
1795 Result += "\n\t";
1796 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001797 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001798 Result += ",0";
1799 if (IDecl->getNumInstanceMethods() > 0) {
1800 Result += ", &_OBJC_INSTANCE_METHODS_";
1801 Result += CDecl->getName();
1802 Result += ", 0\n\t";
1803 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001804 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001805 Result += ",0,0";
1806 if (CDecl->getNumIntfRefProtocols() > 0) {
1807 Result += ", &_OBJC_CLASS_PROTOCOLS_";
1808 Result += CDecl->getName();
1809 Result += ", 0,0\n";
1810 }
Fariborz Jahaniandeef5182007-10-23 18:53:48 +00001811 else
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001812 Result += ",0,0,0\n";
1813 Result += "};\n";
Fariborz Jahanian9f0a1cb2007-10-23 00:02:02 +00001814}
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00001815
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +00001816/// RewriteImplementations - This routine rewrites all method implementations
1817/// and emits meta-data.
1818
1819void RewriteTest::RewriteImplementations(std::string &Result) {
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001820 int ClsDefCount = ClassImplementation.size();
1821 int CatDefCount = CategoryImplementation.size();
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +00001822
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001823 if (ClsDefCount == 0 && CatDefCount == 0)
1824 return;
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +00001825 // Rewrite implemented methods
1826 for (int i = 0; i < ClsDefCount; i++)
1827 RewriteImplementationDecl(ClassImplementation[i]);
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00001828
Fariborz Jahanian66d6b292007-11-13 20:04:28 +00001829 for (int i = 0; i < CatDefCount; i++)
1830 RewriteImplementationDecl(CategoryImplementation[i]);
1831
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001832 // This is needed for use of offsetof
1833 Result += "#include <stddef.h>\n";
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +00001834
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001835 // For each implemented class, write out all its meta data.
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00001836 for (int i = 0; i < ClsDefCount; i++)
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001837 RewriteObjcClassMetaData(ClassImplementation[i], Result);
Fariborz Jahanian2e6d9352007-10-24 19:23:36 +00001838
1839 // For each implemented category, write out all its meta data.
1840 for (int i = 0; i < CatDefCount; i++)
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001841 RewriteObjcCategoryImplDecl(CategoryImplementation[i], Result);
Fariborz Jahanianf4d331d2007-10-18 22:09:03 +00001842
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001843 // Write objc_symtab metadata
1844 /*
1845 struct _objc_symtab
1846 {
1847 long sel_ref_cnt;
1848 SEL *refs;
1849 short cls_def_cnt;
1850 short cat_def_cnt;
1851 void *defs[cls_def_cnt + cat_def_cnt];
1852 };
1853 */
1854
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001855 Result += "\nstruct _objc_symtab {\n";
1856 Result += "\tlong sel_ref_cnt;\n";
1857 Result += "\tSEL *refs;\n";
1858 Result += "\tshort cls_def_cnt;\n";
1859 Result += "\tshort cat_def_cnt;\n";
1860 Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n";
1861 Result += "};\n\n";
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001862
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001863 Result += "static struct _objc_symtab "
1864 "_OBJC_SYMBOLS __attribute__((section (\"__OBJC, __symbols\")))= {\n";
1865 Result += "\t0, 0, " + utostr(ClsDefCount)
1866 + ", " + utostr(CatDefCount) + "\n";
1867 for (int i = 0; i < ClsDefCount; i++) {
1868 Result += "\t,&_OBJC_CLASS_";
1869 Result += ClassImplementation[i]->getName();
1870 Result += "\n";
1871 }
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001872
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001873 for (int i = 0; i < CatDefCount; i++) {
1874 Result += "\t,&_OBJC_CATEGORY_";
1875 Result += CategoryImplementation[i]->getClassInterface()->getName();
1876 Result += "_";
1877 Result += CategoryImplementation[i]->getName();
1878 Result += "\n";
1879 }
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001880
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001881 Result += "};\n\n";
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001882
1883 // Write objc_module metadata
1884
1885 /*
1886 struct _objc_module {
1887 long version;
1888 long size;
1889 const char *name;
1890 struct _objc_symtab *symtab;
1891 }
1892 */
1893
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001894 Result += "\nstruct _objc_module {\n";
1895 Result += "\tlong version;\n";
1896 Result += "\tlong size;\n";
1897 Result += "\tconst char *name;\n";
1898 Result += "\tstruct _objc_symtab *symtab;\n";
1899 Result += "};\n\n";
1900 Result += "static struct _objc_module "
1901 "_OBJC_MODULES __attribute__ ((section (\"__OBJC, __module_info\")))= {\n";
Fariborz Jahanian26e4cd32007-10-26 19:46:17 +00001902 Result += "\t" + utostr(OBJC_ABI_VERSION) +
1903 ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";
Fariborz Jahanianccd87b02007-10-25 20:55:25 +00001904 Result += "};\n\n";
Fariborz Jahanian7a3279d2007-11-13 19:21:13 +00001905
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +00001906}
Chris Lattner311ff022007-10-16 22:36:42 +00001907