blob: 4a67be7f7392a5e3a56c048029825d00b583ff22 [file] [log] [blame]
Chris Lattnerb429ae42007-10-11 00:43:27 +00001//===--- RewriteTest.cpp - Playground for the code rewriter ---------------===//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner959e5be2007-12-29 19:59:25 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Chris Lattnerb429ae42007-10-11 00:43:27 +00007//
8//===----------------------------------------------------------------------===//
9//
10// Hacks and fun related to the code rewriter.
11//
12//===----------------------------------------------------------------------===//
13
14#include "ASTConsumers.h"
Chris Lattner569faa62007-10-11 18:38:32 +000015#include "clang/Rewrite/Rewriter.h"
Chris Lattnerb429ae42007-10-11 00:43:27 +000016#include "clang/AST/AST.h"
17#include "clang/AST/ASTConsumer.h"
Chris Lattner569faa62007-10-11 18:38:32 +000018#include "clang/Basic/SourceManager.h"
Steve Naroffe9780582007-10-23 23:50:29 +000019#include "clang/Basic/IdentifierTable.h"
Chris Lattner4478db92007-11-30 22:53:43 +000020#include "clang/Basic/Diagnostic.h"
Chris Lattnerae43eb72007-12-02 01:13:47 +000021#include "clang/Lex/Lexer.h"
Chris Lattnerc3aa5c42007-10-25 17:07:24 +000022#include "llvm/ADT/StringExtras.h"
Fariborz Jahanianf185aef2007-10-26 19:46:17 +000023#include "llvm/ADT/SmallPtrSet.h"
Chris Lattnerae43eb72007-12-02 01:13:47 +000024#include "llvm/Support/MemoryBuffer.h"
Steve Naroff764c1ae2007-11-15 10:28:18 +000025#include <sstream>
Chris Lattnerb429ae42007-10-11 00:43:27 +000026using namespace clang;
Chris Lattnerc3aa5c42007-10-25 17:07:24 +000027using llvm::utostr;
Chris Lattnerb429ae42007-10-11 00:43:27 +000028
Chris Lattnerb429ae42007-10-11 00:43:27 +000029namespace {
Chris Lattner569faa62007-10-11 18:38:32 +000030 class RewriteTest : public ASTConsumer {
Chris Lattner74db1682007-10-16 21:07:07 +000031 Rewriter Rewrite;
Chris Lattner258f26c2007-11-30 22:25:36 +000032 Diagnostic &Diags;
Chris Lattnerbf0bfa62007-10-17 22:35:30 +000033 ASTContext *Context;
Chris Lattnerb429ae42007-10-11 00:43:27 +000034 SourceManager *SM;
Chris Lattner569faa62007-10-11 18:38:32 +000035 unsigned MainFileID;
Chris Lattnerae43eb72007-12-02 01:13:47 +000036 const char *MainFileStart, *MainFileEnd;
Chris Lattner74db1682007-10-16 21:07:07 +000037 SourceLocation LastIncLoc;
Ted Kremenek42730c52008-01-07 19:49:32 +000038 llvm::SmallVector<ObjCImplementationDecl *, 8> ClassImplementation;
39 llvm::SmallVector<ObjCCategoryImplDecl *, 8> CategoryImplementation;
40 llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCSynthesizedStructs;
41 llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCForwardDecls;
42 llvm::DenseMap<ObjCMethodDecl*, std::string> MethodInternalNames;
Fariborz Jahanian13dad332008-01-15 23:58:23 +000043 llvm::SmallVector<Stmt *, 32> Stmts;
44 llvm::SmallVector<int, 8> ObjCBcLabelNo;
Fariborz Jahanian248db262008-01-22 22:44:46 +000045 llvm::SmallVector<const RecordType *, 8> EncodingRecordTypes;
Steve Naroffe9780582007-10-23 23:50:29 +000046
47 FunctionDecl *MsgSendFunctionDecl;
Steve Naroff764c1ae2007-11-15 10:28:18 +000048 FunctionDecl *MsgSendSuperFunctionDecl;
Fariborz Jahanianc26b2502007-12-03 19:17:29 +000049 FunctionDecl *MsgSendStretFunctionDecl;
50 FunctionDecl *MsgSendSuperStretFunctionDecl;
Fariborz Jahanian1d29b5d2007-12-03 21:26:48 +000051 FunctionDecl *MsgSendFpretFunctionDecl;
Steve Naroffe9780582007-10-23 23:50:29 +000052 FunctionDecl *GetClassFunctionDecl;
Steve Naroff3b1caac2007-12-07 03:50:46 +000053 FunctionDecl *GetMetaClassFunctionDecl;
Steve Naroff71226032007-10-24 22:48:43 +000054 FunctionDecl *SelGetUidFunctionDecl;
Steve Naroffabb96362007-11-08 14:30:50 +000055 FunctionDecl *CFStringFunctionDecl;
Fariborz Jahanian6ff57c62007-12-07 18:47:10 +000056 FunctionDecl *GetProtocolFunctionDecl;
Fariborz Jahanianc26b2502007-12-03 19:17:29 +000057
Steve Naroff0add5d22007-11-03 11:27:19 +000058 // ObjC string constant support.
59 FileVarDecl *ConstantStringClassReference;
60 RecordDecl *NSStringRecord;
Steve Naroff0744c472007-11-04 22:37:50 +000061
Fariborz Jahanian22277422008-01-16 00:09:11 +000062 // ObjC foreach break/continue generation support.
Fariborz Jahanian13dad332008-01-15 23:58:23 +000063 int BcLabelCount;
64
Steve Naroff764c1ae2007-11-15 10:28:18 +000065 // Needed for super.
Ted Kremenek42730c52008-01-07 19:49:32 +000066 ObjCMethodDecl *CurMethodDecl;
Steve Naroff764c1ae2007-11-15 10:28:18 +000067 RecordDecl *SuperStructDecl;
68
Fariborz Jahanian8d2080c2008-01-18 01:15:54 +000069 // Needed for header files being rewritten
70 bool IsHeader;
71
Fariborz Jahanian640a01f2007-10-18 19:23:00 +000072 static const int OBJC_ABI_VERSION =7 ;
Chris Lattnerb429ae42007-10-11 00:43:27 +000073 public:
Ted Kremenek17861c52007-12-19 22:51:13 +000074 void Initialize(ASTContext &context) {
Chris Lattnerbf0bfa62007-10-17 22:35:30 +000075 Context = &context;
Ted Kremenekb3ee1932007-12-11 21:27:55 +000076 SM = &Context->getSourceManager();
Steve Naroffe9780582007-10-23 23:50:29 +000077 MsgSendFunctionDecl = 0;
Steve Naroff764c1ae2007-11-15 10:28:18 +000078 MsgSendSuperFunctionDecl = 0;
Fariborz Jahanianc26b2502007-12-03 19:17:29 +000079 MsgSendStretFunctionDecl = 0;
80 MsgSendSuperStretFunctionDecl = 0;
Fariborz Jahanian1d29b5d2007-12-03 21:26:48 +000081 MsgSendFpretFunctionDecl = 0;
Steve Naroff95b28c12007-10-24 01:09:48 +000082 GetClassFunctionDecl = 0;
Steve Naroff3b1caac2007-12-07 03:50:46 +000083 GetMetaClassFunctionDecl = 0;
Steve Naroff71226032007-10-24 22:48:43 +000084 SelGetUidFunctionDecl = 0;
Steve Naroffabb96362007-11-08 14:30:50 +000085 CFStringFunctionDecl = 0;
Fariborz Jahanian6ff57c62007-12-07 18:47:10 +000086 GetProtocolFunctionDecl = 0;
Steve Naroff0add5d22007-11-03 11:27:19 +000087 ConstantStringClassReference = 0;
88 NSStringRecord = 0;
Steve Naroff764c1ae2007-11-15 10:28:18 +000089 CurMethodDecl = 0;
90 SuperStructDecl = 0;
Fariborz Jahanian13dad332008-01-15 23:58:23 +000091 BcLabelCount = 0;
Steve Naroff764c1ae2007-11-15 10:28:18 +000092
Chris Lattnerae43eb72007-12-02 01:13:47 +000093 // Get the ID and start/end of the main file.
Ted Kremenek17861c52007-12-19 22:51:13 +000094 MainFileID = SM->getMainFileID();
Chris Lattnerae43eb72007-12-02 01:13:47 +000095 const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID);
96 MainFileStart = MainBuf->getBufferStart();
97 MainFileEnd = MainBuf->getBufferEnd();
98
99
Ted Kremenekb3ee1932007-12-11 21:27:55 +0000100 Rewrite.setSourceMgr(Context->getSourceManager());
Steve Narofffcab7932007-11-05 14:55:35 +0000101 // declaring objc_selector outside the parameter list removes a silly
102 // scope related warning...
Fariborz Jahanian8d2080c2008-01-18 01:15:54 +0000103 const char *s = "#pragma once\n"
104 "struct objc_selector; struct objc_class;\n"
Fariborz Jahanian6ff57c62007-12-07 18:47:10 +0000105 "#ifndef OBJC_SUPER\n"
106 "struct objc_super { struct objc_object *o; "
107 "struct objc_object *superClass; };\n"
108 "#define OBJC_SUPER\n"
109 "#endif\n"
110 "#ifndef _REWRITER_typedef_Protocol\n"
111 "typedef struct objc_object Protocol;\n"
112 "#define _REWRITER_typedef_Protocol\n"
113 "#endif\n"
Steve Narofffcab7932007-11-05 14:55:35 +0000114 "extern struct objc_object *objc_msgSend"
Steve Naroff0744c472007-11-04 22:37:50 +0000115 "(struct objc_object *, struct objc_selector *, ...);\n"
Steve Naroff764c1ae2007-11-15 10:28:18 +0000116 "extern struct objc_object *objc_msgSendSuper"
117 "(struct objc_super *, struct objc_selector *, ...);\n"
Fariborz Jahanianc26b2502007-12-03 19:17:29 +0000118 "extern struct objc_object *objc_msgSend_stret"
119 "(struct objc_object *, struct objc_selector *, ...);\n"
120 "extern struct objc_object *objc_msgSendSuper_stret"
121 "(struct objc_super *, struct objc_selector *, ...);\n"
Fariborz Jahanian1d29b5d2007-12-03 21:26:48 +0000122 "extern struct objc_object *objc_msgSend_fpret"
123 "(struct objc_object *, struct objc_selector *, ...);\n"
Steve Naroff0744c472007-11-04 22:37:50 +0000124 "extern struct objc_object *objc_getClass"
Steve Naroffd3287d82007-11-07 18:43:40 +0000125 "(const char *);\n"
Steve Naroff3b1caac2007-12-07 03:50:46 +0000126 "extern struct objc_object *objc_getMetaClass"
127 "(const char *);\n"
Steve Naroffd3287d82007-11-07 18:43:40 +0000128 "extern void objc_exception_throw(struct objc_object *);\n"
129 "extern void objc_exception_try_enter(void *);\n"
130 "extern void objc_exception_try_exit(void *);\n"
131 "extern struct objc_object *objc_exception_extract(void *);\n"
132 "extern int objc_exception_match"
Fariborz Jahanian8d9c7352007-11-14 22:26:25 +0000133 "(struct objc_class *, struct objc_object *, ...);\n"
Fariborz Jahanian6ff57c62007-12-07 18:47:10 +0000134 "extern Protocol *objc_getProtocol(const char *);\n"
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +0000135 "#include <objc/objc.h>\n"
Fariborz Jahaniand8d36532008-01-10 23:04:06 +0000136 "#ifndef __FASTENUMERATIONSTATE\n"
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +0000137 "struct __objcFastEnumerationState {\n\t"
138 "unsigned long state;\n\t"
139 "id *itemsPtr;\n\t"
140 "unsigned long *mutationsPtr;\n\t"
Fariborz Jahaniand8d36532008-01-10 23:04:06 +0000141 "unsigned long extra[5];\n};\n"
142 "#define __FASTENUMERATIONSTATE\n"
143 "#endif\n";
Fariborz Jahanian8d2080c2008-01-18 01:15:54 +0000144 if (IsHeader) {
145 // insert the whole string when rewriting a header file
146 Rewrite.InsertText(SourceLocation::getFileLoc(MainFileID, 0),
147 s, strlen(s));
148 }
149 else {
150 // Not rewriting header, exclude the #pragma once pragma
151 const char *p = s + strlen("#pragma once\n");
152 Rewrite.InsertText(SourceLocation::getFileLoc(MainFileID, 0),
153 p, strlen(p));
154 }
Chris Lattnerb429ae42007-10-11 00:43:27 +0000155 }
Chris Lattner569faa62007-10-11 18:38:32 +0000156
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000157 // Top Level Driver code.
158 virtual void HandleTopLevelDecl(Decl *D);
Chris Lattner74db1682007-10-16 21:07:07 +0000159 void HandleDeclInMainFile(Decl *D);
Fariborz Jahanian8d2080c2008-01-18 01:15:54 +0000160 RewriteTest(bool isHeader, Diagnostic &D) : Diags(D) {IsHeader = isHeader;}
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000161 ~RewriteTest();
162
163 // Syntactic Rewriting.
Steve Naroff0744c472007-11-04 22:37:50 +0000164 void RewritePrologue(SourceLocation Loc);
Fariborz Jahaniana42227a2008-01-19 00:30:35 +0000165 void RewriteInclude();
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000166 void RewriteTabs();
Ted Kremenek42730c52008-01-07 19:49:32 +0000167 void RewriteForwardClassDecl(ObjCClassDecl *Dcl);
168 void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl);
Fariborz Jahanian0136e372007-11-13 20:04:28 +0000169 void RewriteImplementationDecl(NamedDecl *Dcl);
Ted Kremenek42730c52008-01-07 19:49:32 +0000170 void RewriteObjCMethodDecl(ObjCMethodDecl *MDecl, std::string &ResultStr);
171 void RewriteCategoryDecl(ObjCCategoryDecl *Dcl);
172 void RewriteProtocolDecl(ObjCProtocolDecl *Dcl);
173 void RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *Dcl);
174 void RewriteMethodDeclaration(ObjCMethodDecl *Method);
175 void RewriteProperties(int nProperties, ObjCPropertyDecl **Properties);
Steve Naroff02a82aa2007-10-30 23:14:51 +0000176 void RewriteFunctionDecl(FunctionDecl *FD);
Ted Kremenek42730c52008-01-07 19:49:32 +0000177 void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl);
Steve Naroffc8a92d12007-11-01 13:24:47 +0000178 bool needToScanForQualifiers(QualType T);
Ted Kremenek42730c52008-01-07 19:49:32 +0000179 ObjCInterfaceDecl *isSuperReceiver(Expr *recExpr);
Steve Naroff764c1ae2007-11-15 10:28:18 +0000180 QualType getSuperStructType();
Chris Lattner6fe8b272007-10-16 22:36:42 +0000181
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000182 // Expression Rewriting.
Steve Naroff334fbc22007-11-09 15:20:18 +0000183 Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S);
Chris Lattner0021f452007-10-24 16:57:36 +0000184 Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
Steve Naroff6b759ce2007-11-15 02:58:25 +0000185 Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV);
Steve Naroff296b74f2007-11-05 14:50:49 +0000186 Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp);
Chris Lattner0021f452007-10-24 16:57:36 +0000187 Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
Steve Naroff0add5d22007-11-03 11:27:19 +0000188 Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp);
Fariborz Jahanian6ff57c62007-12-07 18:47:10 +0000189 Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp);
Ted Kremenek42730c52008-01-07 19:49:32 +0000190 Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S);
191 Stmt *RewriteObjCCatchStmt(ObjCAtCatchStmt *S);
192 Stmt *RewriteObjCFinallyStmt(ObjCAtFinallyStmt *S);
193 Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S);
Fariborz Jahanian955fcb82008-01-07 21:40:22 +0000194 Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S);
Steve Naroff71226032007-10-24 22:48:43 +0000195 CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD,
196 Expr **args, unsigned nargs);
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +0000197 Stmt *SynthMessageExpr(ObjCMessageExpr *Exp);
Fariborz Jahanian13dad332008-01-15 23:58:23 +0000198 Stmt *RewriteBreakStmt(BreakStmt *S);
199 Stmt *RewriteContinueStmt(ContinueStmt *S);
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +0000200 void SynthCountByEnumWithState(std::string &buf);
201
Steve Naroff02a82aa2007-10-30 23:14:51 +0000202 void SynthMsgSendFunctionDecl();
Steve Naroff764c1ae2007-11-15 10:28:18 +0000203 void SynthMsgSendSuperFunctionDecl();
Fariborz Jahanianc26b2502007-12-03 19:17:29 +0000204 void SynthMsgSendStretFunctionDecl();
Fariborz Jahanian1d29b5d2007-12-03 21:26:48 +0000205 void SynthMsgSendFpretFunctionDecl();
Fariborz Jahanianc26b2502007-12-03 19:17:29 +0000206 void SynthMsgSendSuperStretFunctionDecl();
Steve Naroff02a82aa2007-10-30 23:14:51 +0000207 void SynthGetClassFunctionDecl();
Steve Naroff3b1caac2007-12-07 03:50:46 +0000208 void SynthGetMetaClassFunctionDecl();
Steve Naroffabb96362007-11-08 14:30:50 +0000209 void SynthCFStringFunctionDecl();
Fariborz Jahanianfb8e9912007-12-04 21:47:40 +0000210 void SynthSelGetUidFunctionDecl();
Fariborz Jahanian6ff57c62007-12-07 18:47:10 +0000211 void SynthGetProtocolFunctionDecl();
Steve Naroffabb96362007-11-08 14:30:50 +0000212
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000213 // Metadata emission.
Ted Kremenek42730c52008-01-07 19:49:32 +0000214 void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000215 std::string &Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000216
Ted Kremenek42730c52008-01-07 19:49:32 +0000217 void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl,
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000218 std::string &Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000219
Ted Kremenek42730c52008-01-07 19:49:32 +0000220 typedef ObjCCategoryImplDecl::instmeth_iterator instmeth_iterator;
221 void RewriteObjCMethodsMetaData(instmeth_iterator MethodBegin,
Chris Lattnerdea5bec2007-12-12 07:46:12 +0000222 instmeth_iterator MethodEnd,
Fariborz Jahaniana3986372007-10-25 00:14:44 +0000223 bool IsInstanceMethod,
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000224 const char *prefix,
Chris Lattnerc3aa5c42007-10-25 17:07:24 +0000225 const char *ClassName,
226 std::string &Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000227
Ted Kremenek42730c52008-01-07 19:49:32 +0000228 void RewriteObjCProtocolsMetaData(ObjCProtocolDecl **Protocols,
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +0000229 int NumProtocols,
230 const char *prefix,
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +0000231 const char *ClassName,
232 std::string &Result);
Ted Kremenek42730c52008-01-07 19:49:32 +0000233 void SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
Fariborz Jahanianf185aef2007-10-26 19:46:17 +0000234 std::string &Result);
Ted Kremenek42730c52008-01-07 19:49:32 +0000235 void SynthesizeIvarOffsetComputation(ObjCImplementationDecl *IDecl,
236 ObjCIvarDecl *ivar,
Fariborz Jahanianf185aef2007-10-26 19:46:17 +0000237 std::string &Result);
Fariborz Jahanian8c664912007-11-13 19:21:13 +0000238 void RewriteImplementations(std::string &Result);
Chris Lattnerb429ae42007-10-11 00:43:27 +0000239 };
240}
241
Fariborz Jahanian8d2080c2008-01-18 01:15:54 +0000242static bool IsHeaderFile(const std::string &Filename) {
243 std::string::size_type DotPos = Filename.rfind('.');
244
245 if (DotPos == std::string::npos) {
246 // no file extension
247 return false;
248 }
249
250 std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end());
251 // C header: .h
252 // C++ header: .hh or .H;
253 return Ext == "h" || Ext == "hh" || Ext == "H";
254}
255
256ASTConsumer *clang::CreateCodeRewriterTest(const std::string& InFile,
257 Diagnostic &Diags) {
258 return new RewriteTest(IsHeaderFile(InFile), Diags);
Chris Lattner258f26c2007-11-30 22:25:36 +0000259}
Chris Lattnerb429ae42007-10-11 00:43:27 +0000260
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000261//===----------------------------------------------------------------------===//
262// Top Level Driver Code
263//===----------------------------------------------------------------------===//
264
Chris Lattner569faa62007-10-11 18:38:32 +0000265void RewriteTest::HandleTopLevelDecl(Decl *D) {
Chris Lattner74db1682007-10-16 21:07:07 +0000266 // Two cases: either the decl could be in the main file, or it could be in a
267 // #included file. If the former, rewrite it now. If the later, check to see
268 // if we rewrote the #include/#import.
269 SourceLocation Loc = D->getLocation();
270 Loc = SM->getLogicalLoc(Loc);
271
272 // If this is for a builtin, ignore it.
273 if (Loc.isInvalid()) return;
274
Steve Naroffe9780582007-10-23 23:50:29 +0000275 // Look for built-in declarations that we need to refer during the rewrite.
276 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Steve Naroff02a82aa2007-10-30 23:14:51 +0000277 RewriteFunctionDecl(FD);
Steve Naroff0add5d22007-11-03 11:27:19 +0000278 } else if (FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
279 // declared in <Foundation/NSString.h>
280 if (strcmp(FVD->getName(), "_NSConstantStringClassReference") == 0) {
281 ConstantStringClassReference = FVD;
282 return;
283 }
Ted Kremenek42730c52008-01-07 19:49:32 +0000284 } else if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D)) {
Steve Naroff3774dd92007-10-26 20:53:56 +0000285 RewriteInterfaceDecl(MD);
Ted Kremenek42730c52008-01-07 19:49:32 +0000286 } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) {
Steve Naroff667f1682007-10-30 13:30:57 +0000287 RewriteCategoryDecl(CD);
Ted Kremenek42730c52008-01-07 19:49:32 +0000288 } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
Steve Narofff4b7d6a2007-10-30 16:42:30 +0000289 RewriteProtocolDecl(PD);
Ted Kremenek42730c52008-01-07 19:49:32 +0000290 } else if (ObjCForwardProtocolDecl *FP =
291 dyn_cast<ObjCForwardProtocolDecl>(D)){
Fariborz Jahanian016a1882007-11-14 00:42:16 +0000292 RewriteForwardProtocolDecl(FP);
Steve Naroffe9780582007-10-23 23:50:29 +0000293 }
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000294 // If we have a decl in the main file, see if we should rewrite it.
Chris Lattner74db1682007-10-16 21:07:07 +0000295 if (SM->getDecomposedFileLoc(Loc).first == MainFileID)
296 return HandleDeclInMainFile(D);
Chris Lattner74db1682007-10-16 21:07:07 +0000297}
298
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000299/// HandleDeclInMainFile - This is called for each top-level decl defined in the
300/// main file of the input.
301void RewriteTest::HandleDeclInMainFile(Decl *D) {
302 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
303 if (Stmt *Body = FD->getBody())
Steve Naroff334fbc22007-11-09 15:20:18 +0000304 FD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
Steve Naroff18c83382007-11-13 23:01:27 +0000305
Ted Kremenek42730c52008-01-07 19:49:32 +0000306 if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
Steve Naroff764c1ae2007-11-15 10:28:18 +0000307 if (Stmt *Body = MD->getBody()) {
308 //Body->dump();
309 CurMethodDecl = MD;
Steve Naroff18c83382007-11-13 23:01:27 +0000310 MD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
Steve Naroff764c1ae2007-11-15 10:28:18 +0000311 CurMethodDecl = 0;
312 }
Steve Naroff18c83382007-11-13 23:01:27 +0000313 }
Ted Kremenek42730c52008-01-07 19:49:32 +0000314 if (ObjCImplementationDecl *CI = dyn_cast<ObjCImplementationDecl>(D))
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000315 ClassImplementation.push_back(CI);
Ted Kremenek42730c52008-01-07 19:49:32 +0000316 else if (ObjCCategoryImplDecl *CI = dyn_cast<ObjCCategoryImplDecl>(D))
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000317 CategoryImplementation.push_back(CI);
Ted Kremenek42730c52008-01-07 19:49:32 +0000318 else if (ObjCClassDecl *CD = dyn_cast<ObjCClassDecl>(D))
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000319 RewriteForwardClassDecl(CD);
Steve Naroff334fbc22007-11-09 15:20:18 +0000320 else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
Ted Kremenek42730c52008-01-07 19:49:32 +0000321 RewriteObjCQualifiedInterfaceTypes(VD);
Steve Naroff334fbc22007-11-09 15:20:18 +0000322 if (VD->getInit())
323 RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
324 }
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000325 // Nothing yet.
326}
327
328RewriteTest::~RewriteTest() {
329 // Get the top-level buffer that this corresponds to.
Chris Lattner257236c2007-11-08 04:27:23 +0000330
331 // Rewrite tabs if we care.
332 //RewriteTabs();
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000333
Fariborz Jahaniana42227a2008-01-19 00:30:35 +0000334 RewriteInclude();
335
Fariborz Jahanian9447e462007-11-05 17:47:33 +0000336 // Rewrite Objective-c meta data*
337 std::string ResultStr;
Fariborz Jahanian8c664912007-11-13 19:21:13 +0000338 RewriteImplementations(ResultStr);
Fariborz Jahanian9447e462007-11-05 17:47:33 +0000339
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000340 // Get the buffer corresponding to MainFileID. If we haven't changed it, then
341 // we are done.
342 if (const RewriteBuffer *RewriteBuf =
343 Rewrite.getRewriteBufferFor(MainFileID)) {
Steve Naroff0add5d22007-11-03 11:27:19 +0000344 //printf("Changed:\n");
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000345 std::string S(RewriteBuf->begin(), RewriteBuf->end());
346 printf("%s\n", S.c_str());
347 } else {
348 printf("No changes\n");
349 }
Fariborz Jahanian70ef5462007-11-07 18:40:28 +0000350 // Emit metadata.
351 printf("%s", ResultStr.c_str());
Fariborz Jahanianf185aef2007-10-26 19:46:17 +0000352}
353
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000354//===----------------------------------------------------------------------===//
355// Syntactic (non-AST) Rewriting Code
356//===----------------------------------------------------------------------===//
357
Fariborz Jahaniana42227a2008-01-19 00:30:35 +0000358void RewriteTest::RewriteInclude() {
359 SourceLocation LocStart = SourceLocation::getFileLoc(MainFileID, 0);
360 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
361 const char *MainBufStart = MainBuf.first;
362 const char *MainBufEnd = MainBuf.second;
363 size_t ImportLen = strlen("import");
364 size_t IncludeLen = strlen("include");
365
Fariborz Jahanianc81ed742008-01-19 01:03:17 +0000366 // Loop over the whole file, looking for includes.
Fariborz Jahaniana42227a2008-01-19 00:30:35 +0000367 for (const char *BufPtr = MainBufStart; BufPtr < MainBufEnd; ++BufPtr) {
368 if (*BufPtr == '#') {
369 if (++BufPtr == MainBufEnd)
370 return;
371 while (*BufPtr == ' ' || *BufPtr == '\t')
372 if (++BufPtr == MainBufEnd)
373 return;
374 if (!strncmp(BufPtr, "import", ImportLen)) {
375 // replace import with include
376 SourceLocation ImportLoc =
377 LocStart.getFileLocWithOffset(BufPtr-MainBufStart);
378 Rewrite.ReplaceText(ImportLoc, ImportLen, "include", IncludeLen);
379 BufPtr += ImportLen;
380 }
381 }
382 }
Chris Lattner74db1682007-10-16 21:07:07 +0000383}
384
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000385void RewriteTest::RewriteTabs() {
386 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
387 const char *MainBufStart = MainBuf.first;
388 const char *MainBufEnd = MainBuf.second;
Fariborz Jahanian640a01f2007-10-18 19:23:00 +0000389
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000390 // Loop over the whole file, looking for tabs.
391 for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) {
392 if (*BufPtr != '\t')
393 continue;
394
395 // Okay, we found a tab. This tab will turn into at least one character,
396 // but it depends on which 'virtual column' it is in. Compute that now.
397 unsigned VCol = 0;
398 while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' &&
399 BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r')
400 ++VCol;
401
402 // Okay, now that we know the virtual column, we know how many spaces to
403 // insert. We assume 8-character tab-stops.
404 unsigned Spaces = 8-(VCol & 7);
405
406 // Get the location of the tab.
407 SourceLocation TabLoc =
408 SourceLocation::getFileLoc(MainFileID, BufPtr-MainBufStart);
409
410 // Rewrite the single tab character into a sequence of spaces.
411 Rewrite.ReplaceText(TabLoc, 1, " ", Spaces);
412 }
Chris Lattner569faa62007-10-11 18:38:32 +0000413}
414
415
Ted Kremenek42730c52008-01-07 19:49:32 +0000416void RewriteTest::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) {
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000417 int numDecls = ClassDecl->getNumForwardDecls();
Ted Kremenek42730c52008-01-07 19:49:32 +0000418 ObjCInterfaceDecl **ForwardDecls = ClassDecl->getForwardDecls();
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000419
420 // Get the start location and compute the semi location.
421 SourceLocation startLoc = ClassDecl->getLocation();
422 const char *startBuf = SM->getCharacterData(startLoc);
423 const char *semiPtr = strchr(startBuf, ';');
424
425 // Translate to typedef's that forward reference structs with the same name
426 // as the class. As a convenience, we include the original declaration
427 // as a comment.
428 std::string typedefString;
429 typedefString += "// ";
Steve Naroff71226032007-10-24 22:48:43 +0000430 typedefString.append(startBuf, semiPtr-startBuf+1);
431 typedefString += "\n";
432 for (int i = 0; i < numDecls; i++) {
Ted Kremenek42730c52008-01-07 19:49:32 +0000433 ObjCInterfaceDecl *ForwardDecl = ForwardDecls[i];
Steve Naroff2aeae312007-11-09 12:50:28 +0000434 typedefString += "#ifndef _REWRITER_typedef_";
435 typedefString += ForwardDecl->getName();
436 typedefString += "\n";
437 typedefString += "#define _REWRITER_typedef_";
438 typedefString += ForwardDecl->getName();
439 typedefString += "\n";
Steve Naroff4242b972007-11-05 14:36:37 +0000440 typedefString += "typedef struct objc_object ";
Steve Naroff71226032007-10-24 22:48:43 +0000441 typedefString += ForwardDecl->getName();
Steve Naroff2aeae312007-11-09 12:50:28 +0000442 typedefString += ";\n#endif\n";
Steve Naroff71226032007-10-24 22:48:43 +0000443 }
444
445 // Replace the @class with typedefs corresponding to the classes.
446 Rewrite.ReplaceText(startLoc, semiPtr-startBuf+1,
447 typedefString.c_str(), typedefString.size());
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000448}
449
Ted Kremenek42730c52008-01-07 19:49:32 +0000450void RewriteTest::RewriteMethodDeclaration(ObjCMethodDecl *Method) {
Steve Naroff2ce399a2007-12-14 23:37:57 +0000451 SourceLocation LocStart = Method->getLocStart();
452 SourceLocation LocEnd = Method->getLocEnd();
Steve Naroff667f1682007-10-30 13:30:57 +0000453
Steve Naroff2ce399a2007-12-14 23:37:57 +0000454 if (SM->getLineNumber(LocEnd) > SM->getLineNumber(LocStart)) {
455 Rewrite.InsertText(LocStart, "/* ", 3);
456 Rewrite.ReplaceText(LocEnd, 1, ";*/ ", 4);
457 } else {
458 Rewrite.InsertText(LocStart, "// ", 3);
Steve Naroff667f1682007-10-30 13:30:57 +0000459 }
460}
461
Ted Kremenek42730c52008-01-07 19:49:32 +0000462void RewriteTest::RewriteProperties(int nProperties, ObjCPropertyDecl **Properties)
Fariborz Jahanianeca7fad2007-11-07 00:09:37 +0000463{
464 for (int i = 0; i < nProperties; i++) {
Ted Kremenek42730c52008-01-07 19:49:32 +0000465 ObjCPropertyDecl *Property = Properties[i];
Fariborz Jahanianeca7fad2007-11-07 00:09:37 +0000466 SourceLocation Loc = Property->getLocation();
467
468 Rewrite.ReplaceText(Loc, 0, "// ", 3);
469
470 // FIXME: handle properties that are declared across multiple lines.
471 }
472}
473
Ted Kremenek42730c52008-01-07 19:49:32 +0000474void RewriteTest::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
Steve Naroff667f1682007-10-30 13:30:57 +0000475 SourceLocation LocStart = CatDecl->getLocStart();
476
477 // FIXME: handle category headers that are declared across multiple lines.
478 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
479
Ted Kremenek42730c52008-01-07 19:49:32 +0000480 for (ObjCCategoryDecl::instmeth_iterator I = CatDecl->instmeth_begin(),
Steve Naroff2ce399a2007-12-14 23:37:57 +0000481 E = CatDecl->instmeth_end(); I != E; ++I)
482 RewriteMethodDeclaration(*I);
Ted Kremenek42730c52008-01-07 19:49:32 +0000483 for (ObjCCategoryDecl::classmeth_iterator I = CatDecl->classmeth_begin(),
Steve Naroff2ce399a2007-12-14 23:37:57 +0000484 E = CatDecl->classmeth_end(); I != E; ++I)
485 RewriteMethodDeclaration(*I);
486
Steve Naroff667f1682007-10-30 13:30:57 +0000487 // Lastly, comment out the @end.
488 Rewrite.ReplaceText(CatDecl->getAtEndLoc(), 0, "// ", 3);
489}
490
Ted Kremenek42730c52008-01-07 19:49:32 +0000491void RewriteTest::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
Fariborz Jahanian3960e9c2007-11-14 01:37:46 +0000492 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
Fariborz Jahanian3960e9c2007-11-14 01:37:46 +0000493
Steve Narofff4b7d6a2007-10-30 16:42:30 +0000494 SourceLocation LocStart = PDecl->getLocStart();
495
496 // FIXME: handle protocol headers that are declared across multiple lines.
497 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
498
Ted Kremenek42730c52008-01-07 19:49:32 +0000499 for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(),
Steve Naroff2ce399a2007-12-14 23:37:57 +0000500 E = PDecl->instmeth_end(); I != E; ++I)
501 RewriteMethodDeclaration(*I);
Ted Kremenek42730c52008-01-07 19:49:32 +0000502 for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(),
Steve Naroff2ce399a2007-12-14 23:37:57 +0000503 E = PDecl->classmeth_end(); I != E; ++I)
504 RewriteMethodDeclaration(*I);
505
Steve Narofff4b7d6a2007-10-30 16:42:30 +0000506 // Lastly, comment out the @end.
Fariborz Jahanian3960e9c2007-11-14 01:37:46 +0000507 SourceLocation LocEnd = PDecl->getAtEndLoc();
508 Rewrite.ReplaceText(LocEnd, 0, "// ", 3);
Steve Naroff268fa592007-11-14 15:03:57 +0000509
Fariborz Jahanian3960e9c2007-11-14 01:37:46 +0000510 // Must comment out @optional/@required
511 const char *startBuf = SM->getCharacterData(LocStart);
512 const char *endBuf = SM->getCharacterData(LocEnd);
513 for (const char *p = startBuf; p < endBuf; p++) {
514 if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) {
515 std::string CommentedOptional = "/* @optional */";
Steve Naroff268fa592007-11-14 15:03:57 +0000516 SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
Fariborz Jahanian3960e9c2007-11-14 01:37:46 +0000517 Rewrite.ReplaceText(OptionalLoc, strlen("@optional"),
518 CommentedOptional.c_str(), CommentedOptional.size());
519
520 }
521 else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) {
522 std::string CommentedRequired = "/* @required */";
Steve Naroff268fa592007-11-14 15:03:57 +0000523 SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
Fariborz Jahanian3960e9c2007-11-14 01:37:46 +0000524 Rewrite.ReplaceText(OptionalLoc, strlen("@required"),
525 CommentedRequired.c_str(), CommentedRequired.size());
526
527 }
528 }
Steve Narofff4b7d6a2007-10-30 16:42:30 +0000529}
530
Ted Kremenek42730c52008-01-07 19:49:32 +0000531void RewriteTest::RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *PDecl) {
Fariborz Jahanian016a1882007-11-14 00:42:16 +0000532 SourceLocation LocStart = PDecl->getLocation();
Steve Naroff0540f3f2007-11-14 03:37:28 +0000533 if (LocStart.isInvalid())
534 assert(false && "Invalid SourceLocation");
Fariborz Jahanian016a1882007-11-14 00:42:16 +0000535 // FIXME: handle forward protocol that are declared across multiple lines.
536 Rewrite.ReplaceText(LocStart, 0, "// ", 3);
537}
538
Ted Kremenek42730c52008-01-07 19:49:32 +0000539void RewriteTest::RewriteObjCMethodDecl(ObjCMethodDecl *OMD,
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000540 std::string &ResultStr) {
541 ResultStr += "\nstatic ";
Ted Kremenek42730c52008-01-07 19:49:32 +0000542 if (OMD->getResultType()->isObjCQualifiedIdType())
Fariborz Jahaniane76e8412007-12-17 21:03:50 +0000543 ResultStr += "id";
544 else
545 ResultStr += OMD->getResultType().getAsString();
Fariborz Jahanian7202d982008-01-10 01:39:52 +0000546 ResultStr += " ";
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000547
548 // Unique method name
Fariborz Jahanianbd2fd922007-11-13 21:02:00 +0000549 std::string NameStr;
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000550
Fariborz Jahanianbd2fd922007-11-13 21:02:00 +0000551 if (OMD->isInstance())
552 NameStr += "_I_";
553 else
554 NameStr += "_C_";
555
556 NameStr += OMD->getClassInterface()->getName();
557 NameStr += "_";
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000558
559 NamedDecl *MethodContext = OMD->getMethodContext();
Ted Kremenek42730c52008-01-07 19:49:32 +0000560 if (ObjCCategoryImplDecl *CID =
561 dyn_cast<ObjCCategoryImplDecl>(MethodContext)) {
Fariborz Jahanianbd2fd922007-11-13 21:02:00 +0000562 NameStr += CID->getName();
563 NameStr += "_";
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000564 }
565 // Append selector names, replacing ':' with '_'
566 const char *selName = OMD->getSelector().getName().c_str();
567 if (!strchr(selName, ':'))
Fariborz Jahanianbd2fd922007-11-13 21:02:00 +0000568 NameStr += OMD->getSelector().getName();
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000569 else {
570 std::string selString = OMD->getSelector().getName();
571 int len = selString.size();
572 for (int i = 0; i < len; i++)
573 if (selString[i] == ':')
574 selString[i] = '_';
Fariborz Jahanianbd2fd922007-11-13 21:02:00 +0000575 NameStr += selString;
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000576 }
Fariborz Jahanianbd2fd922007-11-13 21:02:00 +0000577 // Remember this name for metadata emission
578 MethodInternalNames[OMD] = NameStr;
579 ResultStr += NameStr;
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000580
581 // Rewrite arguments
582 ResultStr += "(";
583
584 // invisible arguments
585 if (OMD->isInstance()) {
Ted Kremenek42730c52008-01-07 19:49:32 +0000586 QualType selfTy = Context->getObjCInterfaceType(OMD->getClassInterface());
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000587 selfTy = Context->getPointerType(selfTy);
Ted Kremenek42730c52008-01-07 19:49:32 +0000588 if (ObjCSynthesizedStructs.count(OMD->getClassInterface()))
Fariborz Jahanian0136e372007-11-13 20:04:28 +0000589 ResultStr += "struct ";
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000590 ResultStr += selfTy.getAsString();
591 }
592 else
Ted Kremenek42730c52008-01-07 19:49:32 +0000593 ResultStr += Context->getObjCIdType().getAsString();
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000594
595 ResultStr += " self, ";
Ted Kremenek42730c52008-01-07 19:49:32 +0000596 ResultStr += Context->getObjCSelType().getAsString();
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000597 ResultStr += " _cmd";
598
599 // Method arguments.
600 for (int i = 0; i < OMD->getNumParams(); i++) {
601 ParmVarDecl *PDecl = OMD->getParamDecl(i);
602 ResultStr += ", ";
Ted Kremenek42730c52008-01-07 19:49:32 +0000603 if (PDecl->getType()->isObjCQualifiedIdType())
Fariborz Jahaniane76e8412007-12-17 21:03:50 +0000604 ResultStr += "id";
605 else
606 ResultStr += PDecl->getType().getAsString();
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000607 ResultStr += " ";
608 ResultStr += PDecl->getName();
609 }
Fariborz Jahanian2fab94e2008-01-21 20:14:23 +0000610 if (OMD->isVariadic())
611 ResultStr += ", ...";
Fariborz Jahanian7202d982008-01-10 01:39:52 +0000612 ResultStr += ") ";
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000613
614}
Fariborz Jahanian0136e372007-11-13 20:04:28 +0000615void RewriteTest::RewriteImplementationDecl(NamedDecl *OID) {
Ted Kremenek42730c52008-01-07 19:49:32 +0000616 ObjCImplementationDecl *IMD = dyn_cast<ObjCImplementationDecl>(OID);
617 ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(OID);
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000618
Fariborz Jahanian0136e372007-11-13 20:04:28 +0000619 if (IMD)
620 Rewrite.InsertText(IMD->getLocStart(), "// ", 3);
621 else
622 Rewrite.InsertText(CID->getLocStart(), "// ", 3);
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000623
Ted Kremenek42730c52008-01-07 19:49:32 +0000624 for (ObjCCategoryImplDecl::instmeth_iterator
Chris Lattnerdea5bec2007-12-12 07:46:12 +0000625 I = IMD ? IMD->instmeth_begin() : CID->instmeth_begin(),
626 E = IMD ? IMD->instmeth_end() : CID->instmeth_end(); I != E; ++I) {
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000627 std::string ResultStr;
Ted Kremenek42730c52008-01-07 19:49:32 +0000628 ObjCMethodDecl *OMD = *I;
629 RewriteObjCMethodDecl(OMD, ResultStr);
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000630 SourceLocation LocStart = OMD->getLocStart();
631 SourceLocation LocEnd = OMD->getBody()->getLocStart();
632
633 const char *startBuf = SM->getCharacterData(LocStart);
634 const char *endBuf = SM->getCharacterData(LocEnd);
635 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
636 ResultStr.c_str(), ResultStr.size());
637 }
638
Ted Kremenek42730c52008-01-07 19:49:32 +0000639 for (ObjCCategoryImplDecl::classmeth_iterator
Chris Lattnerdea5bec2007-12-12 07:46:12 +0000640 I = IMD ? IMD->classmeth_begin() : CID->classmeth_begin(),
641 E = IMD ? IMD->classmeth_end() : CID->classmeth_end(); I != E; ++I) {
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000642 std::string ResultStr;
Ted Kremenek42730c52008-01-07 19:49:32 +0000643 ObjCMethodDecl *OMD = *I;
644 RewriteObjCMethodDecl(OMD, ResultStr);
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000645 SourceLocation LocStart = OMD->getLocStart();
646 SourceLocation LocEnd = OMD->getBody()->getLocStart();
647
648 const char *startBuf = SM->getCharacterData(LocStart);
649 const char *endBuf = SM->getCharacterData(LocEnd);
650 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
651 ResultStr.c_str(), ResultStr.size());
652 }
Fariborz Jahanian0136e372007-11-13 20:04:28 +0000653 if (IMD)
654 Rewrite.InsertText(IMD->getLocEnd(), "// ", 3);
655 else
656 Rewrite.InsertText(CID->getLocEnd(), "// ", 3);
Fariborz Jahanian5ea3a762007-11-13 18:44:14 +0000657}
658
Ted Kremenek42730c52008-01-07 19:49:32 +0000659void RewriteTest::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
Steve Naroffef20ed32007-10-30 02:23:23 +0000660 std::string ResultStr;
Ted Kremenek42730c52008-01-07 19:49:32 +0000661 if (!ObjCForwardDecls.count(ClassDecl)) {
Steve Naroff77d081b2007-11-01 03:35:41 +0000662 // we haven't seen a forward decl - generate a typedef.
Steve Naroff2adead72007-11-14 23:02:56 +0000663 ResultStr = "#ifndef _REWRITER_typedef_";
Steve Naroff2aeae312007-11-09 12:50:28 +0000664 ResultStr += ClassDecl->getName();
665 ResultStr += "\n";
666 ResultStr += "#define _REWRITER_typedef_";
667 ResultStr += ClassDecl->getName();
668 ResultStr += "\n";
Fariborz Jahaniana845eec2007-12-03 22:25:42 +0000669 ResultStr += "typedef struct ";
670 ResultStr += ClassDecl->getName();
671 ResultStr += " ";
Steve Naroff77d081b2007-11-01 03:35:41 +0000672 ResultStr += ClassDecl->getName();
Steve Naroff2aeae312007-11-09 12:50:28 +0000673 ResultStr += ";\n#endif\n";
Steve Naroff77d081b2007-11-01 03:35:41 +0000674
675 // Mark this typedef as having been generated.
Ted Kremenek42730c52008-01-07 19:49:32 +0000676 ObjCForwardDecls.insert(ClassDecl);
Steve Naroff77d081b2007-11-01 03:35:41 +0000677 }
Ted Kremenek42730c52008-01-07 19:49:32 +0000678 SynthesizeObjCInternalStruct(ClassDecl, ResultStr);
Steve Naroffef20ed32007-10-30 02:23:23 +0000679
Fariborz Jahanianeca7fad2007-11-07 00:09:37 +0000680 RewriteProperties(ClassDecl->getNumPropertyDecl(),
681 ClassDecl->getPropertyDecl());
Ted Kremenek42730c52008-01-07 19:49:32 +0000682 for (ObjCInterfaceDecl::instmeth_iterator I = ClassDecl->instmeth_begin(),
Steve Naroff2ce399a2007-12-14 23:37:57 +0000683 E = ClassDecl->instmeth_end(); I != E; ++I)
684 RewriteMethodDeclaration(*I);
Ted Kremenek42730c52008-01-07 19:49:32 +0000685 for (ObjCInterfaceDecl::classmeth_iterator I = ClassDecl->classmeth_begin(),
Steve Naroff2ce399a2007-12-14 23:37:57 +0000686 E = ClassDecl->classmeth_end(); I != E; ++I)
687 RewriteMethodDeclaration(*I);
688
Steve Naroff1ccf4632007-10-30 03:43:13 +0000689 // Lastly, comment out the @end.
690 Rewrite.ReplaceText(ClassDecl->getAtEndLoc(), 0, "// ", 3);
Steve Naroff3774dd92007-10-26 20:53:56 +0000691}
692
Steve Naroff6b759ce2007-11-15 02:58:25 +0000693Stmt *RewriteTest::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
Ted Kremenek42730c52008-01-07 19:49:32 +0000694 ObjCIvarDecl *D = IV->getDecl();
Steve Naroff6b759ce2007-11-15 02:58:25 +0000695 if (IV->isFreeIvar()) {
696 Expr *Replacement = new MemberExpr(IV->getBase(), true, D,
697 IV->getLocation());
Steve Naroffe4e5e262007-12-19 14:32:56 +0000698 if (Rewrite.ReplaceStmt(IV, Replacement)) {
699 // replacement failed.
Steve Naroffbcf0a922007-12-19 19:16:49 +0000700 unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Warning,
701 "rewriting sub-expression within a macro (may not be correct)");
Steve Naroffe4e5e262007-12-19 14:32:56 +0000702 SourceRange Range = IV->getSourceRange();
703 Diags.Report(Context->getFullLoc(IV->getLocation()), DiagID, 0, 0, &Range, 1);
Steve Naroffe4e5e262007-12-19 14:32:56 +0000704 }
Steve Naroff6b759ce2007-11-15 02:58:25 +0000705 delete IV;
706 return Replacement;
Steve Naroff292b7b92007-11-15 11:33:00 +0000707 } else {
Fariborz Jahanianc8849882008-01-23 20:34:40 +0000708#if 0
709 /// This code is not right. It seems unnecessary. It breaks use of
710 /// ivar reference used as 'receiver' of an expression; as in:
711 /// [newInv->_container addObject:0];
Steve Naroff292b7b92007-11-15 11:33:00 +0000712 if (CurMethodDecl) {
713 if (const PointerType *pType = IV->getBase()->getType()->getAsPointerType()) {
Ted Kremenek42730c52008-01-07 19:49:32 +0000714 ObjCInterfaceType *intT = dyn_cast<ObjCInterfaceType>(pType->getPointeeType());
Steve Naroff292b7b92007-11-15 11:33:00 +0000715 if (CurMethodDecl->getClassInterface() == intT->getDecl()) {
716 IdentifierInfo *II = intT->getDecl()->getIdentifier();
717 RecordDecl *RD = new RecordDecl(Decl::Struct, SourceLocation(),
718 II, 0);
719 QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
720
721 CastExpr *castExpr = new CastExpr(castT, IV->getBase(), SourceLocation());
722 // Don't forget the parens to enforce the proper binding.
723 ParenExpr *PE = new ParenExpr(SourceLocation(), SourceLocation(), castExpr);
Steve Naroffe4e5e262007-12-19 14:32:56 +0000724 if (Rewrite.ReplaceStmt(IV->getBase(), PE)) {
725 // replacement failed.
Steve Naroffbcf0a922007-12-19 19:16:49 +0000726 unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Warning,
727 "rewriting sub-expression within a macro (may not be correct)");
Steve Naroffe4e5e262007-12-19 14:32:56 +0000728 SourceRange Range = IV->getBase()->getSourceRange();
729 Diags.Report(Context->getFullLoc(IV->getBase()->getLocStart()), DiagID, 0, 0, &Range, 1);
Steve Naroffe4e5e262007-12-19 14:32:56 +0000730 }
Steve Naroff292b7b92007-11-15 11:33:00 +0000731 delete IV->getBase();
732 return PE;
733 }
734 }
735 }
Fariborz Jahanianc8849882008-01-23 20:34:40 +0000736#endif
Steve Naroff6b759ce2007-11-15 02:58:25 +0000737 return IV;
Steve Naroff292b7b92007-11-15 11:33:00 +0000738 }
Steve Naroff6b759ce2007-11-15 02:58:25 +0000739}
740
Chris Lattnerfce2c5a2007-10-24 17:06:59 +0000741//===----------------------------------------------------------------------===//
742// Function Body / Expression rewriting
743//===----------------------------------------------------------------------===//
744
Steve Naroff334fbc22007-11-09 15:20:18 +0000745Stmt *RewriteTest::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
Fariborz Jahanian13dad332008-01-15 23:58:23 +0000746 if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
747 isa<DoStmt>(S) || isa<ForStmt>(S))
748 Stmts.push_back(S);
749 else if (isa<ObjCForCollectionStmt>(S)) {
750 Stmts.push_back(S);
751 ObjCBcLabelNo.push_back(++BcLabelCount);
752 }
753
Chris Lattner6fe8b272007-10-16 22:36:42 +0000754 // Otherwise, just rewrite all children.
755 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
756 CI != E; ++CI)
Steve Naroffe9f69842007-11-07 04:08:17 +0000757 if (*CI) {
Steve Naroff334fbc22007-11-09 15:20:18 +0000758 Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(*CI);
Steve Naroffe9f69842007-11-07 04:08:17 +0000759 if (newStmt)
760 *CI = newStmt;
761 }
Steve Naroffe9780582007-10-23 23:50:29 +0000762
763 // Handle specific things.
764 if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
765 return RewriteAtEncode(AtEncode);
Steve Naroff6b759ce2007-11-15 02:58:25 +0000766
767 if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S))
768 return RewriteObjCIvarRefExpr(IvarRefExpr);
Steve Naroff296b74f2007-11-05 14:50:49 +0000769
770 if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S))
771 return RewriteAtSelector(AtSelector);
Steve Naroff0add5d22007-11-03 11:27:19 +0000772
773 if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S))
774 return RewriteObjCStringLiteral(AtString);
Steve Naroffe9780582007-10-23 23:50:29 +0000775
Steve Naroff71226032007-10-24 22:48:43 +0000776 if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {
777 // Before we rewrite it, put the original message expression in a comment.
778 SourceLocation startLoc = MessExpr->getLocStart();
779 SourceLocation endLoc = MessExpr->getLocEnd();
780
781 const char *startBuf = SM->getCharacterData(startLoc);
782 const char *endBuf = SM->getCharacterData(endLoc);
783
784 std::string messString;
785 messString += "// ";
786 messString.append(startBuf, endBuf-startBuf+1);
787 messString += "\n";
Steve Naroff3774dd92007-10-26 20:53:56 +0000788
Steve Naroff71226032007-10-24 22:48:43 +0000789 // FIXME: Missing definition of Rewrite.InsertText(clang::SourceLocation, char const*, unsigned int).
790 // Rewrite.InsertText(startLoc, messString.c_str(), messString.size());
791 // Tried this, but it didn't work either...
Steve Narofff4b7d6a2007-10-30 16:42:30 +0000792 // Rewrite.ReplaceText(startLoc, 0, messString.c_str(), messString.size());
Steve Naroffe9780582007-10-23 23:50:29 +0000793 return RewriteMessageExpr(MessExpr);
Steve Naroff71226032007-10-24 22:48:43 +0000794 }
Fariborz Jahanian9447e462007-11-05 17:47:33 +0000795
Ted Kremenek42730c52008-01-07 19:49:32 +0000796 if (ObjCAtTryStmt *StmtTry = dyn_cast<ObjCAtTryStmt>(S))
797 return RewriteObjCTryStmt(StmtTry);
Steve Naroff8b1fb8c2007-11-07 15:32:26 +0000798
Ted Kremenek42730c52008-01-07 19:49:32 +0000799 if (ObjCAtThrowStmt *StmtThrow = dyn_cast<ObjCAtThrowStmt>(S))
800 return RewriteObjCThrowStmt(StmtThrow);
Fariborz Jahanian6ff57c62007-12-07 18:47:10 +0000801
802 if (ObjCProtocolExpr *ProtocolExp = dyn_cast<ObjCProtocolExpr>(S))
803 return RewriteObjCProtocolExpr(ProtocolExp);
Fariborz Jahanian955fcb82008-01-07 21:40:22 +0000804
805 if (ObjCForCollectionStmt *StmtForCollection =
806 dyn_cast<ObjCForCollectionStmt>(S))
807 return RewriteObjCForCollectionStmt(StmtForCollection);
Fariborz Jahanian13dad332008-01-15 23:58:23 +0000808 if (BreakStmt *StmtBreakStmt =
809 dyn_cast<BreakStmt>(S))
810 return RewriteBreakStmt(StmtBreakStmt);
811 if (ContinueStmt *StmtContinueStmt =
812 dyn_cast<ContinueStmt>(S))
813 return RewriteContinueStmt(StmtContinueStmt);
Fariborz Jahanian955fcb82008-01-07 21:40:22 +0000814
Fariborz Jahanian13dad332008-01-15 23:58:23 +0000815 if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
816 isa<DoStmt>(S) || isa<ForStmt>(S)) {
817 assert(!Stmts.empty() && "Statement stack is empty");
818 assert ((isa<SwitchStmt>(Stmts.back()) || isa<WhileStmt>(Stmts.back()) ||
819 isa<DoStmt>(Stmts.back()) || isa<ForStmt>(Stmts.back()))
820 && "Statement stack mismatch");
821 Stmts.pop_back();
822 }
Steve Naroff764c1ae2007-11-15 10:28:18 +0000823#if 0
824 if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) {
825 CastExpr *Replacement = new CastExpr(ICE->getType(), ICE->getSubExpr(), SourceLocation());
826 // Get the new text.
827 std::ostringstream Buf;
828 Replacement->printPretty(Buf);
829 const std::string &Str = Buf.str();
830
831 printf("CAST = %s\n", &Str[0]);
832 Rewrite.InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size());
833 delete S;
834 return Replacement;
835 }
836#endif
Chris Lattner0021f452007-10-24 16:57:36 +0000837 // Return this stmt unmodified.
838 return S;
Chris Lattner6fe8b272007-10-16 22:36:42 +0000839}
Fariborz Jahanian955fcb82008-01-07 21:40:22 +0000840
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +0000841/// SynthCountByEnumWithState - To print:
842/// ((unsigned int (*)
843/// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
844/// (void *)objc_msgSend)((id)l_collection,
845/// sel_registerName(
846/// "countByEnumeratingWithState:objects:count:"),
847/// &enumState,
848/// (id *)items, (unsigned int)16)
849///
850void RewriteTest::SynthCountByEnumWithState(std::string &buf) {
851 buf += "((unsigned int (*) (id, SEL, struct __objcFastEnumerationState *, "
852 "id *, unsigned int))(void *)objc_msgSend)";
853 buf += "\n\t\t";
854 buf += "((id)l_collection,\n\t\t";
855 buf += "sel_registerName(\"countByEnumeratingWithState:objects:count:\"),";
856 buf += "\n\t\t";
857 buf += "&enumState, "
858 "(id *)items, (unsigned int)16)";
859}
Fariborz Jahanian955fcb82008-01-07 21:40:22 +0000860
Fariborz Jahanian13dad332008-01-15 23:58:23 +0000861/// RewriteBreakStmt - Rewrite for a break-stmt inside an ObjC2's foreach
862/// statement to exit to its outer synthesized loop.
863///
864Stmt *RewriteTest::RewriteBreakStmt(BreakStmt *S) {
865 if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back()))
866 return S;
867 // replace break with goto __break_label
868 std::string buf;
869
870 SourceLocation startLoc = S->getLocStart();
871 buf = "goto __break_label_";
872 buf += utostr(ObjCBcLabelNo.back());
873 Rewrite.ReplaceText(startLoc, strlen("break"), buf.c_str(), buf.size());
874
875 return 0;
876}
877
878/// RewriteContinueStmt - Rewrite for a continue-stmt inside an ObjC2's foreach
879/// statement to continue with its inner synthesized loop.
880///
881Stmt *RewriteTest::RewriteContinueStmt(ContinueStmt *S) {
882 if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back()))
883 return S;
884 // replace continue with goto __continue_label
885 std::string buf;
886
887 SourceLocation startLoc = S->getLocStart();
888 buf = "goto __continue_label_";
889 buf += utostr(ObjCBcLabelNo.back());
890 Rewrite.ReplaceText(startLoc, strlen("continue"), buf.c_str(), buf.size());
891
892 return 0;
893}
894
Fariborz Jahanian72cf3b52008-01-09 01:25:54 +0000895/// RewriteObjCTryStmt - Rewriter for ObjC2's foreach statement.
Fariborz Jahanian955fcb82008-01-07 21:40:22 +0000896/// It rewrites:
897/// for ( type elem in collection) { stmts; }
Fariborz Jahanian45d52f72007-10-18 22:09:03 +0000898
Fariborz Jahanian955fcb82008-01-07 21:40:22 +0000899/// Into:
900/// {
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +0000901/// type elem;
902/// struct __objcFastEnumerationState enumState = { 0 };
Fariborz Jahanian955fcb82008-01-07 21:40:22 +0000903/// id items[16];
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +0000904/// id l_collection = (id)collection;
905/// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState
906/// objects:items count:16];
Fariborz Jahanian955fcb82008-01-07 21:40:22 +0000907/// if (limit) {
908/// unsigned long startMutations = *enumState.mutationsPtr;
909/// do {
910/// unsigned long counter = 0;
911/// do {
912/// if (startMutations != *enumState.mutationsPtr)
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +0000913/// objc_enumerationMutation(l_collection);
Fariborz Jahanianfb09aa02008-01-09 18:15:42 +0000914/// elem = (type)enumState.itemsPtr[counter++];
Fariborz Jahanian955fcb82008-01-07 21:40:22 +0000915/// stmts;
Fariborz Jahanian13dad332008-01-15 23:58:23 +0000916/// __continue_label: ;
Fariborz Jahanian955fcb82008-01-07 21:40:22 +0000917/// } while (counter < limit);
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +0000918/// } while (limit = [l_collection countByEnumeratingWithState:&enumState
919/// objects:items count:16]);
920/// elem = nil;
Fariborz Jahanian13dad332008-01-15 23:58:23 +0000921/// __break_label: ;
Fariborz Jahanian955fcb82008-01-07 21:40:22 +0000922/// }
923/// else
924/// elem = nil;
925/// }
926///
927Stmt *RewriteTest::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S) {
Fariborz Jahanian13dad332008-01-15 23:58:23 +0000928 assert(!Stmts.empty() && "ObjCForCollectionStmt - Statement stack empty");
929 assert(isa<ObjCForCollectionStmt>(Stmts.back()) &&
930 "ObjCForCollectionStmt Statement stack mismatch");
931 assert(!ObjCBcLabelNo.empty() &&
932 "ObjCForCollectionStmt - Label No stack empty");
933
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +0000934 SourceLocation startLoc = S->getLocStart();
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +0000935 const char *startBuf = SM->getCharacterData(startLoc);
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +0000936 const char *elementName;
Fariborz Jahanianfb09aa02008-01-09 18:15:42 +0000937 std::string elementTypeAsString;
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +0000938 std::string buf;
939 buf = "\n{\n\t";
940 if (DeclStmt *DS = dyn_cast<DeclStmt>(S->getElement())) {
941 // type elem;
942 QualType ElementType = cast<ValueDecl>(DS->getDecl())->getType();
Fariborz Jahanianfb09aa02008-01-09 18:15:42 +0000943 elementTypeAsString = ElementType.getAsString();
944 buf += elementTypeAsString;
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +0000945 buf += " ";
946 elementName = DS->getDecl()->getName();
947 buf += elementName;
948 buf += ";\n\t";
949 }
Fariborz Jahanianfb09aa02008-01-09 18:15:42 +0000950 else if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S->getElement())) {
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +0000951 elementName = DR->getDecl()->getName();
Fariborz Jahanianfb09aa02008-01-09 18:15:42 +0000952 elementTypeAsString = DR->getDecl()->getType().getAsString();
953 }
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +0000954 else
955 assert(false && "RewriteObjCForCollectionStmt - bad element kind");
956
957 // struct __objcFastEnumerationState enumState = { 0 };
958 buf += "struct __objcFastEnumerationState enumState = { 0 };\n\t";
959 // id items[16];
960 buf += "id items[16];\n\t";
961 // id l_collection = (id)
962 buf += "id l_collection = (id)";
Fariborz Jahaniandf2b0952008-01-10 00:24:29 +0000963 // Find start location of 'collection' the hard way!
964 const char *startCollectionBuf = startBuf;
965 startCollectionBuf += 3; // skip 'for'
966 startCollectionBuf = strchr(startCollectionBuf, '(');
967 startCollectionBuf++; // skip '('
968 // find 'in' and skip it.
969 while (*startCollectionBuf != ' ' ||
970 *(startCollectionBuf+1) != 'i' || *(startCollectionBuf+2) != 'n' ||
971 (*(startCollectionBuf+3) != ' ' &&
972 *(startCollectionBuf+3) != '[' && *(startCollectionBuf+3) != '('))
973 startCollectionBuf++;
974 startCollectionBuf += 3;
975
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +0000976 // Replace: "for (type element in" with string constructed thus far.
977 Rewrite.ReplaceText(startLoc, startCollectionBuf - startBuf,
978 buf.c_str(), buf.size());
979 // Replace ')' in for '(' type elem in collection ')' with ';'
Fariborz Jahaniandf2b0952008-01-10 00:24:29 +0000980 SourceLocation rightParenLoc = S->getRParenLoc();
981 const char *rparenBuf = SM->getCharacterData(rightParenLoc);
982 SourceLocation lparenLoc = startLoc.getFileLocWithOffset(rparenBuf-startBuf);
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +0000983 buf = ";\n\t";
984
985 // unsigned long limit = [l_collection countByEnumeratingWithState:&enumState
986 // objects:items count:16];
987 // which is synthesized into:
988 // unsigned int limit =
989 // ((unsigned int (*)
990 // (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
991 // (void *)objc_msgSend)((id)l_collection,
992 // sel_registerName(
993 // "countByEnumeratingWithState:objects:count:"),
994 // (struct __objcFastEnumerationState *)&state,
995 // (id *)items, (unsigned int)16);
996 buf += "unsigned long limit =\n\t\t";
997 SynthCountByEnumWithState(buf);
998 buf += ";\n\t";
999 /// if (limit) {
1000 /// unsigned long startMutations = *enumState.mutationsPtr;
1001 /// do {
1002 /// unsigned long counter = 0;
1003 /// do {
1004 /// if (startMutations != *enumState.mutationsPtr)
1005 /// objc_enumerationMutation(l_collection);
Fariborz Jahanianfb09aa02008-01-09 18:15:42 +00001006 /// elem = (type)enumState.itemsPtr[counter++];
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +00001007 buf += "if (limit) {\n\t";
1008 buf += "unsigned long startMutations = *enumState.mutationsPtr;\n\t";
1009 buf += "do {\n\t\t";
1010 buf += "unsigned long counter = 0;\n\t\t";
1011 buf += "do {\n\t\t\t";
1012 buf += "if (startMutations != *enumState.mutationsPtr)\n\t\t\t\t";
1013 buf += "objc_enumerationMutation(l_collection);\n\t\t\t";
1014 buf += elementName;
Fariborz Jahanianfb09aa02008-01-09 18:15:42 +00001015 buf += " = (";
1016 buf += elementTypeAsString;
1017 buf += ")enumState.itemsPtr[counter++];";
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +00001018 // Replace ')' in for '(' type elem in collection ')' with all of these.
1019 Rewrite.ReplaceText(lparenLoc, 1, buf.c_str(), buf.size());
1020
Fariborz Jahanian13dad332008-01-15 23:58:23 +00001021 /// __continue_label: ;
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +00001022 /// } while (counter < limit);
1023 /// } while (limit = [l_collection countByEnumeratingWithState:&enumState
1024 /// objects:items count:16]);
1025 /// elem = nil;
Fariborz Jahanian13dad332008-01-15 23:58:23 +00001026 /// __break_label: ;
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +00001027 /// }
1028 /// else
1029 /// elem = nil;
1030 /// }
Fariborz Jahanian13dad332008-01-15 23:58:23 +00001031 ///
1032 buf = ";\n\t";
1033 buf += "__continue_label_";
1034 buf += utostr(ObjCBcLabelNo.back());
1035 buf += ": ;";
1036 buf += "\n\t\t";
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +00001037 buf += "} while (counter < limit);\n\t";
1038 buf += "} while (limit = ";
1039 SynthCountByEnumWithState(buf);
1040 buf += ");\n\t";
1041 buf += elementName;
1042 buf += " = nil;\n\t";
Fariborz Jahanian13dad332008-01-15 23:58:23 +00001043 buf += "__break_label_";
1044 buf += utostr(ObjCBcLabelNo.back());
1045 buf += ": ;\n\t";
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +00001046 buf += "}\n\t";
1047 buf += "else\n\t\t";
1048 buf += elementName;
1049 buf += " = nil;\n";
1050 buf += "}\n";
1051 // Insert all these *after* the statement body.
1052 SourceLocation endBodyLoc = S->getBody()->getLocEnd();
1053 const char *endBodyBuf = SM->getCharacterData(endBodyLoc)+1;
1054 endBodyLoc = startLoc.getFileLocWithOffset(endBodyBuf-startBuf);
1055 Rewrite.InsertText(endBodyLoc, buf.c_str(), buf.size());
Fariborz Jahanian13dad332008-01-15 23:58:23 +00001056 Stmts.pop_back();
1057 ObjCBcLabelNo.pop_back();
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +00001058
1059 return 0;
Fariborz Jahanian955fcb82008-01-07 21:40:22 +00001060}
1061
Ted Kremenek42730c52008-01-07 19:49:32 +00001062Stmt *RewriteTest::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
Steve Naroffe9f69842007-11-07 04:08:17 +00001063 // Get the start location and compute the semi location.
1064 SourceLocation startLoc = S->getLocStart();
1065 const char *startBuf = SM->getCharacterData(startLoc);
1066
1067 assert((*startBuf == '@') && "bogus @try location");
1068
1069 std::string buf;
1070 // declare a new scope with two variables, _stack and _rethrow.
1071 buf = "/* @try scope begin */ { struct _objc_exception_data {\n";
1072 buf += "int buf[18/*32-bit i386*/];\n";
1073 buf += "char *pointers[4];} _stack;\n";
1074 buf += "id volatile _rethrow = 0;\n";
1075 buf += "objc_exception_try_enter(&_stack);\n";
Steve Naroffd3287d82007-11-07 18:43:40 +00001076 buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";
Steve Naroffe9f69842007-11-07 04:08:17 +00001077
1078 Rewrite.ReplaceText(startLoc, 4, buf.c_str(), buf.size());
1079
1080 startLoc = S->getTryBody()->getLocEnd();
1081 startBuf = SM->getCharacterData(startLoc);
1082
1083 assert((*startBuf == '}') && "bogus @try block");
1084
1085 SourceLocation lastCurlyLoc = startLoc;
1086
1087 startLoc = startLoc.getFileLocWithOffset(1);
1088 buf = " /* @catch begin */ else {\n";
1089 buf += " id _caught = objc_exception_extract(&_stack);\n";
1090 buf += " objc_exception_try_enter (&_stack);\n";
Steve Naroffd3287d82007-11-07 18:43:40 +00001091 buf += " if (_setjmp(_stack.buf))\n";
Steve Naroffe9f69842007-11-07 04:08:17 +00001092 buf += " _rethrow = objc_exception_extract(&_stack);\n";
1093 buf += " else { /* @catch continue */";
1094
Chris Lattner3c82a7e2007-11-08 04:41:51 +00001095 Rewrite.InsertText(startLoc, buf.c_str(), buf.size());
Steve Naroffe9f69842007-11-07 04:08:17 +00001096
1097 bool sawIdTypedCatch = false;
1098 Stmt *lastCatchBody = 0;
Ted Kremenek42730c52008-01-07 19:49:32 +00001099 ObjCAtCatchStmt *catchList = S->getCatchStmts();
Steve Naroffe9f69842007-11-07 04:08:17 +00001100 while (catchList) {
1101 Stmt *catchStmt = catchList->getCatchParamStmt();
1102
1103 if (catchList == S->getCatchStmts())
1104 buf = "if ("; // we are generating code for the first catch clause
1105 else
1106 buf = "else if (";
1107 startLoc = catchList->getLocStart();
1108 startBuf = SM->getCharacterData(startLoc);
1109
1110 assert((*startBuf == '@') && "bogus @catch location");
1111
1112 const char *lParenLoc = strchr(startBuf, '(');
1113
1114 if (DeclStmt *declStmt = dyn_cast<DeclStmt>(catchStmt)) {
1115 QualType t = dyn_cast<ValueDecl>(declStmt->getDecl())->getType();
Ted Kremenek42730c52008-01-07 19:49:32 +00001116 if (t == Context->getObjCIdType()) {
Steve Naroffe9f69842007-11-07 04:08:17 +00001117 buf += "1) { ";
1118 Rewrite.ReplaceText(startLoc, lParenLoc-startBuf+1,
1119 buf.c_str(), buf.size());
1120 sawIdTypedCatch = true;
1121 } else if (const PointerType *pType = t->getAsPointerType()) {
Ted Kremenek42730c52008-01-07 19:49:32 +00001122 ObjCInterfaceType *cls; // Should be a pointer to a class.
Steve Naroffe9f69842007-11-07 04:08:17 +00001123
Ted Kremenek42730c52008-01-07 19:49:32 +00001124 cls = dyn_cast<ObjCInterfaceType>(pType->getPointeeType().getTypePtr());
Steve Naroffe9f69842007-11-07 04:08:17 +00001125 if (cls) {
Steve Naroffd3287d82007-11-07 18:43:40 +00001126 buf += "objc_exception_match((struct objc_class *)objc_getClass(\"";
Steve Naroffe9f69842007-11-07 04:08:17 +00001127 buf += cls->getDecl()->getName();
Steve Naroffd3287d82007-11-07 18:43:40 +00001128 buf += "\"), (struct objc_object *)_caught)) { ";
Steve Naroffe9f69842007-11-07 04:08:17 +00001129 Rewrite.ReplaceText(startLoc, lParenLoc-startBuf+1,
1130 buf.c_str(), buf.size());
1131 }
1132 }
1133 // Now rewrite the body...
1134 lastCatchBody = catchList->getCatchBody();
1135 SourceLocation rParenLoc = catchList->getRParenLoc();
1136 SourceLocation bodyLoc = lastCatchBody->getLocStart();
1137 const char *bodyBuf = SM->getCharacterData(bodyLoc);
1138 const char *rParenBuf = SM->getCharacterData(rParenLoc);
1139 assert((*rParenBuf == ')') && "bogus @catch paren location");
1140 assert((*bodyBuf == '{') && "bogus @catch body location");
1141
1142 buf = " = _caught;";
1143 // Here we replace ") {" with "= _caught;" (which initializes and
1144 // declares the @catch parameter).
1145 Rewrite.ReplaceText(rParenLoc, bodyBuf-rParenBuf+1,
1146 buf.c_str(), buf.size());
Steve Naroff8b1fb8c2007-11-07 15:32:26 +00001147 } else if (!isa<NullStmt>(catchStmt)) {
Steve Naroffe9f69842007-11-07 04:08:17 +00001148 assert(false && "@catch rewrite bug");
Steve Naroff8b1fb8c2007-11-07 15:32:26 +00001149 }
Steve Naroffe9f69842007-11-07 04:08:17 +00001150 catchList = catchList->getNextCatchStmt();
1151 }
1152 // Complete the catch list...
1153 if (lastCatchBody) {
1154 SourceLocation bodyLoc = lastCatchBody->getLocEnd();
1155 const char *bodyBuf = SM->getCharacterData(bodyLoc);
1156 assert((*bodyBuf == '}') && "bogus @catch body location");
1157 bodyLoc = bodyLoc.getFileLocWithOffset(1);
1158 buf = " } } /* @catch end */\n";
1159
Chris Lattner3c82a7e2007-11-08 04:41:51 +00001160 Rewrite.InsertText(bodyLoc, buf.c_str(), buf.size());
Steve Naroffe9f69842007-11-07 04:08:17 +00001161
1162 // Set lastCurlyLoc
1163 lastCurlyLoc = lastCatchBody->getLocEnd();
1164 }
Ted Kremenek42730c52008-01-07 19:49:32 +00001165 if (ObjCAtFinallyStmt *finalStmt = S->getFinallyStmt()) {
Steve Naroffe9f69842007-11-07 04:08:17 +00001166 startLoc = finalStmt->getLocStart();
1167 startBuf = SM->getCharacterData(startLoc);
1168 assert((*startBuf == '@') && "bogus @finally start");
1169
1170 buf = "/* @finally */";
1171 Rewrite.ReplaceText(startLoc, 8, buf.c_str(), buf.size());
1172
1173 Stmt *body = finalStmt->getFinallyBody();
1174 SourceLocation startLoc = body->getLocStart();
1175 SourceLocation endLoc = body->getLocEnd();
1176 const char *startBuf = SM->getCharacterData(startLoc);
1177 const char *endBuf = SM->getCharacterData(endLoc);
1178 assert((*startBuf == '{') && "bogus @finally body location");
1179 assert((*endBuf == '}') && "bogus @finally body location");
1180
1181 startLoc = startLoc.getFileLocWithOffset(1);
1182 buf = " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
Chris Lattner3c82a7e2007-11-08 04:41:51 +00001183 Rewrite.InsertText(startLoc, buf.c_str(), buf.size());
Steve Naroffe9f69842007-11-07 04:08:17 +00001184 endLoc = endLoc.getFileLocWithOffset(-1);
1185 buf = " if (_rethrow) objc_exception_throw(_rethrow);\n";
Chris Lattner3c82a7e2007-11-08 04:41:51 +00001186 Rewrite.InsertText(endLoc, buf.c_str(), buf.size());
Steve Naroffe9f69842007-11-07 04:08:17 +00001187
1188 // Set lastCurlyLoc
1189 lastCurlyLoc = body->getLocEnd();
1190 }
1191 // Now emit the final closing curly brace...
1192 lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1);
1193 buf = " } /* @try scope end */\n";
Chris Lattner3c82a7e2007-11-08 04:41:51 +00001194 Rewrite.InsertText(lastCurlyLoc, buf.c_str(), buf.size());
Fariborz Jahanian9447e462007-11-05 17:47:33 +00001195 return 0;
1196}
1197
Ted Kremenek42730c52008-01-07 19:49:32 +00001198Stmt *RewriteTest::RewriteObjCCatchStmt(ObjCAtCatchStmt *S) {
Fariborz Jahanian9447e462007-11-05 17:47:33 +00001199 return 0;
1200}
1201
Ted Kremenek42730c52008-01-07 19:49:32 +00001202Stmt *RewriteTest::RewriteObjCFinallyStmt(ObjCAtFinallyStmt *S) {
Fariborz Jahanian9447e462007-11-05 17:47:33 +00001203 return 0;
1204}
1205
Steve Naroff8b1fb8c2007-11-07 15:32:26 +00001206// This can't be done with Rewrite.ReplaceStmt(S, ThrowExpr), since
1207// the throw expression is typically a message expression that's already
1208// been rewritten! (which implies the SourceLocation's are invalid).
Ted Kremenek42730c52008-01-07 19:49:32 +00001209Stmt *RewriteTest::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) {
Steve Naroff8b1fb8c2007-11-07 15:32:26 +00001210 // Get the start location and compute the semi location.
1211 SourceLocation startLoc = S->getLocStart();
1212 const char *startBuf = SM->getCharacterData(startLoc);
1213
1214 assert((*startBuf == '@') && "bogus @throw location");
1215
1216 std::string buf;
1217 /* void objc_exception_throw(id) __attribute__((noreturn)); */
Steve Naroffbe72efa2008-01-19 00:42:38 +00001218 if (S->getThrowExpr())
1219 buf = "objc_exception_throw(";
1220 else // add an implicit argument
1221 buf = "objc_exception_throw(_caught";
Steve Naroff8b1fb8c2007-11-07 15:32:26 +00001222 Rewrite.ReplaceText(startLoc, 6, buf.c_str(), buf.size());
1223 const char *semiBuf = strchr(startBuf, ';');
1224 assert((*semiBuf == ';') && "@throw: can't find ';'");
1225 SourceLocation semiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf);
1226 buf = ");";
1227 Rewrite.ReplaceText(semiLoc, 1, buf.c_str(), buf.size());
1228 return 0;
1229}
Fariborz Jahanian9447e462007-11-05 17:47:33 +00001230
Chris Lattner0021f452007-10-24 16:57:36 +00001231Stmt *RewriteTest::RewriteAtEncode(ObjCEncodeExpr *Exp) {
Chris Lattnerbf0bfa62007-10-17 22:35:30 +00001232 // Create a new string expression.
1233 QualType StrType = Context->getPointerType(Context->CharTy);
Anders Carlsson36f07d82007-10-29 05:01:08 +00001234 std::string StrEncoding;
Fariborz Jahanian248db262008-01-22 22:44:46 +00001235 Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding,
1236 EncodingRecordTypes);
Anders Carlsson36f07d82007-10-29 05:01:08 +00001237 Expr *Replacement = new StringLiteral(StrEncoding.c_str(),
1238 StrEncoding.length(), false, StrType,
Chris Lattnerbf0bfa62007-10-17 22:35:30 +00001239 SourceLocation(), SourceLocation());
Chris Lattner258f26c2007-11-30 22:25:36 +00001240 if (Rewrite.ReplaceStmt(Exp, Replacement)) {
1241 // replacement failed.
Steve Naroffbcf0a922007-12-19 19:16:49 +00001242 unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Warning,
1243 "rewriting sub-expression within a macro (may not be correct)");
Chris Lattner217df512007-12-02 01:09:57 +00001244 SourceRange Range = Exp->getSourceRange();
Ted Kremenekd7f64cd2007-12-12 22:39:36 +00001245 Diags.Report(Context->getFullLoc(Exp->getAtLoc()), DiagID, 0, 0, &Range, 1);
Chris Lattner258f26c2007-11-30 22:25:36 +00001246 }
1247
Chris Lattner4478db92007-11-30 22:53:43 +00001248 // Replace this subexpr in the parent.
Chris Lattner0021f452007-10-24 16:57:36 +00001249 delete Exp;
1250 return Replacement;
Chris Lattner6fe8b272007-10-16 22:36:42 +00001251}
1252
Steve Naroff296b74f2007-11-05 14:50:49 +00001253Stmt *RewriteTest::RewriteAtSelector(ObjCSelectorExpr *Exp) {
1254 assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");
1255 // Create a call to sel_registerName("selName").
1256 llvm::SmallVector<Expr*, 8> SelExprs;
1257 QualType argType = Context->getPointerType(Context->CharTy);
1258 SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
1259 Exp->getSelector().getName().size(),
1260 false, argType, SourceLocation(),
1261 SourceLocation()));
1262 CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
1263 &SelExprs[0], SelExprs.size());
Steve Naroffe4e5e262007-12-19 14:32:56 +00001264 if (Rewrite.ReplaceStmt(Exp, SelExp)) {
1265 // replacement failed.
Steve Naroffbcf0a922007-12-19 19:16:49 +00001266 unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Warning,
1267 "rewriting sub-expression within a macro (may not be correct)");
Steve Naroffe4e5e262007-12-19 14:32:56 +00001268 SourceRange Range = Exp->getSourceRange();
1269 Diags.Report(Context->getFullLoc(Exp->getAtLoc()), DiagID, 0, 0, &Range, 1);
Steve Naroffe4e5e262007-12-19 14:32:56 +00001270 }
Steve Naroff296b74f2007-11-05 14:50:49 +00001271 delete Exp;
1272 return SelExp;
1273}
1274
Steve Naroff71226032007-10-24 22:48:43 +00001275CallExpr *RewriteTest::SynthesizeCallToFunctionDecl(
1276 FunctionDecl *FD, Expr **args, unsigned nargs) {
Steve Naroffe9780582007-10-23 23:50:29 +00001277 // Get the type, we will need to reference it in a couple spots.
Steve Naroff71226032007-10-24 22:48:43 +00001278 QualType msgSendType = FD->getType();
Steve Naroffe9780582007-10-23 23:50:29 +00001279
1280 // Create a reference to the objc_msgSend() declaration.
Steve Naroff71226032007-10-24 22:48:43 +00001281 DeclRefExpr *DRE = new DeclRefExpr(FD, msgSendType, SourceLocation());
Steve Naroffe9780582007-10-23 23:50:29 +00001282
1283 // Now, we cast the reference to a pointer to the objc_msgSend type.
Chris Lattnerfce2c5a2007-10-24 17:06:59 +00001284 QualType pToFunc = Context->getPointerType(msgSendType);
Steve Naroffe9780582007-10-23 23:50:29 +00001285 ImplicitCastExpr *ICE = new ImplicitCastExpr(pToFunc, DRE);
1286
1287 const FunctionType *FT = msgSendType->getAsFunctionType();
Chris Lattner0021f452007-10-24 16:57:36 +00001288
Steve Naroff71226032007-10-24 22:48:43 +00001289 return new CallExpr(ICE, args, nargs, FT->getResultType(), SourceLocation());
1290}
1291
Steve Naroffc8a92d12007-11-01 13:24:47 +00001292static bool scanForProtocolRefs(const char *startBuf, const char *endBuf,
1293 const char *&startRef, const char *&endRef) {
1294 while (startBuf < endBuf) {
1295 if (*startBuf == '<')
1296 startRef = startBuf; // mark the start.
1297 if (*startBuf == '>') {
Steve Naroff2aeae312007-11-09 12:50:28 +00001298 if (startRef && *startRef == '<') {
1299 endRef = startBuf; // mark the end.
1300 return true;
1301 }
1302 return false;
Steve Naroffc8a92d12007-11-01 13:24:47 +00001303 }
1304 startBuf++;
1305 }
1306 return false;
1307}
1308
Fariborz Jahanian150c6ea2007-12-11 22:50:14 +00001309static void scanToNextArgument(const char *&argRef) {
1310 int angle = 0;
1311 while (*argRef != ')' && (*argRef != ',' || angle > 0)) {
1312 if (*argRef == '<')
1313 angle++;
1314 else if (*argRef == '>')
1315 angle--;
1316 argRef++;
1317 }
1318 assert(angle == 0 && "scanToNextArgument - bad protocol type syntax");
1319}
Fariborz Jahaniandb2904f2007-12-11 23:04:08 +00001320
Steve Naroffc8a92d12007-11-01 13:24:47 +00001321bool RewriteTest::needToScanForQualifiers(QualType T) {
Fariborz Jahaniane76e8412007-12-17 21:03:50 +00001322
Ted Kremenek42730c52008-01-07 19:49:32 +00001323 if (T == Context->getObjCIdType())
Steve Naroffc8a92d12007-11-01 13:24:47 +00001324 return true;
1325
Ted Kremenek42730c52008-01-07 19:49:32 +00001326 if (T->isObjCQualifiedIdType())
Fariborz Jahaniane76e8412007-12-17 21:03:50 +00001327 return true;
1328
Steve Naroffc8a92d12007-11-01 13:24:47 +00001329 if (const PointerType *pType = T->getAsPointerType()) {
Steve Naroff05d6ff52007-10-31 04:38:33 +00001330 Type *pointeeType = pType->getPointeeType().getTypePtr();
Ted Kremenek42730c52008-01-07 19:49:32 +00001331 if (isa<ObjCQualifiedInterfaceType>(pointeeType))
Steve Naroff05d6ff52007-10-31 04:38:33 +00001332 return true; // we have "Class <Protocol> *".
1333 }
Steve Naroffc8a92d12007-11-01 13:24:47 +00001334 return false;
1335}
1336
Ted Kremenek42730c52008-01-07 19:49:32 +00001337void RewriteTest::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
Fariborz Jahanian150c6ea2007-12-11 22:50:14 +00001338 SourceLocation Loc;
1339 QualType Type;
1340 const FunctionTypeProto *proto = 0;
1341 if (VarDecl *VD = dyn_cast<VarDecl>(Dcl)) {
1342 Loc = VD->getLocation();
1343 Type = VD->getType();
1344 }
1345 else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Dcl)) {
1346 Loc = FD->getLocation();
1347 // Check for ObjC 'id' and class types that have been adorned with protocol
1348 // information (id<p>, C<p>*). The protocol references need to be rewritten!
1349 const FunctionType *funcType = FD->getType()->getAsFunctionType();
1350 assert(funcType && "missing function type");
1351 proto = dyn_cast<FunctionTypeProto>(funcType);
1352 if (!proto)
1353 return;
1354 Type = proto->getResultType();
1355 }
1356 else
1357 return;
Steve Naroffc8a92d12007-11-01 13:24:47 +00001358
Fariborz Jahanian150c6ea2007-12-11 22:50:14 +00001359 if (needToScanForQualifiers(Type)) {
Steve Naroffc8a92d12007-11-01 13:24:47 +00001360 // Since types are unique, we need to scan the buffer.
Steve Naroffc8a92d12007-11-01 13:24:47 +00001361
1362 const char *endBuf = SM->getCharacterData(Loc);
1363 const char *startBuf = endBuf;
Chris Lattnerae43eb72007-12-02 01:13:47 +00001364 while (*startBuf != ';' && startBuf != MainFileStart)
Steve Naroffc8a92d12007-11-01 13:24:47 +00001365 startBuf--; // scan backward (from the decl location) for return type.
1366 const char *startRef = 0, *endRef = 0;
1367 if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
1368 // Get the locations of the startRef, endRef.
1369 SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-endBuf);
1370 SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-endBuf+1);
1371 // Comment out the protocol references.
Chris Lattner3c82a7e2007-11-08 04:41:51 +00001372 Rewrite.InsertText(LessLoc, "/*", 2);
1373 Rewrite.InsertText(GreaterLoc, "*/", 2);
Steve Naroff05d6ff52007-10-31 04:38:33 +00001374 }
1375 }
Fariborz Jahanian150c6ea2007-12-11 22:50:14 +00001376 if (!proto)
1377 return; // most likely, was a variable
Steve Naroffc8a92d12007-11-01 13:24:47 +00001378 // Now check arguments.
Fariborz Jahanian150c6ea2007-12-11 22:50:14 +00001379 const char *startBuf = SM->getCharacterData(Loc);
1380 const char *startFuncBuf = startBuf;
Steve Naroffc8a92d12007-11-01 13:24:47 +00001381 for (unsigned i = 0; i < proto->getNumArgs(); i++) {
1382 if (needToScanForQualifiers(proto->getArgType(i))) {
1383 // Since types are unique, we need to scan the buffer.
Steve Naroffc8a92d12007-11-01 13:24:47 +00001384
Steve Naroffc8a92d12007-11-01 13:24:47 +00001385 const char *endBuf = startBuf;
Fariborz Jahanian150c6ea2007-12-11 22:50:14 +00001386 // scan forward (from the decl location) for argument types.
1387 scanToNextArgument(endBuf);
Steve Naroffc8a92d12007-11-01 13:24:47 +00001388 const char *startRef = 0, *endRef = 0;
1389 if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
1390 // Get the locations of the startRef, endRef.
Fariborz Jahaniandb2904f2007-12-11 23:04:08 +00001391 SourceLocation LessLoc =
1392 Loc.getFileLocWithOffset(startRef-startFuncBuf);
1393 SourceLocation GreaterLoc =
1394 Loc.getFileLocWithOffset(endRef-startFuncBuf+1);
Steve Naroffc8a92d12007-11-01 13:24:47 +00001395 // Comment out the protocol references.
Chris Lattner3c82a7e2007-11-08 04:41:51 +00001396 Rewrite.InsertText(LessLoc, "/*", 2);
1397 Rewrite.InsertText(GreaterLoc, "*/", 2);
Steve Naroffc8a92d12007-11-01 13:24:47 +00001398 }
Fariborz Jahanian150c6ea2007-12-11 22:50:14 +00001399 startBuf = ++endBuf;
1400 }
1401 else {
1402 while (*startBuf != ')' && *startBuf != ',')
1403 startBuf++; // scan forward (from the decl location) for argument types.
1404 startBuf++;
1405 }
Steve Naroffc8a92d12007-11-01 13:24:47 +00001406 }
Steve Naroff05d6ff52007-10-31 04:38:33 +00001407}
1408
Fariborz Jahanianfb8e9912007-12-04 21:47:40 +00001409// SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str);
1410void RewriteTest::SynthSelGetUidFunctionDecl() {
1411 IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName");
1412 llvm::SmallVector<QualType, 16> ArgTys;
1413 ArgTys.push_back(Context->getPointerType(
1414 Context->CharTy.getQualifiedType(QualType::Const)));
Ted Kremenek42730c52008-01-07 19:49:32 +00001415 QualType getFuncType = Context->getFunctionType(Context->getObjCSelType(),
Fariborz Jahanianfb8e9912007-12-04 21:47:40 +00001416 &ArgTys[0], ArgTys.size(),
1417 false /*isVariadic*/);
1418 SelGetUidFunctionDecl = new FunctionDecl(SourceLocation(),
1419 SelGetUidIdent, getFuncType,
1420 FunctionDecl::Extern, false, 0);
1421}
1422
Fariborz Jahanian6ff57c62007-12-07 18:47:10 +00001423// SynthGetProtocolFunctionDecl - Protocol objc_getProtocol(const char *proto);
1424void RewriteTest::SynthGetProtocolFunctionDecl() {
1425 IdentifierInfo *SelGetProtoIdent = &Context->Idents.get("objc_getProtocol");
1426 llvm::SmallVector<QualType, 16> ArgTys;
1427 ArgTys.push_back(Context->getPointerType(
1428 Context->CharTy.getQualifiedType(QualType::Const)));
Ted Kremenek42730c52008-01-07 19:49:32 +00001429 QualType getFuncType = Context->getFunctionType(Context->getObjCProtoType(),
Fariborz Jahanian6ff57c62007-12-07 18:47:10 +00001430 &ArgTys[0], ArgTys.size(),
1431 false /*isVariadic*/);
1432 GetProtocolFunctionDecl = new FunctionDecl(SourceLocation(),
1433 SelGetProtoIdent, getFuncType,
1434 FunctionDecl::Extern, false, 0);
1435}
1436
Steve Naroff02a82aa2007-10-30 23:14:51 +00001437void RewriteTest::RewriteFunctionDecl(FunctionDecl *FD) {
1438 // declared in <objc/objc.h>
Steve Naroff0add5d22007-11-03 11:27:19 +00001439 if (strcmp(FD->getName(), "sel_registerName") == 0) {
Steve Naroff02a82aa2007-10-30 23:14:51 +00001440 SelGetUidFunctionDecl = FD;
Steve Naroff05d6ff52007-10-31 04:38:33 +00001441 return;
1442 }
Ted Kremenek42730c52008-01-07 19:49:32 +00001443 RewriteObjCQualifiedInterfaceTypes(FD);
Steve Naroff02a82aa2007-10-30 23:14:51 +00001444}
1445
1446// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
1447void RewriteTest::SynthMsgSendFunctionDecl() {
1448 IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend");
1449 llvm::SmallVector<QualType, 16> ArgTys;
Ted Kremenek42730c52008-01-07 19:49:32 +00001450 QualType argT = Context->getObjCIdType();
Steve Naroff02a82aa2007-10-30 23:14:51 +00001451 assert(!argT.isNull() && "Can't find 'id' type");
1452 ArgTys.push_back(argT);
Ted Kremenek42730c52008-01-07 19:49:32 +00001453 argT = Context->getObjCSelType();
Steve Naroff02a82aa2007-10-30 23:14:51 +00001454 assert(!argT.isNull() && "Can't find 'SEL' type");
1455 ArgTys.push_back(argT);
Ted Kremenek42730c52008-01-07 19:49:32 +00001456 QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
Steve Naroff02a82aa2007-10-30 23:14:51 +00001457 &ArgTys[0], ArgTys.size(),
1458 true /*isVariadic*/);
1459 MsgSendFunctionDecl = new FunctionDecl(SourceLocation(),
1460 msgSendIdent, msgSendType,
1461 FunctionDecl::Extern, false, 0);
1462}
1463
Steve Naroff764c1ae2007-11-15 10:28:18 +00001464// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...);
1465void RewriteTest::SynthMsgSendSuperFunctionDecl() {
1466 IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper");
1467 llvm::SmallVector<QualType, 16> ArgTys;
1468 RecordDecl *RD = new RecordDecl(Decl::Struct, SourceLocation(),
1469 &Context->Idents.get("objc_super"), 0);
1470 QualType argT = Context->getPointerType(Context->getTagDeclType(RD));
1471 assert(!argT.isNull() && "Can't build 'struct objc_super *' type");
1472 ArgTys.push_back(argT);
Ted Kremenek42730c52008-01-07 19:49:32 +00001473 argT = Context->getObjCSelType();
Steve Naroff764c1ae2007-11-15 10:28:18 +00001474 assert(!argT.isNull() && "Can't find 'SEL' type");
1475 ArgTys.push_back(argT);
Ted Kremenek42730c52008-01-07 19:49:32 +00001476 QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
Steve Naroff764c1ae2007-11-15 10:28:18 +00001477 &ArgTys[0], ArgTys.size(),
1478 true /*isVariadic*/);
1479 MsgSendSuperFunctionDecl = new FunctionDecl(SourceLocation(),
1480 msgSendIdent, msgSendType,
1481 FunctionDecl::Extern, false, 0);
1482}
1483
Fariborz Jahanianc26b2502007-12-03 19:17:29 +00001484// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...);
1485void RewriteTest::SynthMsgSendStretFunctionDecl() {
1486 IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_stret");
1487 llvm::SmallVector<QualType, 16> ArgTys;
Ted Kremenek42730c52008-01-07 19:49:32 +00001488 QualType argT = Context->getObjCIdType();
Fariborz Jahanianc26b2502007-12-03 19:17:29 +00001489 assert(!argT.isNull() && "Can't find 'id' type");
1490 ArgTys.push_back(argT);
Ted Kremenek42730c52008-01-07 19:49:32 +00001491 argT = Context->getObjCSelType();
Fariborz Jahanianc26b2502007-12-03 19:17:29 +00001492 assert(!argT.isNull() && "Can't find 'SEL' type");
1493 ArgTys.push_back(argT);
Ted Kremenek42730c52008-01-07 19:49:32 +00001494 QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
Fariborz Jahanianc26b2502007-12-03 19:17:29 +00001495 &ArgTys[0], ArgTys.size(),
1496 true /*isVariadic*/);
1497 MsgSendStretFunctionDecl = new FunctionDecl(SourceLocation(),
1498 msgSendIdent, msgSendType,
1499 FunctionDecl::Extern, false, 0);
1500}
1501
1502// SynthMsgSendSuperStretFunctionDecl -
1503// id objc_msgSendSuper_stret(struct objc_super *, SEL op, ...);
1504void RewriteTest::SynthMsgSendSuperStretFunctionDecl() {
1505 IdentifierInfo *msgSendIdent =
1506 &Context->Idents.get("objc_msgSendSuper_stret");
1507 llvm::SmallVector<QualType, 16> ArgTys;
1508 RecordDecl *RD = new RecordDecl(Decl::Struct, SourceLocation(),
1509 &Context->Idents.get("objc_super"), 0);
1510 QualType argT = Context->getPointerType(Context->getTagDeclType(RD));
1511 assert(!argT.isNull() && "Can't build 'struct objc_super *' type");
1512 ArgTys.push_back(argT);
Ted Kremenek42730c52008-01-07 19:49:32 +00001513 argT = Context->getObjCSelType();
Fariborz Jahanianc26b2502007-12-03 19:17:29 +00001514 assert(!argT.isNull() && "Can't find 'SEL' type");
1515 ArgTys.push_back(argT);
Ted Kremenek42730c52008-01-07 19:49:32 +00001516 QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
Fariborz Jahanianc26b2502007-12-03 19:17:29 +00001517 &ArgTys[0], ArgTys.size(),
1518 true /*isVariadic*/);
1519 MsgSendSuperStretFunctionDecl = new FunctionDecl(SourceLocation(),
1520 msgSendIdent, msgSendType,
1521 FunctionDecl::Extern, false, 0);
1522}
1523
Fariborz Jahanian1d29b5d2007-12-03 21:26:48 +00001524// SynthMsgSendFpretFunctionDecl - id objc_msgSend_fpret(id self, SEL op, ...);
1525void RewriteTest::SynthMsgSendFpretFunctionDecl() {
1526 IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_fpret");
1527 llvm::SmallVector<QualType, 16> ArgTys;
Ted Kremenek42730c52008-01-07 19:49:32 +00001528 QualType argT = Context->getObjCIdType();
Fariborz Jahanian1d29b5d2007-12-03 21:26:48 +00001529 assert(!argT.isNull() && "Can't find 'id' type");
1530 ArgTys.push_back(argT);
Ted Kremenek42730c52008-01-07 19:49:32 +00001531 argT = Context->getObjCSelType();
Fariborz Jahanian1d29b5d2007-12-03 21:26:48 +00001532 assert(!argT.isNull() && "Can't find 'SEL' type");
1533 ArgTys.push_back(argT);
Ted Kremenek42730c52008-01-07 19:49:32 +00001534 QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
Fariborz Jahanian1d29b5d2007-12-03 21:26:48 +00001535 &ArgTys[0], ArgTys.size(),
1536 true /*isVariadic*/);
1537 MsgSendFpretFunctionDecl = new FunctionDecl(SourceLocation(),
1538 msgSendIdent, msgSendType,
1539 FunctionDecl::Extern, false, 0);
1540}
1541
Steve Naroff02a82aa2007-10-30 23:14:51 +00001542// SynthGetClassFunctionDecl - id objc_getClass(const char *name);
1543void RewriteTest::SynthGetClassFunctionDecl() {
1544 IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass");
1545 llvm::SmallVector<QualType, 16> ArgTys;
1546 ArgTys.push_back(Context->getPointerType(
1547 Context->CharTy.getQualifiedType(QualType::Const)));
Ted Kremenek42730c52008-01-07 19:49:32 +00001548 QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
Steve Naroff02a82aa2007-10-30 23:14:51 +00001549 &ArgTys[0], ArgTys.size(),
1550 false /*isVariadic*/);
1551 GetClassFunctionDecl = new FunctionDecl(SourceLocation(),
1552 getClassIdent, getClassType,
1553 FunctionDecl::Extern, false, 0);
1554}
1555
Steve Naroff3b1caac2007-12-07 03:50:46 +00001556// SynthGetMetaClassFunctionDecl - id objc_getClass(const char *name);
1557void RewriteTest::SynthGetMetaClassFunctionDecl() {
1558 IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass");
1559 llvm::SmallVector<QualType, 16> ArgTys;
1560 ArgTys.push_back(Context->getPointerType(
1561 Context->CharTy.getQualifiedType(QualType::Const)));
Ted Kremenek42730c52008-01-07 19:49:32 +00001562 QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
Steve Naroff3b1caac2007-12-07 03:50:46 +00001563 &ArgTys[0], ArgTys.size(),
1564 false /*isVariadic*/);
1565 GetMetaClassFunctionDecl = new FunctionDecl(SourceLocation(),
1566 getClassIdent, getClassType,
1567 FunctionDecl::Extern, false, 0);
1568}
1569
Steve Naroffabb96362007-11-08 14:30:50 +00001570// SynthCFStringFunctionDecl - id __builtin___CFStringMakeConstantString(const char *name);
1571void RewriteTest::SynthCFStringFunctionDecl() {
1572 IdentifierInfo *getClassIdent = &Context->Idents.get("__builtin___CFStringMakeConstantString");
1573 llvm::SmallVector<QualType, 16> ArgTys;
1574 ArgTys.push_back(Context->getPointerType(
1575 Context->CharTy.getQualifiedType(QualType::Const)));
Ted Kremenek42730c52008-01-07 19:49:32 +00001576 QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
Steve Naroffabb96362007-11-08 14:30:50 +00001577 &ArgTys[0], ArgTys.size(),
1578 false /*isVariadic*/);
1579 CFStringFunctionDecl = new FunctionDecl(SourceLocation(),
1580 getClassIdent, getClassType,
1581 FunctionDecl::Extern, false, 0);
1582}
1583
Steve Naroff0add5d22007-11-03 11:27:19 +00001584Stmt *RewriteTest::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
Steve Naroffabb96362007-11-08 14:30:50 +00001585#if 1
1586 // This rewrite is specific to GCC, which has builtin support for CFString.
1587 if (!CFStringFunctionDecl)
1588 SynthCFStringFunctionDecl();
1589 // Create a call to __builtin___CFStringMakeConstantString("cstr").
1590 llvm::SmallVector<Expr*, 8> StrExpr;
1591 StrExpr.push_back(Exp->getString());
1592 CallExpr *call = SynthesizeCallToFunctionDecl(CFStringFunctionDecl,
1593 &StrExpr[0], StrExpr.size());
1594 // cast to NSConstantString *
1595 CastExpr *cast = new CastExpr(Exp->getType(), call, SourceLocation());
Steve Naroffe4e5e262007-12-19 14:32:56 +00001596 if (Rewrite.ReplaceStmt(Exp, cast)) {
1597 // replacement failed.
Steve Naroffbcf0a922007-12-19 19:16:49 +00001598 unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Warning,
1599 "rewriting sub-expression within a macro (may not be correct)");
Steve Naroffe4e5e262007-12-19 14:32:56 +00001600 SourceRange Range = Exp->getSourceRange();
1601 Diags.Report(Context->getFullLoc(Exp->getAtLoc()), DiagID, 0, 0, &Range, 1);
Steve Naroffe4e5e262007-12-19 14:32:56 +00001602 }
Steve Naroffabb96362007-11-08 14:30:50 +00001603 delete Exp;
1604 return cast;
1605#else
Steve Naroff0add5d22007-11-03 11:27:19 +00001606 assert(ConstantStringClassReference && "Can't find constant string reference");
1607 llvm::SmallVector<Expr*, 4> InitExprs;
1608
1609 // Synthesize "(Class)&_NSConstantStringClassReference"
1610 DeclRefExpr *ClsRef = new DeclRefExpr(ConstantStringClassReference,
1611 ConstantStringClassReference->getType(),
1612 SourceLocation());
1613 QualType expType = Context->getPointerType(ClsRef->getType());
1614 UnaryOperator *Unop = new UnaryOperator(ClsRef, UnaryOperator::AddrOf,
1615 expType, SourceLocation());
Ted Kremenek42730c52008-01-07 19:49:32 +00001616 CastExpr *cast = new CastExpr(Context->getObjCClassType(), Unop,
Steve Naroff0add5d22007-11-03 11:27:19 +00001617 SourceLocation());
1618 InitExprs.push_back(cast); // set the 'isa'.
1619 InitExprs.push_back(Exp->getString()); // set "char *bytes".
1620 unsigned IntSize = static_cast<unsigned>(
1621 Context->getTypeSize(Context->IntTy, Exp->getLocStart()));
1622 llvm::APInt IntVal(IntSize, Exp->getString()->getByteLength());
1623 IntegerLiteral *len = new IntegerLiteral(IntVal, Context->IntTy,
1624 Exp->getLocStart());
1625 InitExprs.push_back(len); // set "int numBytes".
1626
1627 // struct NSConstantString
1628 QualType CFConstantStrType = Context->getCFConstantStringType();
1629 // (struct NSConstantString) { <exprs from above> }
1630 InitListExpr *ILE = new InitListExpr(SourceLocation(),
1631 &InitExprs[0], InitExprs.size(),
1632 SourceLocation());
Steve Naroffbe37fc02008-01-14 18:19:28 +00001633 CompoundLiteralExpr *StrRep = new CompoundLiteralExpr(CFConstantStrType, ILE, false);
Steve Naroff0add5d22007-11-03 11:27:19 +00001634 // struct NSConstantString *
1635 expType = Context->getPointerType(StrRep->getType());
1636 Unop = new UnaryOperator(StrRep, UnaryOperator::AddrOf, expType,
1637 SourceLocation());
Steve Naroff4242b972007-11-05 14:36:37 +00001638 // cast to NSConstantString *
1639 cast = new CastExpr(Exp->getType(), Unop, SourceLocation());
Steve Naroff0add5d22007-11-03 11:27:19 +00001640 Rewrite.ReplaceStmt(Exp, cast);
1641 delete Exp;
Steve Naroff4242b972007-11-05 14:36:37 +00001642 return cast;
Steve Naroffabb96362007-11-08 14:30:50 +00001643#endif
Steve Naroff0add5d22007-11-03 11:27:19 +00001644}
1645
Ted Kremenek42730c52008-01-07 19:49:32 +00001646ObjCInterfaceDecl *RewriteTest::isSuperReceiver(Expr *recExpr) {
Steve Naroff3b1caac2007-12-07 03:50:46 +00001647 // check if we are sending a message to 'super'
1648 if (CurMethodDecl && CurMethodDecl->isInstance()) {
Steve Naroff764c1ae2007-11-15 10:28:18 +00001649 if (CastExpr *CE = dyn_cast<CastExpr>(recExpr)) {
1650 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) {
1651 if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
1652 if (!strcmp(PVD->getName(), "self")) {
Fariborz Jahaniane76e8412007-12-17 21:03:50 +00001653 // is this id<P1..> type?
Ted Kremenek42730c52008-01-07 19:49:32 +00001654 if (CE->getType()->isObjCQualifiedIdType())
Fariborz Jahaniane76e8412007-12-17 21:03:50 +00001655 return 0;
Steve Naroff764c1ae2007-11-15 10:28:18 +00001656 if (const PointerType *PT = CE->getType()->getAsPointerType()) {
Ted Kremenek42730c52008-01-07 19:49:32 +00001657 if (ObjCInterfaceType *IT =
1658 dyn_cast<ObjCInterfaceType>(PT->getPointeeType())) {
Steve Naroff764c1ae2007-11-15 10:28:18 +00001659 if (IT->getDecl() ==
1660 CurMethodDecl->getClassInterface()->getSuperClass())
1661 return IT->getDecl();
1662 }
1663 }
1664 }
1665 }
1666 }
Steve Naroff3b1caac2007-12-07 03:50:46 +00001667 }
Steve Naroff764c1ae2007-11-15 10:28:18 +00001668 }
1669 return 0;
1670}
1671
1672// struct objc_super { struct objc_object *receiver; struct objc_class *super; };
1673QualType RewriteTest::getSuperStructType() {
1674 if (!SuperStructDecl) {
1675 SuperStructDecl = new RecordDecl(Decl::Struct, SourceLocation(),
1676 &Context->Idents.get("objc_super"), 0);
1677 QualType FieldTypes[2];
1678
1679 // struct objc_object *receiver;
Ted Kremenek42730c52008-01-07 19:49:32 +00001680 FieldTypes[0] = Context->getObjCIdType();
Steve Naroff764c1ae2007-11-15 10:28:18 +00001681 // struct objc_class *super;
Ted Kremenek42730c52008-01-07 19:49:32 +00001682 FieldTypes[1] = Context->getObjCClassType();
Steve Naroff764c1ae2007-11-15 10:28:18 +00001683 // Create fields
1684 FieldDecl *FieldDecls[2];
1685
1686 for (unsigned i = 0; i < 2; ++i)
1687 FieldDecls[i] = new FieldDecl(SourceLocation(), 0, FieldTypes[i]);
1688
1689 SuperStructDecl->defineBody(FieldDecls, 4);
1690 }
1691 return Context->getTagDeclType(SuperStructDecl);
1692}
1693
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +00001694Stmt *RewriteTest::SynthMessageExpr(ObjCMessageExpr *Exp) {
Fariborz Jahanianfb8e9912007-12-04 21:47:40 +00001695 if (!SelGetUidFunctionDecl)
1696 SynthSelGetUidFunctionDecl();
Steve Naroff02a82aa2007-10-30 23:14:51 +00001697 if (!MsgSendFunctionDecl)
1698 SynthMsgSendFunctionDecl();
Steve Naroff764c1ae2007-11-15 10:28:18 +00001699 if (!MsgSendSuperFunctionDecl)
1700 SynthMsgSendSuperFunctionDecl();
Fariborz Jahanianc26b2502007-12-03 19:17:29 +00001701 if (!MsgSendStretFunctionDecl)
1702 SynthMsgSendStretFunctionDecl();
1703 if (!MsgSendSuperStretFunctionDecl)
1704 SynthMsgSendSuperStretFunctionDecl();
Fariborz Jahanian1d29b5d2007-12-03 21:26:48 +00001705 if (!MsgSendFpretFunctionDecl)
1706 SynthMsgSendFpretFunctionDecl();
Steve Naroff02a82aa2007-10-30 23:14:51 +00001707 if (!GetClassFunctionDecl)
1708 SynthGetClassFunctionDecl();
Steve Naroff3b1caac2007-12-07 03:50:46 +00001709 if (!GetMetaClassFunctionDecl)
1710 SynthGetMetaClassFunctionDecl();
Fariborz Jahanianc26b2502007-12-03 19:17:29 +00001711
Steve Naroff764c1ae2007-11-15 10:28:18 +00001712 // default to objc_msgSend().
Fariborz Jahanianc26b2502007-12-03 19:17:29 +00001713 FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl;
1714 // May need to use objc_msgSend_stret() as well.
1715 FunctionDecl *MsgSendStretFlavor = 0;
Ted Kremenek42730c52008-01-07 19:49:32 +00001716 if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) {
Fariborz Jahanianc26b2502007-12-03 19:17:29 +00001717 QualType resultType = mDecl->getResultType();
1718 if (resultType.getCanonicalType()->isStructureType()
1719 || resultType.getCanonicalType()->isUnionType())
1720 MsgSendStretFlavor = MsgSendStretFunctionDecl;
Fariborz Jahanian1d29b5d2007-12-03 21:26:48 +00001721 else if (resultType.getCanonicalType()->isRealFloatingType())
1722 MsgSendFlavor = MsgSendFpretFunctionDecl;
Fariborz Jahanianc26b2502007-12-03 19:17:29 +00001723 }
Steve Naroff764c1ae2007-11-15 10:28:18 +00001724
Steve Naroff71226032007-10-24 22:48:43 +00001725 // Synthesize a call to objc_msgSend().
1726 llvm::SmallVector<Expr*, 8> MsgExprs;
1727 IdentifierInfo *clsName = Exp->getClassName();
1728
1729 // Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend().
1730 if (clsName) { // class message.
Steve Naroff3b1caac2007-12-07 03:50:46 +00001731 if (!strcmp(clsName->getName(), "super")) {
1732 MsgSendFlavor = MsgSendSuperFunctionDecl;
1733 if (MsgSendStretFlavor)
1734 MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
1735 assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
1736
Ted Kremenek42730c52008-01-07 19:49:32 +00001737 ObjCInterfaceDecl *SuperDecl =
Steve Naroff3b1caac2007-12-07 03:50:46 +00001738 CurMethodDecl->getClassInterface()->getSuperClass();
1739
1740 llvm::SmallVector<Expr*, 4> InitExprs;
1741
1742 // set the receiver to self, the first argument to all methods.
1743 InitExprs.push_back(new DeclRefExpr(CurMethodDecl->getSelfDecl(),
Ted Kremenek42730c52008-01-07 19:49:32 +00001744 Context->getObjCIdType(),
Steve Naroff3b1caac2007-12-07 03:50:46 +00001745 SourceLocation()));
1746 llvm::SmallVector<Expr*, 8> ClsExprs;
1747 QualType argType = Context->getPointerType(Context->CharTy);
1748 ClsExprs.push_back(new StringLiteral(SuperDecl->getIdentifier()->getName(),
1749 SuperDecl->getIdentifier()->getLength(),
1750 false, argType, SourceLocation(),
1751 SourceLocation()));
1752 CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
1753 &ClsExprs[0],
1754 ClsExprs.size());
1755 // To turn off a warning, type-cast to 'id'
1756 InitExprs.push_back(
Ted Kremenek42730c52008-01-07 19:49:32 +00001757 new CastExpr(Context->getObjCIdType(),
Steve Naroff3b1caac2007-12-07 03:50:46 +00001758 Cls, SourceLocation())); // set 'super class', using objc_getClass().
1759 // struct objc_super
1760 QualType superType = getSuperStructType();
1761 // (struct objc_super) { <exprs from above> }
1762 InitListExpr *ILE = new InitListExpr(SourceLocation(),
1763 &InitExprs[0], InitExprs.size(),
1764 SourceLocation());
Chris Lattner386ab8a2008-01-02 21:46:24 +00001765 CompoundLiteralExpr *SuperRep = new CompoundLiteralExpr(SourceLocation(),
Steve Naroffbe37fc02008-01-14 18:19:28 +00001766 superType, ILE, false);
Steve Naroff3b1caac2007-12-07 03:50:46 +00001767 // struct objc_super *
1768 Expr *Unop = new UnaryOperator(SuperRep, UnaryOperator::AddrOf,
1769 Context->getPointerType(SuperRep->getType()),
1770 SourceLocation());
1771 MsgExprs.push_back(Unop);
1772 } else {
1773 llvm::SmallVector<Expr*, 8> ClsExprs;
1774 QualType argType = Context->getPointerType(Context->CharTy);
1775 ClsExprs.push_back(new StringLiteral(clsName->getName(),
1776 clsName->getLength(),
1777 false, argType, SourceLocation(),
1778 SourceLocation()));
1779 CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
1780 &ClsExprs[0],
1781 ClsExprs.size());
1782 MsgExprs.push_back(Cls);
1783 }
Steve Naroff885e2122007-11-14 23:54:14 +00001784 } else { // instance message.
1785 Expr *recExpr = Exp->getReceiver();
Steve Naroff764c1ae2007-11-15 10:28:18 +00001786
Ted Kremenek42730c52008-01-07 19:49:32 +00001787 if (ObjCInterfaceDecl *SuperDecl = isSuperReceiver(recExpr)) {
Steve Naroff764c1ae2007-11-15 10:28:18 +00001788 MsgSendFlavor = MsgSendSuperFunctionDecl;
Fariborz Jahanianc26b2502007-12-03 19:17:29 +00001789 if (MsgSendStretFlavor)
1790 MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
Steve Naroff764c1ae2007-11-15 10:28:18 +00001791 assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
1792
1793 llvm::SmallVector<Expr*, 4> InitExprs;
1794
Fariborz Jahaniandc25ba72007-12-04 22:32:58 +00001795 InitExprs.push_back(
Ted Kremenek42730c52008-01-07 19:49:32 +00001796 new CastExpr(Context->getObjCIdType(),
Fariborz Jahaniandc25ba72007-12-04 22:32:58 +00001797 recExpr, SourceLocation())); // set the 'receiver'.
Steve Naroff764c1ae2007-11-15 10:28:18 +00001798
1799 llvm::SmallVector<Expr*, 8> ClsExprs;
1800 QualType argType = Context->getPointerType(Context->CharTy);
Steve Naroff3b1caac2007-12-07 03:50:46 +00001801 ClsExprs.push_back(new StringLiteral(SuperDecl->getIdentifier()->getName(),
1802 SuperDecl->getIdentifier()->getLength(),
Steve Naroff764c1ae2007-11-15 10:28:18 +00001803 false, argType, SourceLocation(),
1804 SourceLocation()));
1805 CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
Fariborz Jahaniandc25ba72007-12-04 22:32:58 +00001806 &ClsExprs[0],
1807 ClsExprs.size());
Fariborz Jahanianfabf3bf2007-12-05 17:29:46 +00001808 // To turn off a warning, type-cast to 'id'
Fariborz Jahaniandc25ba72007-12-04 22:32:58 +00001809 InitExprs.push_back(
Ted Kremenek42730c52008-01-07 19:49:32 +00001810 new CastExpr(Context->getObjCIdType(),
Fariborz Jahaniandc25ba72007-12-04 22:32:58 +00001811 Cls, SourceLocation())); // set 'super class', using objc_getClass().
Steve Naroff764c1ae2007-11-15 10:28:18 +00001812 // struct objc_super
1813 QualType superType = getSuperStructType();
1814 // (struct objc_super) { <exprs from above> }
1815 InitListExpr *ILE = new InitListExpr(SourceLocation(),
1816 &InitExprs[0], InitExprs.size(),
1817 SourceLocation());
Chris Lattner386ab8a2008-01-02 21:46:24 +00001818 CompoundLiteralExpr *SuperRep = new CompoundLiteralExpr(SourceLocation(),
Steve Naroffbe37fc02008-01-14 18:19:28 +00001819 superType, ILE, false);
Steve Naroff764c1ae2007-11-15 10:28:18 +00001820 // struct objc_super *
1821 Expr *Unop = new UnaryOperator(SuperRep, UnaryOperator::AddrOf,
1822 Context->getPointerType(SuperRep->getType()),
1823 SourceLocation());
1824 MsgExprs.push_back(Unop);
1825 } else {
Fariborz Jahanianbe4283c2007-12-07 21:21:21 +00001826 // Remove all type-casts because it may contain objc-style types; e.g.
1827 // Foo<Proto> *.
1828 while (CastExpr *CE = dyn_cast<CastExpr>(recExpr))
1829 recExpr = CE->getSubExpr();
Ted Kremenek42730c52008-01-07 19:49:32 +00001830 recExpr = new CastExpr(Context->getObjCIdType(), recExpr, SourceLocation());
Steve Naroff764c1ae2007-11-15 10:28:18 +00001831 MsgExprs.push_back(recExpr);
1832 }
Steve Naroff885e2122007-11-14 23:54:14 +00001833 }
Steve Naroff0add5d22007-11-03 11:27:19 +00001834 // Create a call to sel_registerName("selName"), it will be the 2nd argument.
Steve Naroff71226032007-10-24 22:48:43 +00001835 llvm::SmallVector<Expr*, 8> SelExprs;
1836 QualType argType = Context->getPointerType(Context->CharTy);
1837 SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
1838 Exp->getSelector().getName().size(),
1839 false, argType, SourceLocation(),
1840 SourceLocation()));
1841 CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
1842 &SelExprs[0], SelExprs.size());
1843 MsgExprs.push_back(SelExp);
1844
1845 // Now push any user supplied arguments.
1846 for (unsigned i = 0; i < Exp->getNumArgs(); i++) {
Steve Naroff885e2122007-11-14 23:54:14 +00001847 Expr *userExpr = Exp->getArg(i);
Steve Naroff6b759ce2007-11-15 02:58:25 +00001848 // Make all implicit casts explicit...ICE comes in handy:-)
1849 if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) {
1850 // Reuse the ICE type, it is exactly what the doctor ordered.
Ted Kremenek42730c52008-01-07 19:49:32 +00001851 userExpr = new CastExpr(ICE->getType()->isObjCQualifiedIdType()
1852 ? Context->getObjCIdType()
Fariborz Jahaniane76e8412007-12-17 21:03:50 +00001853 : ICE->getType(), userExpr, SourceLocation());
Fariborz Jahaniandcb2b1e2007-12-18 21:33:44 +00001854 }
1855 // Make id<P...> cast into an 'id' cast.
1856 else if (CastExpr *CE = dyn_cast<CastExpr>(userExpr)) {
Ted Kremenek42730c52008-01-07 19:49:32 +00001857 if (CE->getType()->isObjCQualifiedIdType()) {
Fariborz Jahaniandcb2b1e2007-12-18 21:33:44 +00001858 while ((CE = dyn_cast<CastExpr>(userExpr)))
1859 userExpr = CE->getSubExpr();
Ted Kremenek42730c52008-01-07 19:49:32 +00001860 userExpr = new CastExpr(Context->getObjCIdType(),
Fariborz Jahaniandcb2b1e2007-12-18 21:33:44 +00001861 userExpr, SourceLocation());
1862 }
Steve Naroff6b759ce2007-11-15 02:58:25 +00001863 }
Steve Naroff885e2122007-11-14 23:54:14 +00001864 MsgExprs.push_back(userExpr);
Steve Naroff71226032007-10-24 22:48:43 +00001865 // We've transferred the ownership to MsgExprs. Null out the argument in
1866 // the original expression, since we will delete it below.
1867 Exp->setArg(i, 0);
1868 }
Steve Naroff0744c472007-11-04 22:37:50 +00001869 // Generate the funky cast.
1870 CastExpr *cast;
1871 llvm::SmallVector<QualType, 8> ArgTypes;
1872 QualType returnType;
1873
1874 // Push 'id' and 'SEL', the 2 implicit arguments.
Steve Naroff0c04bb62007-11-15 10:43:57 +00001875 if (MsgSendFlavor == MsgSendSuperFunctionDecl)
1876 ArgTypes.push_back(Context->getPointerType(getSuperStructType()));
1877 else
Ted Kremenek42730c52008-01-07 19:49:32 +00001878 ArgTypes.push_back(Context->getObjCIdType());
1879 ArgTypes.push_back(Context->getObjCSelType());
1880 if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) {
Steve Naroff0744c472007-11-04 22:37:50 +00001881 // Push any user argument types.
Steve Naroff4242b972007-11-05 14:36:37 +00001882 for (int i = 0; i < mDecl->getNumParams(); i++) {
Ted Kremenek42730c52008-01-07 19:49:32 +00001883 QualType t = mDecl->getParamDecl(i)->getType()->isObjCQualifiedIdType()
1884 ? Context->getObjCIdType()
Fariborz Jahaniane76e8412007-12-17 21:03:50 +00001885 : mDecl->getParamDecl(i)->getType();
Steve Naroff4242b972007-11-05 14:36:37 +00001886 ArgTypes.push_back(t);
1887 }
Ted Kremenek42730c52008-01-07 19:49:32 +00001888 returnType = mDecl->getResultType()->isObjCQualifiedIdType()
1889 ? Context->getObjCIdType() : mDecl->getResultType();
Steve Naroff0744c472007-11-04 22:37:50 +00001890 } else {
Ted Kremenek42730c52008-01-07 19:49:32 +00001891 returnType = Context->getObjCIdType();
Steve Naroff0744c472007-11-04 22:37:50 +00001892 }
1893 // Get the type, we will need to reference it in a couple spots.
Steve Naroff764c1ae2007-11-15 10:28:18 +00001894 QualType msgSendType = MsgSendFlavor->getType();
Steve Naroff0744c472007-11-04 22:37:50 +00001895
1896 // Create a reference to the objc_msgSend() declaration.
Fariborz Jahanianc26b2502007-12-03 19:17:29 +00001897 DeclRefExpr *DRE = new DeclRefExpr(MsgSendFlavor, msgSendType,
1898 SourceLocation());
Steve Naroff0744c472007-11-04 22:37:50 +00001899
1900 // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid).
1901 // If we don't do this cast, we get the following bizarre warning/note:
1902 // xx.m:13: warning: function called through a non-compatible type
1903 // xx.m:13: note: if this code is reached, the program will abort
1904 cast = new CastExpr(Context->getPointerType(Context->VoidTy), DRE,
1905 SourceLocation());
Steve Naroff29fe7462007-11-15 12:35:21 +00001906
Steve Naroff0744c472007-11-04 22:37:50 +00001907 // Now do the "normal" pointer to function cast.
1908 QualType castType = Context->getFunctionType(returnType,
Fariborz Jahanianefba8c82007-12-06 19:49:56 +00001909 &ArgTypes[0], ArgTypes.size(),
1910 Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false);
Steve Naroff0744c472007-11-04 22:37:50 +00001911 castType = Context->getPointerType(castType);
1912 cast = new CastExpr(castType, cast, SourceLocation());
1913
1914 // Don't forget the parens to enforce the proper binding.
1915 ParenExpr *PE = new ParenExpr(SourceLocation(), SourceLocation(), cast);
1916
1917 const FunctionType *FT = msgSendType->getAsFunctionType();
1918 CallExpr *CE = new CallExpr(PE, &MsgExprs[0], MsgExprs.size(),
1919 FT->getResultType(), SourceLocation());
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +00001920 Stmt *ReplacingStmt = CE;
Fariborz Jahanianc26b2502007-12-03 19:17:29 +00001921 if (MsgSendStretFlavor) {
1922 // We have the method which returns a struct/union. Must also generate
1923 // call to objc_msgSend_stret and hang both varieties on a conditional
1924 // expression which dictate which one to envoke depending on size of
1925 // method's return type.
1926
1927 // Create a reference to the objc_msgSend_stret() declaration.
1928 DeclRefExpr *STDRE = new DeclRefExpr(MsgSendStretFlavor, msgSendType,
1929 SourceLocation());
1930 // Need to cast objc_msgSend_stret to "void *" (see above comment).
1931 cast = new CastExpr(Context->getPointerType(Context->VoidTy), STDRE,
1932 SourceLocation());
1933 // Now do the "normal" pointer to function cast.
1934 castType = Context->getFunctionType(returnType,
Fariborz Jahanianefba8c82007-12-06 19:49:56 +00001935 &ArgTypes[0], ArgTypes.size(),
1936 Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false);
Fariborz Jahanianc26b2502007-12-03 19:17:29 +00001937 castType = Context->getPointerType(castType);
1938 cast = new CastExpr(castType, cast, SourceLocation());
1939
1940 // Don't forget the parens to enforce the proper binding.
1941 PE = new ParenExpr(SourceLocation(), SourceLocation(), cast);
1942
1943 FT = msgSendType->getAsFunctionType();
1944 CallExpr *STCE = new CallExpr(PE, &MsgExprs[0], MsgExprs.size(),
1945 FT->getResultType(), SourceLocation());
1946
1947 // Build sizeof(returnType)
1948 SizeOfAlignOfTypeExpr *sizeofExpr = new SizeOfAlignOfTypeExpr(true,
1949 returnType, Context->getSizeType(),
1950 SourceLocation(), SourceLocation());
1951 // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
1952 // FIXME: Value of 8 is base on ppc32/x86 ABI for the most common cases.
1953 // For X86 it is more complicated and some kind of target specific routine
1954 // is needed to decide what to do.
1955 unsigned IntSize = static_cast<unsigned>(
1956 Context->getTypeSize(Context->IntTy, SourceLocation()));
1957
1958 IntegerLiteral *limit = new IntegerLiteral(llvm::APInt(IntSize, 8),
1959 Context->IntTy,
1960 SourceLocation());
1961 BinaryOperator *lessThanExpr = new BinaryOperator(sizeofExpr, limit,
1962 BinaryOperator::LE,
1963 Context->IntTy,
1964 SourceLocation());
1965 // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
1966 ConditionalOperator *CondExpr =
1967 new ConditionalOperator(lessThanExpr, CE, STCE, returnType);
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +00001968 ReplacingStmt = new ParenExpr(SourceLocation(), SourceLocation(), CondExpr);
Fariborz Jahanianc26b2502007-12-03 19:17:29 +00001969 }
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +00001970 return ReplacingStmt;
1971}
1972
1973Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) {
1974 Stmt *ReplacingStmt = SynthMessageExpr(Exp);
Steve Naroff71226032007-10-24 22:48:43 +00001975 // Now do the actual rewrite.
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +00001976 if (Rewrite.ReplaceStmt(Exp, ReplacingStmt)) {
Steve Naroffe4e5e262007-12-19 14:32:56 +00001977 // replacement failed.
Steve Naroffbcf0a922007-12-19 19:16:49 +00001978 unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Warning,
1979 "rewriting sub-expression within a macro (may not be correct)");
Steve Naroffe4e5e262007-12-19 14:32:56 +00001980 SourceRange Range = Exp->getSourceRange();
1981 Diags.Report(Context->getFullLoc(Exp->getLocStart()), DiagID, 0, 0, &Range, 1);
Steve Naroffe4e5e262007-12-19 14:32:56 +00001982 }
Steve Naroff71226032007-10-24 22:48:43 +00001983
Chris Lattner0021f452007-10-24 16:57:36 +00001984 delete Exp;
Fariborz Jahanian9ea6a2d2008-01-08 22:06:28 +00001985 return ReplacingStmt;
Steve Naroffe9780582007-10-23 23:50:29 +00001986}
1987
Fariborz Jahanian6ff57c62007-12-07 18:47:10 +00001988/// RewriteObjCProtocolExpr - Rewrite a protocol expression into
1989/// call to objc_getProtocol("proto-name").
1990Stmt *RewriteTest::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
1991 if (!GetProtocolFunctionDecl)
1992 SynthGetProtocolFunctionDecl();
1993 // Create a call to objc_getProtocol("ProtocolName").
1994 llvm::SmallVector<Expr*, 8> ProtoExprs;
1995 QualType argType = Context->getPointerType(Context->CharTy);
1996 ProtoExprs.push_back(new StringLiteral(Exp->getProtocol()->getName(),
1997 strlen(Exp->getProtocol()->getName()),
1998 false, argType, SourceLocation(),
1999 SourceLocation()));
2000 CallExpr *ProtoExp = SynthesizeCallToFunctionDecl(GetProtocolFunctionDecl,
2001 &ProtoExprs[0],
2002 ProtoExprs.size());
Steve Naroffe4e5e262007-12-19 14:32:56 +00002003 if (Rewrite.ReplaceStmt(Exp, ProtoExp)) {
2004 // replacement failed.
Steve Naroffbcf0a922007-12-19 19:16:49 +00002005 unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Warning,
2006 "rewriting sub-expression within a macro (may not be correct)");
Steve Naroffe4e5e262007-12-19 14:32:56 +00002007 SourceRange Range = Exp->getSourceRange();
2008 Diags.Report(Context->getFullLoc(Exp->getAtLoc()), DiagID, 0, 0, &Range, 1);
Steve Naroffe4e5e262007-12-19 14:32:56 +00002009 }
Fariborz Jahanian6ff57c62007-12-07 18:47:10 +00002010 delete Exp;
2011 return ProtoExp;
2012
2013}
2014
Ted Kremenek42730c52008-01-07 19:49:32 +00002015/// SynthesizeObjCInternalStruct - Rewrite one internal struct corresponding to
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00002016/// an objective-c class with ivars.
Ted Kremenek42730c52008-01-07 19:49:32 +00002017void RewriteTest::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00002018 std::string &Result) {
Ted Kremenek42730c52008-01-07 19:49:32 +00002019 assert(CDecl && "Class missing in SynthesizeObjCInternalStruct");
2020 assert(CDecl->getName() && "Name missing in SynthesizeObjCInternalStruct");
Fariborz Jahanianfb4f6a32007-10-31 23:08:24 +00002021 // Do not synthesize more than once.
Ted Kremenek42730c52008-01-07 19:49:32 +00002022 if (ObjCSynthesizedStructs.count(CDecl))
Fariborz Jahanianfb4f6a32007-10-31 23:08:24 +00002023 return;
Ted Kremenek42730c52008-01-07 19:49:32 +00002024 ObjCInterfaceDecl *RCDecl = CDecl->getSuperClass();
Steve Naroffdd2e26c2007-11-12 13:56:41 +00002025 int NumIvars = CDecl->getNumInstanceVariables();
Steve Naroff2c7afc92007-11-14 19:25:57 +00002026 SourceLocation LocStart = CDecl->getLocStart();
2027 SourceLocation LocEnd = CDecl->getLocEnd();
2028
2029 const char *startBuf = SM->getCharacterData(LocStart);
2030 const char *endBuf = SM->getCharacterData(LocEnd);
Fariborz Jahanian920cde32007-11-26 19:52:57 +00002031 // If no ivars and no root or if its root, directly or indirectly,
2032 // have no ivars (thus not synthesized) then no need to synthesize this class.
Ted Kremenek42730c52008-01-07 19:49:32 +00002033 if (NumIvars <= 0 && (!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) {
Fariborz Jahanian920cde32007-11-26 19:52:57 +00002034 endBuf += Lexer::MeasureTokenLength(LocEnd, *SM);
2035 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
2036 Result.c_str(), Result.size());
2037 return;
2038 }
2039
2040 // FIXME: This has potential of causing problem. If
Ted Kremenek42730c52008-01-07 19:49:32 +00002041 // SynthesizeObjCInternalStruct is ever called recursively.
Fariborz Jahanian920cde32007-11-26 19:52:57 +00002042 Result += "\nstruct ";
2043 Result += CDecl->getName();
Steve Naroff2c7afc92007-11-14 19:25:57 +00002044
Fariborz Jahanian6acfa2b2007-10-31 17:29:28 +00002045 if (NumIvars > 0) {
Steve Naroff2c7afc92007-11-14 19:25:57 +00002046 const char *cursor = strchr(startBuf, '{');
2047 assert((cursor && endBuf)
Ted Kremenek42730c52008-01-07 19:49:32 +00002048 && "SynthesizeObjCInternalStruct - malformed @interface");
Steve Naroff2c7afc92007-11-14 19:25:57 +00002049
2050 // rewrite the original header *without* disturbing the '{'
2051 Rewrite.ReplaceText(LocStart, cursor-startBuf-1,
2052 Result.c_str(), Result.size());
Ted Kremenek42730c52008-01-07 19:49:32 +00002053 if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) {
Steve Naroff2c7afc92007-11-14 19:25:57 +00002054 Result = "\n struct ";
2055 Result += RCDecl->getName();
Steve Narofff2ee53f2007-12-07 22:15:58 +00002056 // Note: We don't name the field decl. This simplifies the "codegen" for
2057 // accessing a superclasses instance variables (and is similar to what gcc
2058 // does internally). The unnamed struct field feature is enabled with
2059 // -fms-extensions. If the struct definition were "inlined", we wouldn't
2060 // need to use this switch. That said, I don't want to inline the def.
Steve Naroff2c7afc92007-11-14 19:25:57 +00002061 Result += ";\n";
2062
2063 // insert the super class structure definition.
2064 SourceLocation OnePastCurly = LocStart.getFileLocWithOffset(cursor-startBuf+1);
2065 Rewrite.InsertText(OnePastCurly, Result.c_str(), Result.size());
2066 }
2067 cursor++; // past '{'
2068
2069 // Now comment out any visibility specifiers.
2070 while (cursor < endBuf) {
2071 if (*cursor == '@') {
2072 SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
Chris Lattnerf04ead52007-11-14 22:57:51 +00002073 // Skip whitespace.
2074 for (++cursor; cursor[0] == ' ' || cursor[0] == '\t'; ++cursor)
2075 /*scan*/;
2076
Fariborz Jahanian6acfa2b2007-10-31 17:29:28 +00002077 // FIXME: presence of @public, etc. inside comment results in
2078 // this transformation as well, which is still correct c-code.
Steve Naroff2c7afc92007-11-14 19:25:57 +00002079 if (!strncmp(cursor, "public", strlen("public")) ||
2080 !strncmp(cursor, "private", strlen("private")) ||
Fariborz Jahanian8d9c7352007-11-14 22:26:25 +00002081 !strncmp(cursor, "protected", strlen("protected")))
Steve Naroff2c7afc92007-11-14 19:25:57 +00002082 Rewrite.InsertText(atLoc, "// ", 3);
Fariborz Jahanian6acfa2b2007-10-31 17:29:28 +00002083 }
Fariborz Jahanian8d9c7352007-11-14 22:26:25 +00002084 // FIXME: If there are cases where '<' is used in ivar declaration part
2085 // of user code, then scan the ivar list and use needToScanForQualifiers
2086 // for type checking.
2087 else if (*cursor == '<') {
2088 SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
2089 Rewrite.InsertText(atLoc, "/* ", 3);
2090 cursor = strchr(cursor, '>');
2091 cursor++;
2092 atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
2093 Rewrite.InsertText(atLoc, " */", 3);
2094 }
Steve Naroff2c7afc92007-11-14 19:25:57 +00002095 cursor++;
Fariborz Jahanian6acfa2b2007-10-31 17:29:28 +00002096 }
Steve Naroff2c7afc92007-11-14 19:25:57 +00002097 // Don't forget to add a ';'!!
2098 Rewrite.InsertText(LocEnd.getFileLocWithOffset(1), ";", 1);
2099 } else { // we don't have any instance variables - insert super struct.
2100 endBuf += Lexer::MeasureTokenLength(LocEnd, *SM);
2101 Result += " {\n struct ";
2102 Result += RCDecl->getName();
Steve Narofff2ee53f2007-12-07 22:15:58 +00002103 // Note: We don't name the field decl. This simplifies the "codegen" for
2104 // accessing a superclasses instance variables (and is similar to what gcc
2105 // does internally). The unnamed struct field feature is enabled with
2106 // -fms-extensions. If the struct definition were "inlined", we wouldn't
2107 // need to use this switch. That said, I don't want to inline the def.
Steve Naroff2c7afc92007-11-14 19:25:57 +00002108 Result += ";\n};\n";
2109 Rewrite.ReplaceText(LocStart, endBuf-startBuf,
2110 Result.c_str(), Result.size());
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00002111 }
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00002112 // Mark this struct as having been generated.
Ted Kremenek42730c52008-01-07 19:49:32 +00002113 if (!ObjCSynthesizedStructs.insert(CDecl))
2114 assert(false && "struct already synthesize- SynthesizeObjCInternalStruct");
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00002115}
2116
Ted Kremenek42730c52008-01-07 19:49:32 +00002117// RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002118/// class methods.
Ted Kremenek42730c52008-01-07 19:49:32 +00002119void RewriteTest::RewriteObjCMethodsMetaData(instmeth_iterator MethodBegin,
Chris Lattnerdea5bec2007-12-12 07:46:12 +00002120 instmeth_iterator MethodEnd,
Fariborz Jahaniana3986372007-10-25 00:14:44 +00002121 bool IsInstanceMethod,
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002122 const char *prefix,
Chris Lattnerc3aa5c42007-10-25 17:07:24 +00002123 const char *ClassName,
2124 std::string &Result) {
Chris Lattnerdea5bec2007-12-12 07:46:12 +00002125 if (MethodBegin == MethodEnd) return;
2126
Fariborz Jahanian04455192007-10-22 21:41:37 +00002127 static bool objc_impl_method = false;
Chris Lattnerdea5bec2007-12-12 07:46:12 +00002128 if (!objc_impl_method) {
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002129 /* struct _objc_method {
Fariborz Jahanian04455192007-10-22 21:41:37 +00002130 SEL _cmd;
2131 char *method_types;
2132 void *_imp;
2133 }
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002134 */
Chris Lattnerc3aa5c42007-10-25 17:07:24 +00002135 Result += "\nstruct _objc_method {\n";
2136 Result += "\tSEL _cmd;\n";
2137 Result += "\tchar *method_types;\n";
2138 Result += "\tvoid *_imp;\n";
2139 Result += "};\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002140
2141 /* struct _objc_method_list {
2142 struct _objc_method_list *next_method;
2143 int method_count;
2144 struct _objc_method method_list[];
2145 }
2146 */
2147 Result += "\nstruct _objc_method_list {\n";
2148 Result += "\tstruct _objc_method_list *next_method;\n";
2149 Result += "\tint method_count;\n";
2150 Result += "\tstruct _objc_method method_list[];\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002151 objc_impl_method = true;
Fariborz Jahanian96b55da2007-10-19 00:36:46 +00002152 }
Chris Lattnerdea5bec2007-12-12 07:46:12 +00002153
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002154 // Build _objc_method_list for class's methods if needed
Chris Lattnerdea5bec2007-12-12 07:46:12 +00002155 Result += "\nstatic struct _objc_method_list _OBJC_";
2156 Result += prefix;
2157 Result += IsInstanceMethod ? "INSTANCE" : "CLASS";
2158 Result += "_METHODS_";
2159 Result += ClassName;
2160 Result += " __attribute__ ((section (\"__OBJC, __";
2161 Result += IsInstanceMethod ? "inst" : "cls";
2162 Result += "_meth\")))= ";
2163 Result += "{\n\t0, " + utostr(MethodEnd-MethodBegin) + "\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002164
Chris Lattnerdea5bec2007-12-12 07:46:12 +00002165 Result += "\t,{{(SEL)\"";
2166 Result += (*MethodBegin)->getSelector().getName().c_str();
2167 std::string MethodTypeString;
Ted Kremenek42730c52008-01-07 19:49:32 +00002168 Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
Chris Lattnerdea5bec2007-12-12 07:46:12 +00002169 Result += "\", \"";
2170 Result += MethodTypeString;
2171 Result += "\", ";
2172 Result += MethodInternalNames[*MethodBegin];
2173 Result += "}\n";
2174 for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) {
2175 Result += "\t ,{(SEL)\"";
2176 Result += (*MethodBegin)->getSelector().getName().c_str();
Fariborz Jahanianc81f3162007-10-29 22:57:28 +00002177 std::string MethodTypeString;
Ted Kremenek42730c52008-01-07 19:49:32 +00002178 Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
Fariborz Jahanianc81f3162007-10-29 22:57:28 +00002179 Result += "\", \"";
2180 Result += MethodTypeString;
Fariborz Jahanianbd2fd922007-11-13 21:02:00 +00002181 Result += "\", ";
Chris Lattnerdea5bec2007-12-12 07:46:12 +00002182 Result += MethodInternalNames[*MethodBegin];
Fariborz Jahanianbd2fd922007-11-13 21:02:00 +00002183 Result += "}\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +00002184 }
Chris Lattnerdea5bec2007-12-12 07:46:12 +00002185 Result += "\t }\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002186}
2187
Ted Kremenek42730c52008-01-07 19:49:32 +00002188/// RewriteObjCProtocolsMetaData - Rewrite protocols meta-data.
2189void RewriteTest::RewriteObjCProtocolsMetaData(ObjCProtocolDecl **Protocols,
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002190 int NumProtocols,
2191 const char *prefix,
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002192 const char *ClassName,
2193 std::string &Result) {
Fariborz Jahanian04455192007-10-22 21:41:37 +00002194 static bool objc_protocol_methods = false;
Fariborz Jahanian04455192007-10-22 21:41:37 +00002195 if (NumProtocols > 0) {
Fariborz Jahanian04455192007-10-22 21:41:37 +00002196 for (int i = 0; i < NumProtocols; i++) {
Ted Kremenek42730c52008-01-07 19:49:32 +00002197 ObjCProtocolDecl *PDecl = Protocols[i];
Fariborz Jahanian04455192007-10-22 21:41:37 +00002198 // Output struct protocol_methods holder of method selector and type.
2199 if (!objc_protocol_methods &&
2200 (PDecl->getNumInstanceMethods() > 0
2201 || PDecl->getNumClassMethods() > 0)) {
2202 /* struct protocol_methods {
2203 SEL _cmd;
2204 char *method_types;
2205 }
2206 */
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002207 Result += "\nstruct protocol_methods {\n";
2208 Result += "\tSEL _cmd;\n";
2209 Result += "\tchar *method_types;\n";
2210 Result += "};\n";
2211
2212 /* struct _objc_protocol_method_list {
2213 int protocol_method_count;
2214 struct protocol_methods protocols[];
2215 }
2216 */
2217 Result += "\nstruct _objc_protocol_method_list {\n";
2218 Result += "\tint protocol_method_count;\n";
2219 Result += "\tstruct protocol_methods protocols[];\n};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +00002220 objc_protocol_methods = true;
2221 }
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002222
Fariborz Jahanianbe63dd52007-12-17 17:56:10 +00002223 int NumMethods = PDecl->getNumInstanceMethods();
2224 if(NumMethods > 0) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002225 Result += "\nstatic struct _objc_protocol_method_list "
2226 "_OBJC_PROTOCOL_INSTANCE_METHODS_";
2227 Result += PDecl->getName();
2228 Result += " __attribute__ ((section (\"__OBJC, __cat_inst_meth\")))= "
2229 "{\n\t" + utostr(NumMethods) + "\n";
2230
Fariborz Jahanianbe63dd52007-12-17 17:56:10 +00002231 // Output instance methods declared in this protocol.
Ted Kremenek42730c52008-01-07 19:49:32 +00002232 for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(),
Fariborz Jahanianbe63dd52007-12-17 17:56:10 +00002233 E = PDecl->instmeth_end(); I != E; ++I) {
2234 if (I == PDecl->instmeth_begin())
2235 Result += "\t ,{{(SEL)\"";
2236 else
2237 Result += "\t ,{(SEL)\"";
2238 Result += (*I)->getSelector().getName().c_str();
2239 std::string MethodTypeString;
Ted Kremenek42730c52008-01-07 19:49:32 +00002240 Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
Fariborz Jahanianbe63dd52007-12-17 17:56:10 +00002241 Result += "\", \"";
2242 Result += MethodTypeString;
2243 Result += "\"}\n";
2244 }
2245 Result += "\t }\n};\n";
2246 }
Fariborz Jahanian04455192007-10-22 21:41:37 +00002247
2248 // Output class methods declared in this protocol.
2249 NumMethods = PDecl->getNumClassMethods();
2250 if (NumMethods > 0) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002251 Result += "\nstatic struct _objc_protocol_method_list "
2252 "_OBJC_PROTOCOL_CLASS_METHODS_";
2253 Result += PDecl->getName();
2254 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
2255 "{\n\t";
2256 Result += utostr(NumMethods);
2257 Result += "\n";
2258
Fariborz Jahanian65a3d852007-12-17 18:07:01 +00002259 // Output instance methods declared in this protocol.
Ted Kremenek42730c52008-01-07 19:49:32 +00002260 for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(),
Fariborz Jahanian65a3d852007-12-17 18:07:01 +00002261 E = PDecl->classmeth_end(); I != E; ++I) {
2262 if (I == PDecl->classmeth_begin())
2263 Result += "\t ,{{(SEL)\"";
2264 else
2265 Result += "\t ,{(SEL)\"";
Steve Naroff2ce399a2007-12-14 23:37:57 +00002266 Result += (*I)->getSelector().getName().c_str();
Fariborz Jahanianc81f3162007-10-29 22:57:28 +00002267 std::string MethodTypeString;
Ted Kremenek42730c52008-01-07 19:49:32 +00002268 Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
Fariborz Jahanianc81f3162007-10-29 22:57:28 +00002269 Result += "\", \"";
2270 Result += MethodTypeString;
2271 Result += "\"}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002272 }
2273 Result += "\t }\n};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +00002274 }
2275 // Output:
2276 /* struct _objc_protocol {
2277 // Objective-C 1.0 extensions
2278 struct _objc_protocol_extension *isa;
2279 char *protocol_name;
2280 struct _objc_protocol **protocol_list;
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002281 struct _objc_protocol_method_list *instance_methods;
2282 struct _objc_protocol_method_list *class_methods;
Fariborz Jahanian04455192007-10-22 21:41:37 +00002283 };
2284 */
2285 static bool objc_protocol = false;
2286 if (!objc_protocol) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002287 Result += "\nstruct _objc_protocol {\n";
2288 Result += "\tstruct _objc_protocol_extension *isa;\n";
2289 Result += "\tchar *protocol_name;\n";
2290 Result += "\tstruct _objc_protocol **protocol_list;\n";
2291 Result += "\tstruct _objc_protocol_method_list *instance_methods;\n";
2292 Result += "\tstruct _objc_protocol_method_list *class_methods;\n";
2293 Result += "};\n";
2294
2295 /* struct _objc_protocol_list {
2296 struct _objc_protocol_list *next;
2297 int protocol_count;
2298 struct _objc_protocol *class_protocols[];
2299 }
2300 */
2301 Result += "\nstruct _objc_protocol_list {\n";
2302 Result += "\tstruct _objc_protocol_list *next;\n";
2303 Result += "\tint protocol_count;\n";
2304 Result += "\tstruct _objc_protocol *class_protocols[];\n";
2305 Result += "};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +00002306 objc_protocol = true;
2307 }
2308
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002309 Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_";
2310 Result += PDecl->getName();
2311 Result += " __attribute__ ((section (\"__OBJC, __protocol\")))= "
2312 "{\n\t0, \"";
2313 Result += PDecl->getName();
2314 Result += "\", 0, ";
Steve Naroff2ce399a2007-12-14 23:37:57 +00002315 if (PDecl->getNumInstanceMethods() > 0) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002316 Result += "&_OBJC_PROTOCOL_INSTANCE_METHODS_";
2317 Result += PDecl->getName();
2318 Result += ", ";
2319 }
Fariborz Jahanian04455192007-10-22 21:41:37 +00002320 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002321 Result += "0, ";
Steve Naroff2ce399a2007-12-14 23:37:57 +00002322 if (PDecl->getNumClassMethods() > 0) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002323 Result += "&_OBJC_PROTOCOL_CLASS_METHODS_";
2324 Result += PDecl->getName();
2325 Result += "\n";
2326 }
Fariborz Jahanian04455192007-10-22 21:41:37 +00002327 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002328 Result += "0\n";
2329 Result += "};\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +00002330 }
Fariborz Jahanian04455192007-10-22 21:41:37 +00002331 // Output the top lovel protocol meta-data for the class.
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002332 Result += "\nstatic struct _objc_protocol_list _OBJC_";
2333 Result += prefix;
2334 Result += "_PROTOCOLS_";
2335 Result += ClassName;
2336 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
2337 "{\n\t0, ";
2338 Result += utostr(NumProtocols);
2339 Result += "\n";
2340
2341 Result += "\t,{&_OBJC_PROTOCOL_";
2342 Result += Protocols[0]->getName();
2343 Result += " \n";
2344
2345 for (int i = 1; i < NumProtocols; i++) {
Ted Kremenek42730c52008-01-07 19:49:32 +00002346 ObjCProtocolDecl *PDecl = Protocols[i];
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002347 Result += "\t ,&_OBJC_PROTOCOL_";
2348 Result += PDecl->getName();
2349 Result += "\n";
Fariborz Jahanian04455192007-10-22 21:41:37 +00002350 }
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002351 Result += "\t }\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002352 }
2353}
2354
Ted Kremenek42730c52008-01-07 19:49:32 +00002355/// RewriteObjCCategoryImplDecl - Rewrite metadata for each category
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002356/// implementation.
Ted Kremenek42730c52008-01-07 19:49:32 +00002357void RewriteTest::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002358 std::string &Result) {
Ted Kremenek42730c52008-01-07 19:49:32 +00002359 ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface();
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002360 // Find category declaration for this implementation.
Ted Kremenek42730c52008-01-07 19:49:32 +00002361 ObjCCategoryDecl *CDecl;
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002362 for (CDecl = ClassDecl->getCategoryList(); CDecl;
2363 CDecl = CDecl->getNextClassCategory())
2364 if (CDecl->getIdentifier() == IDecl->getIdentifier())
2365 break;
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002366
Chris Lattnera661a4d2007-12-23 01:40:15 +00002367 std::string FullCategoryName = ClassDecl->getName();
2368 FullCategoryName += '_';
2369 FullCategoryName += IDecl->getName();
2370
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002371 // Build _objc_method_list for class's instance methods if needed
Ted Kremenek42730c52008-01-07 19:49:32 +00002372 RewriteObjCMethodsMetaData(IDecl->instmeth_begin(), IDecl->instmeth_end(),
Chris Lattnera661a4d2007-12-23 01:40:15 +00002373 true, "CATEGORY_", FullCategoryName.c_str(),
2374 Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002375
2376 // Build _objc_method_list for class's class methods if needed
Ted Kremenek42730c52008-01-07 19:49:32 +00002377 RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
Chris Lattnera661a4d2007-12-23 01:40:15 +00002378 false, "CATEGORY_", FullCategoryName.c_str(),
2379 Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002380
2381 // Protocols referenced in class declaration?
Fariborz Jahaniand256e062007-11-13 22:09:49 +00002382 // Null CDecl is case of a category implementation with no category interface
2383 if (CDecl)
Ted Kremenek42730c52008-01-07 19:49:32 +00002384 RewriteObjCProtocolsMetaData(CDecl->getReferencedProtocols(),
Fariborz Jahaniand256e062007-11-13 22:09:49 +00002385 CDecl->getNumReferencedProtocols(),
2386 "CATEGORY",
Chris Lattnera661a4d2007-12-23 01:40:15 +00002387 FullCategoryName.c_str(), Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002388
2389 /* struct _objc_category {
2390 char *category_name;
2391 char *class_name;
2392 struct _objc_method_list *instance_methods;
2393 struct _objc_method_list *class_methods;
2394 struct _objc_protocol_list *protocols;
2395 // Objective-C 1.0 extensions
2396 uint32_t size; // sizeof (struct _objc_category)
2397 struct _objc_property_list *instance_properties; // category's own
2398 // @property decl.
2399 };
2400 */
2401
2402 static bool objc_category = false;
2403 if (!objc_category) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002404 Result += "\nstruct _objc_category {\n";
2405 Result += "\tchar *category_name;\n";
2406 Result += "\tchar *class_name;\n";
2407 Result += "\tstruct _objc_method_list *instance_methods;\n";
2408 Result += "\tstruct _objc_method_list *class_methods;\n";
2409 Result += "\tstruct _objc_protocol_list *protocols;\n";
2410 Result += "\tunsigned int size;\n";
2411 Result += "\tstruct _objc_property_list *instance_properties;\n";
2412 Result += "};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002413 objc_category = true;
Fariborz Jahanian04455192007-10-22 21:41:37 +00002414 }
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002415 Result += "\nstatic struct _objc_category _OBJC_CATEGORY_";
2416 Result += FullCategoryName;
2417 Result += " __attribute__ ((section (\"__OBJC, __category\")))= {\n\t\"";
2418 Result += IDecl->getName();
2419 Result += "\"\n\t, \"";
2420 Result += ClassDecl->getName();
2421 Result += "\"\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002422
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002423 if (IDecl->getNumInstanceMethods() > 0) {
2424 Result += "\t, (struct _objc_method_list *)"
2425 "&_OBJC_CATEGORY_INSTANCE_METHODS_";
2426 Result += FullCategoryName;
2427 Result += "\n";
2428 }
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002429 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002430 Result += "\t, 0\n";
2431 if (IDecl->getNumClassMethods() > 0) {
2432 Result += "\t, (struct _objc_method_list *)"
2433 "&_OBJC_CATEGORY_CLASS_METHODS_";
2434 Result += FullCategoryName;
2435 Result += "\n";
2436 }
2437 else
2438 Result += "\t, 0\n";
2439
Fariborz Jahaniand256e062007-11-13 22:09:49 +00002440 if (CDecl && CDecl->getNumReferencedProtocols() > 0) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002441 Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";
2442 Result += FullCategoryName;
2443 Result += "\n";
2444 }
2445 else
2446 Result += "\t, 0\n";
2447 Result += "\t, sizeof(struct _objc_category), 0\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002448}
2449
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00002450/// SynthesizeIvarOffsetComputation - This rutine synthesizes computation of
2451/// ivar offset.
Ted Kremenek42730c52008-01-07 19:49:32 +00002452void RewriteTest::SynthesizeIvarOffsetComputation(ObjCImplementationDecl *IDecl,
2453 ObjCIvarDecl *ivar,
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00002454 std::string &Result) {
Fariborz Jahanian9447e462007-11-05 17:47:33 +00002455 Result += "offsetof(struct ";
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00002456 Result += IDecl->getName();
2457 Result += ", ";
2458 Result += ivar->getName();
2459 Result += ")";
2460}
2461
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002462//===----------------------------------------------------------------------===//
2463// Meta Data Emission
2464//===----------------------------------------------------------------------===//
2465
Ted Kremenek42730c52008-01-07 19:49:32 +00002466void RewriteTest::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002467 std::string &Result) {
Ted Kremenek42730c52008-01-07 19:49:32 +00002468 ObjCInterfaceDecl *CDecl = IDecl->getClassInterface();
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002469
Fariborz Jahanian7e216522007-11-26 20:59:57 +00002470 // Explictly declared @interface's are already synthesized.
2471 if (CDecl->ImplicitInterfaceDecl()) {
2472 // FIXME: Implementation of a class with no @interface (legacy) doese not
2473 // produce correct synthesis as yet.
Ted Kremenek42730c52008-01-07 19:49:32 +00002474 SynthesizeObjCInternalStruct(CDecl, Result);
Fariborz Jahanian7e216522007-11-26 20:59:57 +00002475 }
Fariborz Jahanianab3ec252007-10-26 23:09:28 +00002476
Chris Lattnerc7b06752007-12-12 07:56:42 +00002477 // Build _objc_ivar_list metadata for classes ivars if needed
2478 int NumIvars = IDecl->getImplDeclNumIvars() > 0
2479 ? IDecl->getImplDeclNumIvars()
2480 : (CDecl ? CDecl->getNumInstanceVariables() : 0);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002481 if (NumIvars > 0) {
2482 static bool objc_ivar = false;
2483 if (!objc_ivar) {
2484 /* struct _objc_ivar {
2485 char *ivar_name;
2486 char *ivar_type;
2487 int ivar_offset;
2488 };
2489 */
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002490 Result += "\nstruct _objc_ivar {\n";
2491 Result += "\tchar *ivar_name;\n";
2492 Result += "\tchar *ivar_type;\n";
2493 Result += "\tint ivar_offset;\n";
2494 Result += "};\n";
2495
2496 /* struct _objc_ivar_list {
2497 int ivar_count;
2498 struct _objc_ivar ivar_list[];
2499 };
2500 */
2501 Result += "\nstruct _objc_ivar_list {\n";
2502 Result += "\tint ivar_count;\n";
2503 Result += "\tstruct _objc_ivar ivar_list[];\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002504 objc_ivar = true;
2505 }
2506
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002507 Result += "\nstatic struct _objc_ivar_list _OBJC_INSTANCE_VARIABLES_";
2508 Result += IDecl->getName();
2509 Result += " __attribute__ ((section (\"__OBJC, __instance_vars\")))= "
2510 "{\n\t";
2511 Result += utostr(NumIvars);
2512 Result += "\n";
Chris Lattnerc7b06752007-12-12 07:56:42 +00002513
Ted Kremenek42730c52008-01-07 19:49:32 +00002514 ObjCInterfaceDecl::ivar_iterator IVI, IVE;
Chris Lattnerc7b06752007-12-12 07:56:42 +00002515 if (IDecl->getImplDeclNumIvars() > 0) {
2516 IVI = IDecl->ivar_begin();
2517 IVE = IDecl->ivar_end();
2518 } else {
2519 IVI = CDecl->ivar_begin();
2520 IVE = CDecl->ivar_end();
2521 }
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002522 Result += "\t,{{\"";
Chris Lattnerc7b06752007-12-12 07:56:42 +00002523 Result += (*IVI)->getName();
Fariborz Jahaniand5ea4612007-10-29 17:16:25 +00002524 Result += "\", \"";
2525 std::string StrEncoding;
Fariborz Jahanian248db262008-01-22 22:44:46 +00002526 Context->getObjCEncodingForType((*IVI)->getType(), StrEncoding,
2527 EncodingRecordTypes);
Fariborz Jahaniand5ea4612007-10-29 17:16:25 +00002528 Result += StrEncoding;
2529 Result += "\", ";
Chris Lattnerc7b06752007-12-12 07:56:42 +00002530 SynthesizeIvarOffsetComputation(IDecl, *IVI, Result);
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00002531 Result += "}\n";
Chris Lattnerc7b06752007-12-12 07:56:42 +00002532 for (++IVI; IVI != IVE; ++IVI) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002533 Result += "\t ,{\"";
Chris Lattnerc7b06752007-12-12 07:56:42 +00002534 Result += (*IVI)->getName();
Fariborz Jahaniand5ea4612007-10-29 17:16:25 +00002535 Result += "\", \"";
2536 std::string StrEncoding;
Fariborz Jahanian248db262008-01-22 22:44:46 +00002537 Context->getObjCEncodingForType((*IVI)->getType(), StrEncoding,
2538 EncodingRecordTypes);
Fariborz Jahaniand5ea4612007-10-29 17:16:25 +00002539 Result += StrEncoding;
2540 Result += "\", ";
Chris Lattnerc7b06752007-12-12 07:56:42 +00002541 SynthesizeIvarOffsetComputation(IDecl, (*IVI), Result);
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00002542 Result += "}\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002543 }
2544
2545 Result += "\t }\n};\n";
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002546 }
2547
2548 // Build _objc_method_list for class's instance methods if needed
Ted Kremenek42730c52008-01-07 19:49:32 +00002549 RewriteObjCMethodsMetaData(IDecl->instmeth_begin(), IDecl->instmeth_end(),
Chris Lattnerdea5bec2007-12-12 07:46:12 +00002550 true, "", IDecl->getName(), Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002551
2552 // Build _objc_method_list for class's class methods if needed
Ted Kremenek42730c52008-01-07 19:49:32 +00002553 RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
Chris Lattnerdea5bec2007-12-12 07:46:12 +00002554 false, "", IDecl->getName(), Result);
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002555
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002556 // Protocols referenced in class declaration?
Ted Kremenek42730c52008-01-07 19:49:32 +00002557 RewriteObjCProtocolsMetaData(CDecl->getReferencedProtocols(),
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002558 CDecl->getNumIntfRefProtocols(),
Chris Lattnerdea5bec2007-12-12 07:46:12 +00002559 "CLASS", CDecl->getName(), Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002560
Fariborz Jahanian0f013d12007-10-23 00:02:02 +00002561
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00002562 // Declaration of class/meta-class metadata
2563 /* struct _objc_class {
2564 struct _objc_class *isa; // or const char *root_class_name when metadata
Fariborz Jahanian0f013d12007-10-23 00:02:02 +00002565 const char *super_class_name;
2566 char *name;
2567 long version;
2568 long info;
2569 long instance_size;
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00002570 struct _objc_ivar_list *ivars;
2571 struct _objc_method_list *methods;
Fariborz Jahanian0f013d12007-10-23 00:02:02 +00002572 struct objc_cache *cache;
2573 struct objc_protocol_list *protocols;
2574 const char *ivar_layout;
2575 struct _objc_class_ext *ext;
2576 };
2577 */
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00002578 static bool objc_class = false;
2579 if (!objc_class) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002580 Result += "\nstruct _objc_class {\n";
2581 Result += "\tstruct _objc_class *isa;\n";
2582 Result += "\tconst char *super_class_name;\n";
2583 Result += "\tchar *name;\n";
2584 Result += "\tlong version;\n";
2585 Result += "\tlong info;\n";
2586 Result += "\tlong instance_size;\n";
2587 Result += "\tstruct _objc_ivar_list *ivars;\n";
2588 Result += "\tstruct _objc_method_list *methods;\n";
2589 Result += "\tstruct objc_cache *cache;\n";
2590 Result += "\tstruct _objc_protocol_list *protocols;\n";
2591 Result += "\tconst char *ivar_layout;\n";
2592 Result += "\tstruct _objc_class_ext *ext;\n";
2593 Result += "};\n";
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00002594 objc_class = true;
Fariborz Jahanian0f013d12007-10-23 00:02:02 +00002595 }
2596
2597 // Meta-class metadata generation.
Ted Kremenek42730c52008-01-07 19:49:32 +00002598 ObjCInterfaceDecl *RootClass = 0;
2599 ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass();
Fariborz Jahanian0f013d12007-10-23 00:02:02 +00002600 while (SuperClass) {
2601 RootClass = SuperClass;
2602 SuperClass = SuperClass->getSuperClass();
2603 }
2604 SuperClass = CDecl->getSuperClass();
2605
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002606 Result += "\nstatic struct _objc_class _OBJC_METACLASS_";
2607 Result += CDecl->getName();
2608 Result += " __attribute__ ((section (\"__OBJC, __meta_class\")))= "
2609 "{\n\t(struct _objc_class *)\"";
2610 Result += (RootClass ? RootClass->getName() : CDecl->getName());
2611 Result += "\"";
2612
2613 if (SuperClass) {
2614 Result += ", \"";
2615 Result += SuperClass->getName();
2616 Result += "\", \"";
2617 Result += CDecl->getName();
2618 Result += "\"";
2619 }
2620 else {
2621 Result += ", 0, \"";
2622 Result += CDecl->getName();
2623 Result += "\"";
2624 }
Ted Kremenek42730c52008-01-07 19:49:32 +00002625 // Set 'ivars' field for root class to 0. ObjC1 runtime does not use it.
Fariborz Jahanian0f013d12007-10-23 00:02:02 +00002626 // 'info' field is initialized to CLS_META(2) for metaclass
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002627 Result += ", 0,2, sizeof(struct _objc_class), 0";
Steve Naroffbde81042007-12-05 21:49:40 +00002628 if (IDecl->getNumClassMethods() > 0) {
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002629 Result += "\n\t, &_OBJC_CLASS_METHODS_";
Steve Naroffbde81042007-12-05 21:49:40 +00002630 Result += IDecl->getName();
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002631 Result += "\n";
2632 }
Fariborz Jahanian0f013d12007-10-23 00:02:02 +00002633 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002634 Result += ", 0\n";
2635 if (CDecl->getNumIntfRefProtocols() > 0) {
2636 Result += "\t,0, &_OBJC_CLASS_PROTOCOLS_";
2637 Result += CDecl->getName();
2638 Result += ",0,0\n";
2639 }
Fariborz Jahanian0cb4d922007-10-24 20:54:23 +00002640 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002641 Result += "\t,0,0,0,0\n";
2642 Result += "};\n";
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00002643
2644 // class metadata generation.
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002645 Result += "\nstatic struct _objc_class _OBJC_CLASS_";
2646 Result += CDecl->getName();
2647 Result += " __attribute__ ((section (\"__OBJC, __class\")))= "
2648 "{\n\t&_OBJC_METACLASS_";
2649 Result += CDecl->getName();
2650 if (SuperClass) {
2651 Result += ", \"";
2652 Result += SuperClass->getName();
2653 Result += "\", \"";
2654 Result += CDecl->getName();
2655 Result += "\"";
2656 }
2657 else {
2658 Result += ", 0, \"";
2659 Result += CDecl->getName();
2660 Result += "\"";
2661 }
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00002662 // 'info' field is initialized to CLS_CLASS(1) for class
Fariborz Jahanianab3ec252007-10-26 23:09:28 +00002663 Result += ", 0,1";
Ted Kremenek42730c52008-01-07 19:49:32 +00002664 if (!ObjCSynthesizedStructs.count(CDecl))
Fariborz Jahanianab3ec252007-10-26 23:09:28 +00002665 Result += ",0";
2666 else {
2667 // class has size. Must synthesize its size.
Fariborz Jahanian9447e462007-11-05 17:47:33 +00002668 Result += ",sizeof(struct ";
Fariborz Jahanianab3ec252007-10-26 23:09:28 +00002669 Result += CDecl->getName();
2670 Result += ")";
2671 }
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002672 if (NumIvars > 0) {
2673 Result += ", &_OBJC_INSTANCE_VARIABLES_";
2674 Result += CDecl->getName();
2675 Result += "\n\t";
2676 }
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00002677 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002678 Result += ",0";
2679 if (IDecl->getNumInstanceMethods() > 0) {
2680 Result += ", &_OBJC_INSTANCE_METHODS_";
2681 Result += CDecl->getName();
2682 Result += ", 0\n\t";
2683 }
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00002684 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002685 Result += ",0,0";
2686 if (CDecl->getNumIntfRefProtocols() > 0) {
2687 Result += ", &_OBJC_CLASS_PROTOCOLS_";
2688 Result += CDecl->getName();
2689 Result += ", 0,0\n";
2690 }
Fariborz Jahanianf8fa1e72007-10-23 18:53:48 +00002691 else
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002692 Result += ",0,0,0\n";
2693 Result += "};\n";
Fariborz Jahanian0f013d12007-10-23 00:02:02 +00002694}
Fariborz Jahanian45d52f72007-10-18 22:09:03 +00002695
Fariborz Jahanian8c664912007-11-13 19:21:13 +00002696/// RewriteImplementations - This routine rewrites all method implementations
2697/// and emits meta-data.
2698
2699void RewriteTest::RewriteImplementations(std::string &Result) {
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00002700 int ClsDefCount = ClassImplementation.size();
2701 int CatDefCount = CategoryImplementation.size();
Fariborz Jahanian8c664912007-11-13 19:21:13 +00002702
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00002703 if (ClsDefCount == 0 && CatDefCount == 0)
2704 return;
Fariborz Jahanian8c664912007-11-13 19:21:13 +00002705 // Rewrite implemented methods
2706 for (int i = 0; i < ClsDefCount; i++)
2707 RewriteImplementationDecl(ClassImplementation[i]);
Fariborz Jahanian45d52f72007-10-18 22:09:03 +00002708
Fariborz Jahanian0136e372007-11-13 20:04:28 +00002709 for (int i = 0; i < CatDefCount; i++)
2710 RewriteImplementationDecl(CategoryImplementation[i]);
2711
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00002712 // This is needed for use of offsetof
2713 Result += "#include <stddef.h>\n";
Fariborz Jahanian8c664912007-11-13 19:21:13 +00002714
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002715 // For each implemented class, write out all its meta data.
Fariborz Jahanian45d52f72007-10-18 22:09:03 +00002716 for (int i = 0; i < ClsDefCount; i++)
Ted Kremenek42730c52008-01-07 19:49:32 +00002717 RewriteObjCClassMetaData(ClassImplementation[i], Result);
Fariborz Jahanian9b4e4ff2007-10-24 19:23:36 +00002718
2719 // For each implemented category, write out all its meta data.
2720 for (int i = 0; i < CatDefCount; i++)
Ted Kremenek42730c52008-01-07 19:49:32 +00002721 RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result);
Fariborz Jahanian45d52f72007-10-18 22:09:03 +00002722
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00002723 // Write objc_symtab metadata
2724 /*
2725 struct _objc_symtab
2726 {
2727 long sel_ref_cnt;
2728 SEL *refs;
2729 short cls_def_cnt;
2730 short cat_def_cnt;
2731 void *defs[cls_def_cnt + cat_def_cnt];
2732 };
2733 */
2734
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002735 Result += "\nstruct _objc_symtab {\n";
2736 Result += "\tlong sel_ref_cnt;\n";
2737 Result += "\tSEL *refs;\n";
2738 Result += "\tshort cls_def_cnt;\n";
2739 Result += "\tshort cat_def_cnt;\n";
2740 Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n";
2741 Result += "};\n\n";
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00002742
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002743 Result += "static struct _objc_symtab "
2744 "_OBJC_SYMBOLS __attribute__((section (\"__OBJC, __symbols\")))= {\n";
2745 Result += "\t0, 0, " + utostr(ClsDefCount)
2746 + ", " + utostr(CatDefCount) + "\n";
2747 for (int i = 0; i < ClsDefCount; i++) {
2748 Result += "\t,&_OBJC_CLASS_";
2749 Result += ClassImplementation[i]->getName();
2750 Result += "\n";
2751 }
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00002752
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002753 for (int i = 0; i < CatDefCount; i++) {
2754 Result += "\t,&_OBJC_CATEGORY_";
2755 Result += CategoryImplementation[i]->getClassInterface()->getName();
2756 Result += "_";
2757 Result += CategoryImplementation[i]->getName();
2758 Result += "\n";
2759 }
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00002760
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002761 Result += "};\n\n";
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00002762
2763 // Write objc_module metadata
2764
2765 /*
2766 struct _objc_module {
2767 long version;
2768 long size;
2769 const char *name;
2770 struct _objc_symtab *symtab;
2771 }
2772 */
2773
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002774 Result += "\nstruct _objc_module {\n";
2775 Result += "\tlong version;\n";
2776 Result += "\tlong size;\n";
2777 Result += "\tconst char *name;\n";
2778 Result += "\tstruct _objc_symtab *symtab;\n";
2779 Result += "};\n\n";
2780 Result += "static struct _objc_module "
2781 "_OBJC_MODULES __attribute__ ((section (\"__OBJC, __module_info\")))= {\n";
Fariborz Jahanianf185aef2007-10-26 19:46:17 +00002782 Result += "\t" + utostr(OBJC_ABI_VERSION) +
2783 ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";
Fariborz Jahaniancf89c7e2007-10-25 20:55:25 +00002784 Result += "};\n\n";
Fariborz Jahanian8c664912007-11-13 19:21:13 +00002785
Fariborz Jahanian640a01f2007-10-18 19:23:00 +00002786}
Chris Lattner6fe8b272007-10-16 22:36:42 +00002787