1 //===--- RewriteTest.cpp - Playground for the code rewriter ---------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Hacks and fun related to the code rewriter.
12 //===----------------------------------------------------------------------===//
14 #include "ASTConsumers.h"
15 #include "clang/Rewrite/Rewriter.h"
16 #include "clang/AST/AST.h"
17 #include "clang/AST/ASTConsumer.h"
18 #include "clang/Basic/SourceManager.h"
19 #include "clang/Basic/IdentifierTable.h"
20 #include "clang/Basic/Diagnostic.h"
21 #include "clang/Lex/Lexer.h"
22 #include "llvm/ADT/StringExtras.h"
23 #include "llvm/ADT/SmallPtrSet.h"
24 #include "llvm/Support/MemoryBuffer.h"
25 #include "llvm/Support/CommandLine.h"
27 using namespace clang;
30 static llvm::cl::opt<bool>
31 SilenceRewriteMacroWarning("Wno-rewrite-macros", llvm::cl::init(false),
32 llvm::cl::desc("Silence ObjC rewriting warnings"));
35 class RewriteTest : public ASTConsumer {
38 unsigned RewriteFailedDiag;
43 const char *MainFileStart, *MainFileEnd;
44 SourceLocation LastIncLoc;
45 llvm::SmallVector<ObjCImplementationDecl *, 8> ClassImplementation;
46 llvm::SmallVector<ObjCCategoryImplDecl *, 8> CategoryImplementation;
47 llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCSynthesizedStructs;
48 llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCForwardDecls;
49 llvm::DenseMap<ObjCMethodDecl*, std::string> MethodInternalNames;
50 llvm::SmallVector<Stmt *, 32> Stmts;
51 llvm::SmallVector<int, 8> ObjCBcLabelNo;
52 llvm::SmallVector<const RecordType *, 8> EncodingRecordTypes;
54 FunctionDecl *MsgSendFunctionDecl;
55 FunctionDecl *MsgSendSuperFunctionDecl;
56 FunctionDecl *MsgSendStretFunctionDecl;
57 FunctionDecl *MsgSendSuperStretFunctionDecl;
58 FunctionDecl *MsgSendFpretFunctionDecl;
59 FunctionDecl *GetClassFunctionDecl;
60 FunctionDecl *GetMetaClassFunctionDecl;
61 FunctionDecl *SelGetUidFunctionDecl;
62 FunctionDecl *CFStringFunctionDecl;
63 FunctionDecl *GetProtocolFunctionDecl;
65 // ObjC string constant support.
66 FileVarDecl *ConstantStringClassReference;
67 RecordDecl *NSStringRecord;
69 // ObjC foreach break/continue generation support.
73 ObjCMethodDecl *CurMethodDecl;
74 RecordDecl *SuperStructDecl;
76 // Needed for header files being rewritten
79 static const int OBJC_ABI_VERSION =7 ;
81 void Initialize(ASTContext &context);
84 // Top Level Driver code.
85 virtual void HandleTopLevelDecl(Decl *D);
86 void HandleDeclInMainFile(Decl *D);
87 RewriteTest(bool isHeader, Diagnostic &D) : Diags(D) {
89 RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
90 "rewriting sub-expression within a macro (may not be correct)");
94 void ReplaceStmt(Stmt *Old, Stmt *New) {
95 // If replacement succeeded or warning disabled return with no warning.
96 if (!Rewrite.ReplaceStmt(Old, New) || SilenceRewriteMacroWarning)
99 SourceRange Range = Old->getSourceRange();
100 Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag,
104 void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen) {
105 // If insertion succeeded or warning disabled return with no warning.
106 if (!Rewrite.InsertText(Loc, StrData, StrLen) ||
107 SilenceRewriteMacroWarning)
110 Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag);
113 void RemoveText(SourceLocation Loc, unsigned StrLen) {
114 // If removal succeeded or warning disabled return with no warning.
115 if (!Rewrite.RemoveText(Loc, StrLen) || SilenceRewriteMacroWarning)
118 Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag);
121 void ReplaceText(SourceLocation Start, unsigned OrigLength,
122 const char *NewStr, unsigned NewLength) {
123 // If removal succeeded or warning disabled return with no warning.
124 if (!Rewrite.ReplaceText(Start, OrigLength, NewStr, NewLength) ||
125 SilenceRewriteMacroWarning)
128 Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag);
131 // Syntactic Rewriting.
132 void RewritePrologue(SourceLocation Loc);
133 void RewriteInclude();
135 void RewriteForwardClassDecl(ObjCClassDecl *Dcl);
136 void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl);
137 void RewriteImplementationDecl(NamedDecl *Dcl);
138 void RewriteObjCMethodDecl(ObjCMethodDecl *MDecl, std::string &ResultStr);
139 void RewriteCategoryDecl(ObjCCategoryDecl *Dcl);
140 void RewriteProtocolDecl(ObjCProtocolDecl *Dcl);
141 void RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *Dcl);
142 void RewriteMethodDeclaration(ObjCMethodDecl *Method);
143 void RewriteProperties(int nProperties, ObjCPropertyDecl **Properties);
144 void RewriteFunctionDecl(FunctionDecl *FD);
145 void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl);
146 bool needToScanForQualifiers(QualType T);
147 ObjCInterfaceDecl *isSuperReceiver(Expr *recExpr);
148 QualType getSuperStructType();
150 // Expression Rewriting.
151 Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S);
152 Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
153 Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV);
154 Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp);
155 Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
156 Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp);
157 Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp);
158 Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S);
159 Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S);
160 Stmt *RewriteObjCCatchStmt(ObjCAtCatchStmt *S);
161 Stmt *RewriteObjCFinallyStmt(ObjCAtFinallyStmt *S);
162 Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S);
163 Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
164 SourceLocation OrigEnd);
165 CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD,
166 Expr **args, unsigned nargs);
167 Stmt *SynthMessageExpr(ObjCMessageExpr *Exp);
168 Stmt *RewriteBreakStmt(BreakStmt *S);
169 Stmt *RewriteContinueStmt(ContinueStmt *S);
170 void SynthCountByEnumWithState(std::string &buf);
172 void SynthMsgSendFunctionDecl();
173 void SynthMsgSendSuperFunctionDecl();
174 void SynthMsgSendStretFunctionDecl();
175 void SynthMsgSendFpretFunctionDecl();
176 void SynthMsgSendSuperStretFunctionDecl();
177 void SynthGetClassFunctionDecl();
178 void SynthGetMetaClassFunctionDecl();
179 void SynthCFStringFunctionDecl();
180 void SynthSelGetUidFunctionDecl();
181 void SynthGetProtocolFunctionDecl();
183 // Metadata emission.
184 void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
185 std::string &Result);
187 void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl,
188 std::string &Result);
190 typedef ObjCCategoryImplDecl::instmeth_iterator instmeth_iterator;
191 void RewriteObjCMethodsMetaData(instmeth_iterator MethodBegin,
192 instmeth_iterator MethodEnd,
193 bool IsInstanceMethod,
195 const char *ClassName,
196 std::string &Result);
198 void RewriteObjCProtocolsMetaData(ObjCProtocolDecl **Protocols,
201 const char *ClassName,
202 std::string &Result);
203 void SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
204 std::string &Result);
205 void SynthesizeIvarOffsetComputation(ObjCImplementationDecl *IDecl,
207 std::string &Result);
208 void RewriteImplementations(std::string &Result);
212 static bool IsHeaderFile(const std::string &Filename) {
213 std::string::size_type DotPos = Filename.rfind('.');
215 if (DotPos == std::string::npos) {
220 std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end());
222 // C++ header: .hh or .H;
223 return Ext == "h" || Ext == "hh" || Ext == "H";
226 ASTConsumer *clang::CreateCodeRewriterTest(const std::string& InFile,
228 return new RewriteTest(IsHeaderFile(InFile), Diags);
231 void RewriteTest::Initialize(ASTContext &context) {
233 SM = &Context->getSourceManager();
234 MsgSendFunctionDecl = 0;
235 MsgSendSuperFunctionDecl = 0;
236 MsgSendStretFunctionDecl = 0;
237 MsgSendSuperStretFunctionDecl = 0;
238 MsgSendFpretFunctionDecl = 0;
239 GetClassFunctionDecl = 0;
240 GetMetaClassFunctionDecl = 0;
241 SelGetUidFunctionDecl = 0;
242 CFStringFunctionDecl = 0;
243 GetProtocolFunctionDecl = 0;
244 ConstantStringClassReference = 0;
250 // Get the ID and start/end of the main file.
251 MainFileID = SM->getMainFileID();
252 const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID);
253 MainFileStart = MainBuf->getBufferStart();
254 MainFileEnd = MainBuf->getBufferEnd();
257 Rewrite.setSourceMgr(Context->getSourceManager());
258 // declaring objc_selector outside the parameter list removes a silly
259 // scope related warning...
260 const char *s = "#pragma once\n"
261 "struct objc_selector; struct objc_class;\n"
262 "#ifndef OBJC_SUPER\n"
263 "struct objc_super { struct objc_object *o; "
264 "struct objc_object *superClass; };\n"
265 "#define OBJC_SUPER\n"
267 "#ifndef _REWRITER_typedef_Protocol\n"
268 "typedef struct objc_object Protocol;\n"
269 "#define _REWRITER_typedef_Protocol\n"
271 "extern struct objc_object *objc_msgSend"
272 "(struct objc_object *, struct objc_selector *, ...);\n"
273 "extern struct objc_object *objc_msgSendSuper"
274 "(struct objc_super *, struct objc_selector *, ...);\n"
275 "extern struct objc_object *objc_msgSend_stret"
276 "(struct objc_object *, struct objc_selector *, ...);\n"
277 "extern struct objc_object *objc_msgSendSuper_stret"
278 "(struct objc_super *, struct objc_selector *, ...);\n"
279 "extern struct objc_object *objc_msgSend_fpret"
280 "(struct objc_object *, struct objc_selector *, ...);\n"
281 "extern struct objc_object *objc_getClass"
283 "extern struct objc_object *objc_getMetaClass"
285 "extern void objc_exception_throw(struct objc_object *);\n"
286 "extern void objc_exception_try_enter(void *);\n"
287 "extern void objc_exception_try_exit(void *);\n"
288 "extern struct objc_object *objc_exception_extract(void *);\n"
289 "extern int objc_exception_match"
290 "(struct objc_class *, struct objc_object *, ...);\n"
291 "extern Protocol *objc_getProtocol(const char *);\n"
292 "#include <objc/objc.h>\n"
293 "#ifndef __FASTENUMERATIONSTATE\n"
294 "struct __objcFastEnumerationState {\n\t"
295 "unsigned long state;\n\t"
297 "unsigned long *mutationsPtr;\n\t"
298 "unsigned long extra[5];\n};\n"
299 "#define __FASTENUMERATIONSTATE\n"
302 // insert the whole string when rewriting a header file
303 InsertText(SourceLocation::getFileLoc(MainFileID, 0), s, strlen(s));
306 // Not rewriting header, exclude the #pragma once pragma
307 const char *p = s + strlen("#pragma once\n");
308 InsertText(SourceLocation::getFileLoc(MainFileID, 0), p, strlen(p));
313 //===----------------------------------------------------------------------===//
314 // Top Level Driver Code
315 //===----------------------------------------------------------------------===//
317 void RewriteTest::HandleTopLevelDecl(Decl *D) {
318 // Two cases: either the decl could be in the main file, or it could be in a
319 // #included file. If the former, rewrite it now. If the later, check to see
320 // if we rewrote the #include/#import.
321 SourceLocation Loc = D->getLocation();
322 Loc = SM->getLogicalLoc(Loc);
324 // If this is for a builtin, ignore it.
325 if (Loc.isInvalid()) return;
327 // Look for built-in declarations that we need to refer during the rewrite.
328 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
329 RewriteFunctionDecl(FD);
330 } else if (FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
331 // declared in <Foundation/NSString.h>
332 if (strcmp(FVD->getName(), "_NSConstantStringClassReference") == 0) {
333 ConstantStringClassReference = FVD;
336 } else if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D)) {
337 RewriteInterfaceDecl(MD);
338 } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) {
339 RewriteCategoryDecl(CD);
340 } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
341 RewriteProtocolDecl(PD);
342 } else if (ObjCForwardProtocolDecl *FP =
343 dyn_cast<ObjCForwardProtocolDecl>(D)){
344 RewriteForwardProtocolDecl(FP);
346 // If we have a decl in the main file, see if we should rewrite it.
347 if (SM->getDecomposedFileLoc(Loc).first == MainFileID)
348 return HandleDeclInMainFile(D);
351 /// HandleDeclInMainFile - This is called for each top-level decl defined in the
352 /// main file of the input.
353 void RewriteTest::HandleDeclInMainFile(Decl *D) {
354 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
355 if (Stmt *Body = FD->getBody())
356 FD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
358 if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
359 if (Stmt *Body = MD->getBody()) {
362 MD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
366 if (ObjCImplementationDecl *CI = dyn_cast<ObjCImplementationDecl>(D))
367 ClassImplementation.push_back(CI);
368 else if (ObjCCategoryImplDecl *CI = dyn_cast<ObjCCategoryImplDecl>(D))
369 CategoryImplementation.push_back(CI);
370 else if (ObjCClassDecl *CD = dyn_cast<ObjCClassDecl>(D))
371 RewriteForwardClassDecl(CD);
372 else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
373 RewriteObjCQualifiedInterfaceTypes(VD);
375 RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
380 RewriteTest::~RewriteTest() {
381 // Get the top-level buffer that this corresponds to.
383 // Rewrite tabs if we care.
388 // Rewrite Objective-c meta data*
389 std::string ResultStr;
390 RewriteImplementations(ResultStr);
392 // Get the buffer corresponding to MainFileID. If we haven't changed it, then
394 if (const RewriteBuffer *RewriteBuf =
395 Rewrite.getRewriteBufferFor(MainFileID)) {
396 //printf("Changed:\n");
397 std::string S(RewriteBuf->begin(), RewriteBuf->end());
398 printf("%s\n", S.c_str());
400 printf("No changes\n");
403 printf("%s", ResultStr.c_str());
406 //===----------------------------------------------------------------------===//
407 // Syntactic (non-AST) Rewriting Code
408 //===----------------------------------------------------------------------===//
410 void RewriteTest::RewriteInclude() {
411 SourceLocation LocStart = SourceLocation::getFileLoc(MainFileID, 0);
412 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
413 const char *MainBufStart = MainBuf.first;
414 const char *MainBufEnd = MainBuf.second;
415 size_t ImportLen = strlen("import");
416 size_t IncludeLen = strlen("include");
418 // Loop over the whole file, looking for includes.
419 for (const char *BufPtr = MainBufStart; BufPtr < MainBufEnd; ++BufPtr) {
420 if (*BufPtr == '#') {
421 if (++BufPtr == MainBufEnd)
423 while (*BufPtr == ' ' || *BufPtr == '\t')
424 if (++BufPtr == MainBufEnd)
426 if (!strncmp(BufPtr, "import", ImportLen)) {
427 // replace import with include
428 SourceLocation ImportLoc =
429 LocStart.getFileLocWithOffset(BufPtr-MainBufStart);
430 ReplaceText(ImportLoc, ImportLen, "include", IncludeLen);
437 void RewriteTest::RewriteTabs() {
438 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
439 const char *MainBufStart = MainBuf.first;
440 const char *MainBufEnd = MainBuf.second;
442 // Loop over the whole file, looking for tabs.
443 for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) {
447 // Okay, we found a tab. This tab will turn into at least one character,
448 // but it depends on which 'virtual column' it is in. Compute that now.
450 while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' &&
451 BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r')
454 // Okay, now that we know the virtual column, we know how many spaces to
455 // insert. We assume 8-character tab-stops.
456 unsigned Spaces = 8-(VCol & 7);
458 // Get the location of the tab.
459 SourceLocation TabLoc =
460 SourceLocation::getFileLoc(MainFileID, BufPtr-MainBufStart);
462 // Rewrite the single tab character into a sequence of spaces.
463 ReplaceText(TabLoc, 1, " ", Spaces);
468 void RewriteTest::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) {
469 int numDecls = ClassDecl->getNumForwardDecls();
470 ObjCInterfaceDecl **ForwardDecls = ClassDecl->getForwardDecls();
472 // Get the start location and compute the semi location.
473 SourceLocation startLoc = ClassDecl->getLocation();
474 const char *startBuf = SM->getCharacterData(startLoc);
475 const char *semiPtr = strchr(startBuf, ';');
477 // Translate to typedef's that forward reference structs with the same name
478 // as the class. As a convenience, we include the original declaration
480 std::string typedefString;
481 typedefString += "// ";
482 typedefString.append(startBuf, semiPtr-startBuf+1);
483 typedefString += "\n";
484 for (int i = 0; i < numDecls; i++) {
485 ObjCInterfaceDecl *ForwardDecl = ForwardDecls[i];
486 typedefString += "#ifndef _REWRITER_typedef_";
487 typedefString += ForwardDecl->getName();
488 typedefString += "\n";
489 typedefString += "#define _REWRITER_typedef_";
490 typedefString += ForwardDecl->getName();
491 typedefString += "\n";
492 typedefString += "typedef struct objc_object ";
493 typedefString += ForwardDecl->getName();
494 typedefString += ";\n#endif\n";
497 // Replace the @class with typedefs corresponding to the classes.
498 ReplaceText(startLoc, semiPtr-startBuf+1,
499 typedefString.c_str(), typedefString.size());
502 void RewriteTest::RewriteMethodDeclaration(ObjCMethodDecl *Method) {
503 SourceLocation LocStart = Method->getLocStart();
504 SourceLocation LocEnd = Method->getLocEnd();
506 if (SM->getLineNumber(LocEnd) > SM->getLineNumber(LocStart)) {
507 InsertText(LocStart, "/* ", 3);
508 ReplaceText(LocEnd, 1, ";*/ ", 4);
510 InsertText(LocStart, "// ", 3);
514 void RewriteTest::RewriteProperties(int nProperties, ObjCPropertyDecl **Properties)
516 for (int i = 0; i < nProperties; i++) {
517 ObjCPropertyDecl *Property = Properties[i];
518 SourceLocation Loc = Property->getLocation();
520 ReplaceText(Loc, 0, "// ", 3);
522 // FIXME: handle properties that are declared across multiple lines.
526 void RewriteTest::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
527 SourceLocation LocStart = CatDecl->getLocStart();
529 // FIXME: handle category headers that are declared across multiple lines.
530 ReplaceText(LocStart, 0, "// ", 3);
532 for (ObjCCategoryDecl::instmeth_iterator I = CatDecl->instmeth_begin(),
533 E = CatDecl->instmeth_end(); I != E; ++I)
534 RewriteMethodDeclaration(*I);
535 for (ObjCCategoryDecl::classmeth_iterator I = CatDecl->classmeth_begin(),
536 E = CatDecl->classmeth_end(); I != E; ++I)
537 RewriteMethodDeclaration(*I);
539 // Lastly, comment out the @end.
540 ReplaceText(CatDecl->getAtEndLoc(), 0, "// ", 3);
543 void RewriteTest::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
544 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
546 SourceLocation LocStart = PDecl->getLocStart();
548 // FIXME: handle protocol headers that are declared across multiple lines.
549 ReplaceText(LocStart, 0, "// ", 3);
551 for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(),
552 E = PDecl->instmeth_end(); I != E; ++I)
553 RewriteMethodDeclaration(*I);
554 for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(),
555 E = PDecl->classmeth_end(); I != E; ++I)
556 RewriteMethodDeclaration(*I);
558 // Lastly, comment out the @end.
559 SourceLocation LocEnd = PDecl->getAtEndLoc();
560 ReplaceText(LocEnd, 0, "// ", 3);
562 // Must comment out @optional/@required
563 const char *startBuf = SM->getCharacterData(LocStart);
564 const char *endBuf = SM->getCharacterData(LocEnd);
565 for (const char *p = startBuf; p < endBuf; p++) {
566 if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) {
567 std::string CommentedOptional = "/* @optional */";
568 SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
569 ReplaceText(OptionalLoc, strlen("@optional"),
570 CommentedOptional.c_str(), CommentedOptional.size());
573 else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) {
574 std::string CommentedRequired = "/* @required */";
575 SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
576 ReplaceText(OptionalLoc, strlen("@required"),
577 CommentedRequired.c_str(), CommentedRequired.size());
583 void RewriteTest::RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *PDecl) {
584 SourceLocation LocStart = PDecl->getLocation();
585 if (LocStart.isInvalid())
586 assert(false && "Invalid SourceLocation");
587 // FIXME: handle forward protocol that are declared across multiple lines.
588 ReplaceText(LocStart, 0, "// ", 3);
591 void RewriteTest::RewriteObjCMethodDecl(ObjCMethodDecl *OMD,
592 std::string &ResultStr) {
593 ResultStr += "\nstatic ";
594 if (OMD->getResultType()->isObjCQualifiedIdType())
597 ResultStr += OMD->getResultType().getAsString();
600 // Unique method name
603 if (OMD->isInstance())
608 NameStr += OMD->getClassInterface()->getName();
611 NamedDecl *MethodContext = OMD->getMethodContext();
612 if (ObjCCategoryImplDecl *CID =
613 dyn_cast<ObjCCategoryImplDecl>(MethodContext)) {
614 NameStr += CID->getName();
617 // Append selector names, replacing ':' with '_'
618 const char *selName = OMD->getSelector().getName().c_str();
619 if (!strchr(selName, ':'))
620 NameStr += OMD->getSelector().getName();
622 std::string selString = OMD->getSelector().getName();
623 int len = selString.size();
624 for (int i = 0; i < len; i++)
625 if (selString[i] == ':')
627 NameStr += selString;
629 // Remember this name for metadata emission
630 MethodInternalNames[OMD] = NameStr;
631 ResultStr += NameStr;
636 // invisible arguments
637 if (OMD->isInstance()) {
638 QualType selfTy = Context->getObjCInterfaceType(OMD->getClassInterface());
639 selfTy = Context->getPointerType(selfTy);
640 if (ObjCSynthesizedStructs.count(OMD->getClassInterface()))
641 ResultStr += "struct ";
642 ResultStr += selfTy.getAsString();
645 ResultStr += Context->getObjCIdType().getAsString();
647 ResultStr += " self, ";
648 ResultStr += Context->getObjCSelType().getAsString();
649 ResultStr += " _cmd";
652 for (int i = 0; i < OMD->getNumParams(); i++) {
653 ParmVarDecl *PDecl = OMD->getParamDecl(i);
655 if (PDecl->getType()->isObjCQualifiedIdType())
658 ResultStr += PDecl->getType().getAsString();
660 ResultStr += PDecl->getName();
662 if (OMD->isVariadic())
663 ResultStr += ", ...";
667 void RewriteTest::RewriteImplementationDecl(NamedDecl *OID) {
668 ObjCImplementationDecl *IMD = dyn_cast<ObjCImplementationDecl>(OID);
669 ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(OID);
672 InsertText(IMD->getLocStart(), "// ", 3);
674 InsertText(CID->getLocStart(), "// ", 3);
676 for (ObjCCategoryImplDecl::instmeth_iterator
677 I = IMD ? IMD->instmeth_begin() : CID->instmeth_begin(),
678 E = IMD ? IMD->instmeth_end() : CID->instmeth_end(); I != E; ++I) {
679 std::string ResultStr;
680 ObjCMethodDecl *OMD = *I;
681 RewriteObjCMethodDecl(OMD, ResultStr);
682 SourceLocation LocStart = OMD->getLocStart();
683 SourceLocation LocEnd = OMD->getBody()->getLocStart();
685 const char *startBuf = SM->getCharacterData(LocStart);
686 const char *endBuf = SM->getCharacterData(LocEnd);
687 ReplaceText(LocStart, endBuf-startBuf,
688 ResultStr.c_str(), ResultStr.size());
691 for (ObjCCategoryImplDecl::classmeth_iterator
692 I = IMD ? IMD->classmeth_begin() : CID->classmeth_begin(),
693 E = IMD ? IMD->classmeth_end() : CID->classmeth_end(); I != E; ++I) {
694 std::string ResultStr;
695 ObjCMethodDecl *OMD = *I;
696 RewriteObjCMethodDecl(OMD, ResultStr);
697 SourceLocation LocStart = OMD->getLocStart();
698 SourceLocation LocEnd = OMD->getBody()->getLocStart();
700 const char *startBuf = SM->getCharacterData(LocStart);
701 const char *endBuf = SM->getCharacterData(LocEnd);
702 ReplaceText(LocStart, endBuf-startBuf,
703 ResultStr.c_str(), ResultStr.size());
706 InsertText(IMD->getLocEnd(), "// ", 3);
708 InsertText(CID->getLocEnd(), "// ", 3);
711 void RewriteTest::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
712 std::string ResultStr;
713 if (!ObjCForwardDecls.count(ClassDecl)) {
714 // we haven't seen a forward decl - generate a typedef.
715 ResultStr = "#ifndef _REWRITER_typedef_";
716 ResultStr += ClassDecl->getName();
718 ResultStr += "#define _REWRITER_typedef_";
719 ResultStr += ClassDecl->getName();
721 ResultStr += "typedef struct ";
722 ResultStr += ClassDecl->getName();
724 ResultStr += ClassDecl->getName();
725 ResultStr += ";\n#endif\n";
727 // Mark this typedef as having been generated.
728 ObjCForwardDecls.insert(ClassDecl);
730 SynthesizeObjCInternalStruct(ClassDecl, ResultStr);
732 RewriteProperties(ClassDecl->getNumPropertyDecl(),
733 ClassDecl->getPropertyDecl());
734 for (ObjCInterfaceDecl::instmeth_iterator I = ClassDecl->instmeth_begin(),
735 E = ClassDecl->instmeth_end(); I != E; ++I)
736 RewriteMethodDeclaration(*I);
737 for (ObjCInterfaceDecl::classmeth_iterator I = ClassDecl->classmeth_begin(),
738 E = ClassDecl->classmeth_end(); I != E; ++I)
739 RewriteMethodDeclaration(*I);
741 // Lastly, comment out the @end.
742 ReplaceText(ClassDecl->getAtEndLoc(), 0, "// ", 3);
745 Stmt *RewriteTest::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
746 ObjCIvarDecl *D = IV->getDecl();
747 if (IV->isFreeIvar()) {
748 Expr *Replacement = new MemberExpr(IV->getBase(), true, D,
750 ReplaceStmt(IV, Replacement);
755 /// This code is not right. It seems unnecessary. It breaks use of
756 /// ivar reference used as 'receiver' of an expression; as in:
757 /// [newInv->_container addObject:0];
759 if (const PointerType *pType = IV->getBase()->getType()->getAsPointerType()) {
760 ObjCInterfaceType *intT = dyn_cast<ObjCInterfaceType>(pType->getPointeeType());
761 if (CurMethodDecl->getClassInterface() == intT->getDecl()) {
762 IdentifierInfo *II = intT->getDecl()->getIdentifier();
763 RecordDecl *RD = new RecordDecl(Decl::Struct, SourceLocation(),
765 QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
767 CastExpr *castExpr = new CastExpr(castT, IV->getBase(), SourceLocation());
768 // Don't forget the parens to enforce the proper binding.
769 ParenExpr *PE = new ParenExpr(SourceLocation(), SourceLocation(), castExpr);
770 ReplaceStmt(IV->getBase(), PE);
771 delete IV->getBase();
781 //===----------------------------------------------------------------------===//
782 // Function Body / Expression rewriting
783 //===----------------------------------------------------------------------===//
785 Stmt *RewriteTest::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
786 if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
787 isa<DoStmt>(S) || isa<ForStmt>(S))
789 else if (isa<ObjCForCollectionStmt>(S)) {
791 ObjCBcLabelNo.push_back(++BcLabelCount);
794 SourceLocation OrigStmtEnd = S->getLocEnd();
796 // Start by rewriting all children.
797 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
800 Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(*CI);
805 // Handle specific things.
806 if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
807 return RewriteAtEncode(AtEncode);
809 if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S))
810 return RewriteObjCIvarRefExpr(IvarRefExpr);
812 if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S))
813 return RewriteAtSelector(AtSelector);
815 if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S))
816 return RewriteObjCStringLiteral(AtString);
818 if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {
819 // Before we rewrite it, put the original message expression in a comment.
820 SourceLocation startLoc = MessExpr->getLocStart();
821 SourceLocation endLoc = MessExpr->getLocEnd();
823 const char *startBuf = SM->getCharacterData(startLoc);
824 const char *endBuf = SM->getCharacterData(endLoc);
826 std::string messString;
828 messString.append(startBuf, endBuf-startBuf+1);
831 // FIXME: Missing definition of
832 // InsertText(clang::SourceLocation, char const*, unsigned int).
833 // InsertText(startLoc, messString.c_str(), messString.size());
834 // Tried this, but it didn't work either...
835 // ReplaceText(startLoc, 0, messString.c_str(), messString.size());
836 return RewriteMessageExpr(MessExpr);
839 if (ObjCAtTryStmt *StmtTry = dyn_cast<ObjCAtTryStmt>(S))
840 return RewriteObjCTryStmt(StmtTry);
842 if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast<ObjCAtSynchronizedStmt>(S))
843 return RewriteObjCSynchronizedStmt(StmtTry);
845 if (ObjCAtThrowStmt *StmtThrow = dyn_cast<ObjCAtThrowStmt>(S))
846 return RewriteObjCThrowStmt(StmtThrow);
848 if (ObjCProtocolExpr *ProtocolExp = dyn_cast<ObjCProtocolExpr>(S))
849 return RewriteObjCProtocolExpr(ProtocolExp);
851 if (ObjCForCollectionStmt *StmtForCollection =
852 dyn_cast<ObjCForCollectionStmt>(S))
853 return RewriteObjCForCollectionStmt(StmtForCollection, OrigStmtEnd);
854 if (BreakStmt *StmtBreakStmt =
855 dyn_cast<BreakStmt>(S))
856 return RewriteBreakStmt(StmtBreakStmt);
857 if (ContinueStmt *StmtContinueStmt =
858 dyn_cast<ContinueStmt>(S))
859 return RewriteContinueStmt(StmtContinueStmt);
861 if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
862 isa<DoStmt>(S) || isa<ForStmt>(S)) {
863 assert(!Stmts.empty() && "Statement stack is empty");
864 assert ((isa<SwitchStmt>(Stmts.back()) || isa<WhileStmt>(Stmts.back()) ||
865 isa<DoStmt>(Stmts.back()) || isa<ForStmt>(Stmts.back()))
866 && "Statement stack mismatch");
870 if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) {
871 CastExpr *Replacement = new CastExpr(ICE->getType(), ICE->getSubExpr(), SourceLocation());
873 std::ostringstream Buf;
874 Replacement->printPretty(Buf);
875 const std::string &Str = Buf.str();
877 printf("CAST = %s\n", &Str[0]);
878 InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size());
883 // Return this stmt unmodified.
887 /// SynthCountByEnumWithState - To print:
888 /// ((unsigned int (*)
889 /// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
890 /// (void *)objc_msgSend)((id)l_collection,
891 /// sel_registerName(
892 /// "countByEnumeratingWithState:objects:count:"),
894 /// (id *)items, (unsigned int)16)
896 void RewriteTest::SynthCountByEnumWithState(std::string &buf) {
897 buf += "((unsigned int (*) (id, SEL, struct __objcFastEnumerationState *, "
898 "id *, unsigned int))(void *)objc_msgSend)";
900 buf += "((id)l_collection,\n\t\t";
901 buf += "sel_registerName(\"countByEnumeratingWithState:objects:count:\"),";
903 buf += "&enumState, "
904 "(id *)items, (unsigned int)16)";
907 /// RewriteBreakStmt - Rewrite for a break-stmt inside an ObjC2's foreach
908 /// statement to exit to its outer synthesized loop.
910 Stmt *RewriteTest::RewriteBreakStmt(BreakStmt *S) {
911 if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back()))
913 // replace break with goto __break_label
916 SourceLocation startLoc = S->getLocStart();
917 buf = "goto __break_label_";
918 buf += utostr(ObjCBcLabelNo.back());
919 ReplaceText(startLoc, strlen("break"), buf.c_str(), buf.size());
924 /// RewriteContinueStmt - Rewrite for a continue-stmt inside an ObjC2's foreach
925 /// statement to continue with its inner synthesized loop.
927 Stmt *RewriteTest::RewriteContinueStmt(ContinueStmt *S) {
928 if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back()))
930 // replace continue with goto __continue_label
933 SourceLocation startLoc = S->getLocStart();
934 buf = "goto __continue_label_";
935 buf += utostr(ObjCBcLabelNo.back());
936 ReplaceText(startLoc, strlen("continue"), buf.c_str(), buf.size());
941 /// RewriteObjCForCollectionStmt - Rewriter for ObjC2's foreach statement.
943 /// for ( type elem in collection) { stmts; }
948 /// struct __objcFastEnumerationState enumState = { 0 };
950 /// id l_collection = (id)collection;
951 /// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState
952 /// objects:items count:16];
954 /// unsigned long startMutations = *enumState.mutationsPtr;
956 /// unsigned long counter = 0;
958 /// if (startMutations != *enumState.mutationsPtr)
959 /// objc_enumerationMutation(l_collection);
960 /// elem = (type)enumState.itemsPtr[counter++];
962 /// __continue_label: ;
963 /// } while (counter < limit);
964 /// } while (limit = [l_collection countByEnumeratingWithState:&enumState
965 /// objects:items count:16]);
973 Stmt *RewriteTest::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
974 SourceLocation OrigEnd) {
975 assert(!Stmts.empty() && "ObjCForCollectionStmt - Statement stack empty");
976 assert(isa<ObjCForCollectionStmt>(Stmts.back()) &&
977 "ObjCForCollectionStmt Statement stack mismatch");
978 assert(!ObjCBcLabelNo.empty() &&
979 "ObjCForCollectionStmt - Label No stack empty");
981 SourceLocation startLoc = S->getLocStart();
982 const char *startBuf = SM->getCharacterData(startLoc);
983 const char *elementName;
984 std::string elementTypeAsString;
987 if (DeclStmt *DS = dyn_cast<DeclStmt>(S->getElement())) {
989 QualType ElementType = cast<ValueDecl>(DS->getDecl())->getType();
990 elementTypeAsString = ElementType.getAsString();
991 buf += elementTypeAsString;
993 elementName = DS->getDecl()->getName();
997 else if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S->getElement())) {
998 elementName = DR->getDecl()->getName();
999 elementTypeAsString = DR->getDecl()->getType().getAsString();
1002 assert(false && "RewriteObjCForCollectionStmt - bad element kind");
1004 // struct __objcFastEnumerationState enumState = { 0 };
1005 buf += "struct __objcFastEnumerationState enumState = { 0 };\n\t";
1007 buf += "id items[16];\n\t";
1008 // id l_collection = (id)
1009 buf += "id l_collection = (id)";
1010 // Find start location of 'collection' the hard way!
1011 const char *startCollectionBuf = startBuf;
1012 startCollectionBuf += 3; // skip 'for'
1013 startCollectionBuf = strchr(startCollectionBuf, '(');
1014 startCollectionBuf++; // skip '('
1015 // find 'in' and skip it.
1016 while (*startCollectionBuf != ' ' ||
1017 *(startCollectionBuf+1) != 'i' || *(startCollectionBuf+2) != 'n' ||
1018 (*(startCollectionBuf+3) != ' ' &&
1019 *(startCollectionBuf+3) != '[' && *(startCollectionBuf+3) != '('))
1020 startCollectionBuf++;
1021 startCollectionBuf += 3;
1023 // Replace: "for (type element in" with string constructed thus far.
1024 ReplaceText(startLoc, startCollectionBuf - startBuf,
1025 buf.c_str(), buf.size());
1026 // Replace ')' in for '(' type elem in collection ')' with ';'
1027 SourceLocation rightParenLoc = S->getRParenLoc();
1028 const char *rparenBuf = SM->getCharacterData(rightParenLoc);
1029 SourceLocation lparenLoc = startLoc.getFileLocWithOffset(rparenBuf-startBuf);
1032 // unsigned long limit = [l_collection countByEnumeratingWithState:&enumState
1033 // objects:items count:16];
1034 // which is synthesized into:
1035 // unsigned int limit =
1036 // ((unsigned int (*)
1037 // (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
1038 // (void *)objc_msgSend)((id)l_collection,
1039 // sel_registerName(
1040 // "countByEnumeratingWithState:objects:count:"),
1041 // (struct __objcFastEnumerationState *)&state,
1042 // (id *)items, (unsigned int)16);
1043 buf += "unsigned long limit =\n\t\t";
1044 SynthCountByEnumWithState(buf);
1047 /// unsigned long startMutations = *enumState.mutationsPtr;
1049 /// unsigned long counter = 0;
1051 /// if (startMutations != *enumState.mutationsPtr)
1052 /// objc_enumerationMutation(l_collection);
1053 /// elem = (type)enumState.itemsPtr[counter++];
1054 buf += "if (limit) {\n\t";
1055 buf += "unsigned long startMutations = *enumState.mutationsPtr;\n\t";
1056 buf += "do {\n\t\t";
1057 buf += "unsigned long counter = 0;\n\t\t";
1058 buf += "do {\n\t\t\t";
1059 buf += "if (startMutations != *enumState.mutationsPtr)\n\t\t\t\t";
1060 buf += "objc_enumerationMutation(l_collection);\n\t\t\t";
1063 buf += elementTypeAsString;
1064 buf += ")enumState.itemsPtr[counter++];";
1065 // Replace ')' in for '(' type elem in collection ')' with all of these.
1066 ReplaceText(lparenLoc, 1, buf.c_str(), buf.size());
1068 /// __continue_label: ;
1069 /// } while (counter < limit);
1070 /// } while (limit = [l_collection countByEnumeratingWithState:&enumState
1071 /// objects:items count:16]);
1073 /// __break_label: ;
1080 buf += "__continue_label_";
1081 buf += utostr(ObjCBcLabelNo.back());
1084 buf += "} while (counter < limit);\n\t";
1085 buf += "} while (limit = ";
1086 SynthCountByEnumWithState(buf);
1089 buf += " = nil;\n\t";
1090 buf += "__break_label_";
1091 buf += utostr(ObjCBcLabelNo.back());
1094 buf += "else\n\t\t";
1098 // Insert all these *after* the statement body.
1099 SourceLocation endBodyLoc = OrigEnd.getFileLocWithOffset(1);
1100 InsertText(endBodyLoc, buf.c_str(), buf.size());
1102 ObjCBcLabelNo.pop_back();
1106 /// RewriteObjCSynchronizedStmt -
1107 /// This routine rewrites @synchronized(expr) stmt;
1109 /// objc_sync_enter(expr);
1110 /// @try stmt @finally { objc_sync_exit(expr); }
1112 Stmt *RewriteTest::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
1113 // Get the start location and compute the semi location.
1114 SourceLocation startLoc = S->getLocStart();
1115 const char *startBuf = SM->getCharacterData(startLoc);
1117 assert((*startBuf == '@') && "bogus @synchronized location");
1120 buf = "objc_sync_enter";
1121 ReplaceText(startLoc, 13, buf.c_str(), buf.size());
1122 SourceLocation endLoc = S->getSynchExpr()->getLocEnd();
1123 const char *endBuf = SM->getCharacterData(endLoc);
1125 const char *rparenBuf = strchr(endBuf, ')');
1126 SourceLocation rparenLoc = startLoc.getFileLocWithOffset(rparenBuf-startBuf);
1128 // declare a new scope with two variables, _stack and _rethrow.
1129 buf += "/* @try scope begin */ \n{ struct _objc_exception_data {\n";
1130 buf += "int buf[18/*32-bit i386*/];\n";
1131 buf += "char *pointers[4];} _stack;\n";
1132 buf += "id volatile _rethrow = 0;\n";
1133 buf += "objc_exception_try_enter(&_stack);\n";
1134 buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";
1135 ReplaceText(rparenLoc, 1, buf.c_str(), buf.size());
1136 startLoc = S->getSynchBody()->getLocEnd();
1137 startBuf = SM->getCharacterData(startLoc);
1139 assert((*startBuf == '}') && "bogus @try block");
1140 SourceLocation lastCurlyLoc = startLoc;
1141 buf = "}\nelse {\n";
1142 buf += " _rethrow = objc_exception_extract(&_stack);\n";
1143 buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
1144 // FIXME: This must be objc_sync_exit(syncExpr);
1145 buf += " objc_sync_exit();\n";
1146 buf += " if (_rethrow) objc_exception_throw(_rethrow);\n";
1150 ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size());
1154 Stmt *RewriteTest::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
1155 // Get the start location and compute the semi location.
1156 SourceLocation startLoc = S->getLocStart();
1157 const char *startBuf = SM->getCharacterData(startLoc);
1159 assert((*startBuf == '@') && "bogus @try location");
1162 // declare a new scope with two variables, _stack and _rethrow.
1163 buf = "/* @try scope begin */ { struct _objc_exception_data {\n";
1164 buf += "int buf[18/*32-bit i386*/];\n";
1165 buf += "char *pointers[4];} _stack;\n";
1166 buf += "id volatile _rethrow = 0;\n";
1167 buf += "objc_exception_try_enter(&_stack);\n";
1168 buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";
1170 ReplaceText(startLoc, 4, buf.c_str(), buf.size());
1172 startLoc = S->getTryBody()->getLocEnd();
1173 startBuf = SM->getCharacterData(startLoc);
1175 assert((*startBuf == '}') && "bogus @try block");
1177 SourceLocation lastCurlyLoc = startLoc;
1179 startLoc = startLoc.getFileLocWithOffset(1);
1180 buf = " /* @catch begin */ else {\n";
1181 buf += " id _caught = objc_exception_extract(&_stack);\n";
1182 buf += " objc_exception_try_enter (&_stack);\n";
1183 buf += " if (_setjmp(_stack.buf))\n";
1184 buf += " _rethrow = objc_exception_extract(&_stack);\n";
1185 buf += " else { /* @catch continue */";
1187 InsertText(startLoc, buf.c_str(), buf.size());
1189 bool sawIdTypedCatch = false;
1190 Stmt *lastCatchBody = 0;
1191 ObjCAtCatchStmt *catchList = S->getCatchStmts();
1193 Stmt *catchStmt = catchList->getCatchParamStmt();
1195 if (catchList == S->getCatchStmts())
1196 buf = "if ("; // we are generating code for the first catch clause
1199 startLoc = catchList->getLocStart();
1200 startBuf = SM->getCharacterData(startLoc);
1202 assert((*startBuf == '@') && "bogus @catch location");
1204 const char *lParenLoc = strchr(startBuf, '(');
1206 if (DeclStmt *declStmt = dyn_cast<DeclStmt>(catchStmt)) {
1207 QualType t = dyn_cast<ValueDecl>(declStmt->getDecl())->getType();
1208 if (t == Context->getObjCIdType()) {
1210 ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size());
1211 sawIdTypedCatch = true;
1212 } else if (const PointerType *pType = t->getAsPointerType()) {
1213 ObjCInterfaceType *cls; // Should be a pointer to a class.
1215 cls = dyn_cast<ObjCInterfaceType>(pType->getPointeeType().getTypePtr());
1217 buf += "objc_exception_match((struct objc_class *)objc_getClass(\"";
1218 buf += cls->getDecl()->getName();
1219 buf += "\"), (struct objc_object *)_caught)) { ";
1220 ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size());
1223 // Now rewrite the body...
1224 lastCatchBody = catchList->getCatchBody();
1225 SourceLocation rParenLoc = catchList->getRParenLoc();
1226 SourceLocation bodyLoc = lastCatchBody->getLocStart();
1227 const char *bodyBuf = SM->getCharacterData(bodyLoc);
1228 const char *rParenBuf = SM->getCharacterData(rParenLoc);
1229 assert((*rParenBuf == ')') && "bogus @catch paren location");
1230 assert((*bodyBuf == '{') && "bogus @catch body location");
1232 buf = " = _caught;";
1233 // Here we replace ") {" with "= _caught;" (which initializes and
1234 // declares the @catch parameter).
1235 ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, buf.c_str(), buf.size());
1236 } else if (!isa<NullStmt>(catchStmt)) {
1237 assert(false && "@catch rewrite bug");
1239 catchList = catchList->getNextCatchStmt();
1241 // Complete the catch list...
1242 if (lastCatchBody) {
1243 SourceLocation bodyLoc = lastCatchBody->getLocEnd();
1244 const char *bodyBuf = SM->getCharacterData(bodyLoc);
1245 assert((*bodyBuf == '}') && "bogus @catch body location");
1246 bodyLoc = bodyLoc.getFileLocWithOffset(1);
1247 buf = " } } /* @catch end */\n";
1249 InsertText(bodyLoc, buf.c_str(), buf.size());
1252 lastCurlyLoc = lastCatchBody->getLocEnd();
1254 if (ObjCAtFinallyStmt *finalStmt = S->getFinallyStmt()) {
1255 startLoc = finalStmt->getLocStart();
1256 startBuf = SM->getCharacterData(startLoc);
1257 assert((*startBuf == '@') && "bogus @finally start");
1259 buf = "/* @finally */";
1260 ReplaceText(startLoc, 8, buf.c_str(), buf.size());
1262 Stmt *body = finalStmt->getFinallyBody();
1263 SourceLocation startLoc = body->getLocStart();
1264 SourceLocation endLoc = body->getLocEnd();
1265 const char *startBuf = SM->getCharacterData(startLoc);
1266 const char *endBuf = SM->getCharacterData(endLoc);
1267 assert((*startBuf == '{') && "bogus @finally body location");
1268 assert((*endBuf == '}') && "bogus @finally body location");
1270 startLoc = startLoc.getFileLocWithOffset(1);
1271 buf = " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
1272 InsertText(startLoc, buf.c_str(), buf.size());
1273 endLoc = endLoc.getFileLocWithOffset(-1);
1274 buf = " if (_rethrow) objc_exception_throw(_rethrow);\n";
1275 InsertText(endLoc, buf.c_str(), buf.size());
1278 lastCurlyLoc = body->getLocEnd();
1280 // Now emit the final closing curly brace...
1281 lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1);
1282 buf = " } /* @try scope end */\n";
1283 InsertText(lastCurlyLoc, buf.c_str(), buf.size());
1287 Stmt *RewriteTest::RewriteObjCCatchStmt(ObjCAtCatchStmt *S) {
1291 Stmt *RewriteTest::RewriteObjCFinallyStmt(ObjCAtFinallyStmt *S) {
1295 // This can't be done with ReplaceStmt(S, ThrowExpr), since
1296 // the throw expression is typically a message expression that's already
1297 // been rewritten! (which implies the SourceLocation's are invalid).
1298 Stmt *RewriteTest::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) {
1299 // Get the start location and compute the semi location.
1300 SourceLocation startLoc = S->getLocStart();
1301 const char *startBuf = SM->getCharacterData(startLoc);
1303 assert((*startBuf == '@') && "bogus @throw location");
1306 /* void objc_exception_throw(id) __attribute__((noreturn)); */
1307 if (S->getThrowExpr())
1308 buf = "objc_exception_throw(";
1309 else // add an implicit argument
1310 buf = "objc_exception_throw(_caught";
1311 ReplaceText(startLoc, 6, buf.c_str(), buf.size());
1312 const char *semiBuf = strchr(startBuf, ';');
1313 assert((*semiBuf == ';') && "@throw: can't find ';'");
1314 SourceLocation semiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf);
1316 ReplaceText(semiLoc, 1, buf.c_str(), buf.size());
1320 Stmt *RewriteTest::RewriteAtEncode(ObjCEncodeExpr *Exp) {
1321 // Create a new string expression.
1322 QualType StrType = Context->getPointerType(Context->CharTy);
1323 std::string StrEncoding;
1324 Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding,
1325 EncodingRecordTypes);
1326 Expr *Replacement = new StringLiteral(StrEncoding.c_str(),
1327 StrEncoding.length(), false, StrType,
1328 SourceLocation(), SourceLocation());
1329 ReplaceStmt(Exp, Replacement);
1331 // Replace this subexpr in the parent.
1336 Stmt *RewriteTest::RewriteAtSelector(ObjCSelectorExpr *Exp) {
1337 assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");
1338 // Create a call to sel_registerName("selName").
1339 llvm::SmallVector<Expr*, 8> SelExprs;
1340 QualType argType = Context->getPointerType(Context->CharTy);
1341 SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
1342 Exp->getSelector().getName().size(),
1343 false, argType, SourceLocation(),
1345 CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
1346 &SelExprs[0], SelExprs.size());
1347 ReplaceStmt(Exp, SelExp);
1352 CallExpr *RewriteTest::SynthesizeCallToFunctionDecl(
1353 FunctionDecl *FD, Expr **args, unsigned nargs) {
1354 // Get the type, we will need to reference it in a couple spots.
1355 QualType msgSendType = FD->getType();
1357 // Create a reference to the objc_msgSend() declaration.
1358 DeclRefExpr *DRE = new DeclRefExpr(FD, msgSendType, SourceLocation());
1360 // Now, we cast the reference to a pointer to the objc_msgSend type.
1361 QualType pToFunc = Context->getPointerType(msgSendType);
1362 ImplicitCastExpr *ICE = new ImplicitCastExpr(pToFunc, DRE);
1364 const FunctionType *FT = msgSendType->getAsFunctionType();
1366 return new CallExpr(ICE, args, nargs, FT->getResultType(), SourceLocation());
1369 static bool scanForProtocolRefs(const char *startBuf, const char *endBuf,
1370 const char *&startRef, const char *&endRef) {
1371 while (startBuf < endBuf) {
1372 if (*startBuf == '<')
1373 startRef = startBuf; // mark the start.
1374 if (*startBuf == '>') {
1375 if (startRef && *startRef == '<') {
1376 endRef = startBuf; // mark the end.
1386 static void scanToNextArgument(const char *&argRef) {
1388 while (*argRef != ')' && (*argRef != ',' || angle > 0)) {
1391 else if (*argRef == '>')
1395 assert(angle == 0 && "scanToNextArgument - bad protocol type syntax");
1398 bool RewriteTest::needToScanForQualifiers(QualType T) {
1400 if (T == Context->getObjCIdType())
1403 if (T->isObjCQualifiedIdType())
1406 if (const PointerType *pType = T->getAsPointerType()) {
1407 Type *pointeeType = pType->getPointeeType().getTypePtr();
1408 if (isa<ObjCQualifiedInterfaceType>(pointeeType))
1409 return true; // we have "Class <Protocol> *".
1414 void RewriteTest::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
1417 const FunctionTypeProto *proto = 0;
1418 if (VarDecl *VD = dyn_cast<VarDecl>(Dcl)) {
1419 Loc = VD->getLocation();
1420 Type = VD->getType();
1422 else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Dcl)) {
1423 Loc = FD->getLocation();
1424 // Check for ObjC 'id' and class types that have been adorned with protocol
1425 // information (id<p>, C<p>*). The protocol references need to be rewritten!
1426 const FunctionType *funcType = FD->getType()->getAsFunctionType();
1427 assert(funcType && "missing function type");
1428 proto = dyn_cast<FunctionTypeProto>(funcType);
1431 Type = proto->getResultType();
1436 if (needToScanForQualifiers(Type)) {
1437 // Since types are unique, we need to scan the buffer.
1439 const char *endBuf = SM->getCharacterData(Loc);
1440 const char *startBuf = endBuf;
1441 while (*startBuf != ';' && startBuf != MainFileStart)
1442 startBuf--; // scan backward (from the decl location) for return type.
1443 const char *startRef = 0, *endRef = 0;
1444 if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
1445 // Get the locations of the startRef, endRef.
1446 SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-endBuf);
1447 SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-endBuf+1);
1448 // Comment out the protocol references.
1449 InsertText(LessLoc, "/*", 2);
1450 InsertText(GreaterLoc, "*/", 2);
1454 return; // most likely, was a variable
1455 // Now check arguments.
1456 const char *startBuf = SM->getCharacterData(Loc);
1457 const char *startFuncBuf = startBuf;
1458 for (unsigned i = 0; i < proto->getNumArgs(); i++) {
1459 if (needToScanForQualifiers(proto->getArgType(i))) {
1460 // Since types are unique, we need to scan the buffer.
1462 const char *endBuf = startBuf;
1463 // scan forward (from the decl location) for argument types.
1464 scanToNextArgument(endBuf);
1465 const char *startRef = 0, *endRef = 0;
1466 if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
1467 // Get the locations of the startRef, endRef.
1468 SourceLocation LessLoc =
1469 Loc.getFileLocWithOffset(startRef-startFuncBuf);
1470 SourceLocation GreaterLoc =
1471 Loc.getFileLocWithOffset(endRef-startFuncBuf+1);
1472 // Comment out the protocol references.
1473 InsertText(LessLoc, "/*", 2);
1474 InsertText(GreaterLoc, "*/", 2);
1476 startBuf = ++endBuf;
1479 while (*startBuf != ')' && *startBuf != ',')
1480 startBuf++; // scan forward (from the decl location) for argument types.
1486 // SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str);
1487 void RewriteTest::SynthSelGetUidFunctionDecl() {
1488 IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName");
1489 llvm::SmallVector<QualType, 16> ArgTys;
1490 ArgTys.push_back(Context->getPointerType(
1491 Context->CharTy.getQualifiedType(QualType::Const)));
1492 QualType getFuncType = Context->getFunctionType(Context->getObjCSelType(),
1493 &ArgTys[0], ArgTys.size(),
1494 false /*isVariadic*/);
1495 SelGetUidFunctionDecl = new FunctionDecl(SourceLocation(),
1496 SelGetUidIdent, getFuncType,
1497 FunctionDecl::Extern, false, 0);
1500 // SynthGetProtocolFunctionDecl - Protocol objc_getProtocol(const char *proto);
1501 void RewriteTest::SynthGetProtocolFunctionDecl() {
1502 IdentifierInfo *SelGetProtoIdent = &Context->Idents.get("objc_getProtocol");
1503 llvm::SmallVector<QualType, 16> ArgTys;
1504 ArgTys.push_back(Context->getPointerType(
1505 Context->CharTy.getQualifiedType(QualType::Const)));
1506 QualType getFuncType = Context->getFunctionType(Context->getObjCProtoType(),
1507 &ArgTys[0], ArgTys.size(),
1508 false /*isVariadic*/);
1509 GetProtocolFunctionDecl = new FunctionDecl(SourceLocation(),
1510 SelGetProtoIdent, getFuncType,
1511 FunctionDecl::Extern, false, 0);
1514 void RewriteTest::RewriteFunctionDecl(FunctionDecl *FD) {
1515 // declared in <objc/objc.h>
1516 if (strcmp(FD->getName(), "sel_registerName") == 0) {
1517 SelGetUidFunctionDecl = FD;
1520 RewriteObjCQualifiedInterfaceTypes(FD);
1523 // SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
1524 void RewriteTest::SynthMsgSendFunctionDecl() {
1525 IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend");
1526 llvm::SmallVector<QualType, 16> ArgTys;
1527 QualType argT = Context->getObjCIdType();
1528 assert(!argT.isNull() && "Can't find 'id' type");
1529 ArgTys.push_back(argT);
1530 argT = Context->getObjCSelType();
1531 assert(!argT.isNull() && "Can't find 'SEL' type");
1532 ArgTys.push_back(argT);
1533 QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
1534 &ArgTys[0], ArgTys.size(),
1535 true /*isVariadic*/);
1536 MsgSendFunctionDecl = new FunctionDecl(SourceLocation(),
1537 msgSendIdent, msgSendType,
1538 FunctionDecl::Extern, false, 0);
1541 // SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...);
1542 void RewriteTest::SynthMsgSendSuperFunctionDecl() {
1543 IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper");
1544 llvm::SmallVector<QualType, 16> ArgTys;
1545 RecordDecl *RD = new RecordDecl(Decl::Struct, SourceLocation(),
1546 &Context->Idents.get("objc_super"), 0);
1547 QualType argT = Context->getPointerType(Context->getTagDeclType(RD));
1548 assert(!argT.isNull() && "Can't build 'struct objc_super *' type");
1549 ArgTys.push_back(argT);
1550 argT = Context->getObjCSelType();
1551 assert(!argT.isNull() && "Can't find 'SEL' type");
1552 ArgTys.push_back(argT);
1553 QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
1554 &ArgTys[0], ArgTys.size(),
1555 true /*isVariadic*/);
1556 MsgSendSuperFunctionDecl = new FunctionDecl(SourceLocation(),
1557 msgSendIdent, msgSendType,
1558 FunctionDecl::Extern, false, 0);
1561 // SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...);
1562 void RewriteTest::SynthMsgSendStretFunctionDecl() {
1563 IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_stret");
1564 llvm::SmallVector<QualType, 16> ArgTys;
1565 QualType argT = Context->getObjCIdType();
1566 assert(!argT.isNull() && "Can't find 'id' type");
1567 ArgTys.push_back(argT);
1568 argT = Context->getObjCSelType();
1569 assert(!argT.isNull() && "Can't find 'SEL' type");
1570 ArgTys.push_back(argT);
1571 QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
1572 &ArgTys[0], ArgTys.size(),
1573 true /*isVariadic*/);
1574 MsgSendStretFunctionDecl = new FunctionDecl(SourceLocation(),
1575 msgSendIdent, msgSendType,
1576 FunctionDecl::Extern, false, 0);
1579 // SynthMsgSendSuperStretFunctionDecl -
1580 // id objc_msgSendSuper_stret(struct objc_super *, SEL op, ...);
1581 void RewriteTest::SynthMsgSendSuperStretFunctionDecl() {
1582 IdentifierInfo *msgSendIdent =
1583 &Context->Idents.get("objc_msgSendSuper_stret");
1584 llvm::SmallVector<QualType, 16> ArgTys;
1585 RecordDecl *RD = new RecordDecl(Decl::Struct, SourceLocation(),
1586 &Context->Idents.get("objc_super"), 0);
1587 QualType argT = Context->getPointerType(Context->getTagDeclType(RD));
1588 assert(!argT.isNull() && "Can't build 'struct objc_super *' type");
1589 ArgTys.push_back(argT);
1590 argT = Context->getObjCSelType();
1591 assert(!argT.isNull() && "Can't find 'SEL' type");
1592 ArgTys.push_back(argT);
1593 QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
1594 &ArgTys[0], ArgTys.size(),
1595 true /*isVariadic*/);
1596 MsgSendSuperStretFunctionDecl = new FunctionDecl(SourceLocation(),
1597 msgSendIdent, msgSendType,
1598 FunctionDecl::Extern, false, 0);
1601 // SynthMsgSendFpretFunctionDecl - id objc_msgSend_fpret(id self, SEL op, ...);
1602 void RewriteTest::SynthMsgSendFpretFunctionDecl() {
1603 IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_fpret");
1604 llvm::SmallVector<QualType, 16> ArgTys;
1605 QualType argT = Context->getObjCIdType();
1606 assert(!argT.isNull() && "Can't find 'id' type");
1607 ArgTys.push_back(argT);
1608 argT = Context->getObjCSelType();
1609 assert(!argT.isNull() && "Can't find 'SEL' type");
1610 ArgTys.push_back(argT);
1611 QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
1612 &ArgTys[0], ArgTys.size(),
1613 true /*isVariadic*/);
1614 MsgSendFpretFunctionDecl = new FunctionDecl(SourceLocation(),
1615 msgSendIdent, msgSendType,
1616 FunctionDecl::Extern, false, 0);
1619 // SynthGetClassFunctionDecl - id objc_getClass(const char *name);
1620 void RewriteTest::SynthGetClassFunctionDecl() {
1621 IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass");
1622 llvm::SmallVector<QualType, 16> ArgTys;
1623 ArgTys.push_back(Context->getPointerType(
1624 Context->CharTy.getQualifiedType(QualType::Const)));
1625 QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
1626 &ArgTys[0], ArgTys.size(),
1627 false /*isVariadic*/);
1628 GetClassFunctionDecl = new FunctionDecl(SourceLocation(),
1629 getClassIdent, getClassType,
1630 FunctionDecl::Extern, false, 0);
1633 // SynthGetMetaClassFunctionDecl - id objc_getClass(const char *name);
1634 void RewriteTest::SynthGetMetaClassFunctionDecl() {
1635 IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass");
1636 llvm::SmallVector<QualType, 16> ArgTys;
1637 ArgTys.push_back(Context->getPointerType(
1638 Context->CharTy.getQualifiedType(QualType::Const)));
1639 QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
1640 &ArgTys[0], ArgTys.size(),
1641 false /*isVariadic*/);
1642 GetMetaClassFunctionDecl = new FunctionDecl(SourceLocation(),
1643 getClassIdent, getClassType,
1644 FunctionDecl::Extern, false, 0);
1647 // SynthCFStringFunctionDecl - id __builtin___CFStringMakeConstantString(const char *name);
1648 void RewriteTest::SynthCFStringFunctionDecl() {
1649 IdentifierInfo *getClassIdent = &Context->Idents.get("__builtin___CFStringMakeConstantString");
1650 llvm::SmallVector<QualType, 16> ArgTys;
1651 ArgTys.push_back(Context->getPointerType(
1652 Context->CharTy.getQualifiedType(QualType::Const)));
1653 QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
1654 &ArgTys[0], ArgTys.size(),
1655 false /*isVariadic*/);
1656 CFStringFunctionDecl = new FunctionDecl(SourceLocation(),
1657 getClassIdent, getClassType,
1658 FunctionDecl::Extern, false, 0);
1661 Stmt *RewriteTest::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
1663 // This rewrite is specific to GCC, which has builtin support for CFString.
1664 if (!CFStringFunctionDecl)
1665 SynthCFStringFunctionDecl();
1666 // Create a call to __builtin___CFStringMakeConstantString("cstr").
1667 llvm::SmallVector<Expr*, 8> StrExpr;
1668 StrExpr.push_back(Exp->getString());
1669 CallExpr *call = SynthesizeCallToFunctionDecl(CFStringFunctionDecl,
1670 &StrExpr[0], StrExpr.size());
1671 // cast to NSConstantString *
1672 CastExpr *cast = new CastExpr(Exp->getType(), call, SourceLocation());
1673 ReplaceStmt(Exp, cast);
1677 assert(ConstantStringClassReference && "Can't find constant string reference");
1678 llvm::SmallVector<Expr*, 4> InitExprs;
1680 // Synthesize "(Class)&_NSConstantStringClassReference"
1681 DeclRefExpr *ClsRef = new DeclRefExpr(ConstantStringClassReference,
1682 ConstantStringClassReference->getType(),
1684 QualType expType = Context->getPointerType(ClsRef->getType());
1685 UnaryOperator *Unop = new UnaryOperator(ClsRef, UnaryOperator::AddrOf,
1686 expType, SourceLocation());
1687 CastExpr *cast = new CastExpr(Context->getObjCClassType(), Unop,
1689 InitExprs.push_back(cast); // set the 'isa'.
1690 InitExprs.push_back(Exp->getString()); // set "char *bytes".
1691 unsigned IntSize = static_cast<unsigned>(
1692 Context->getTypeSize(Context->IntTy, Exp->getLocStart()));
1693 llvm::APInt IntVal(IntSize, Exp->getString()->getByteLength());
1694 IntegerLiteral *len = new IntegerLiteral(IntVal, Context->IntTy,
1695 Exp->getLocStart());
1696 InitExprs.push_back(len); // set "int numBytes".
1698 // struct NSConstantString
1699 QualType CFConstantStrType = Context->getCFConstantStringType();
1700 // (struct NSConstantString) { <exprs from above> }
1701 InitListExpr *ILE = new InitListExpr(SourceLocation(),
1702 &InitExprs[0], InitExprs.size(),
1704 CompoundLiteralExpr *StrRep = new CompoundLiteralExpr(CFConstantStrType, ILE, false);
1705 // struct NSConstantString *
1706 expType = Context->getPointerType(StrRep->getType());
1707 Unop = new UnaryOperator(StrRep, UnaryOperator::AddrOf, expType,
1709 // cast to NSConstantString *
1710 cast = new CastExpr(Exp->getType(), Unop, SourceLocation());
1711 ReplaceStmt(Exp, cast);
1717 ObjCInterfaceDecl *RewriteTest::isSuperReceiver(Expr *recExpr) {
1718 // check if we are sending a message to 'super'
1719 if (CurMethodDecl && CurMethodDecl->isInstance()) {
1720 if (CastExpr *CE = dyn_cast<CastExpr>(recExpr)) {
1721 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) {
1722 if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
1723 if (!strcmp(PVD->getName(), "self")) {
1724 // is this id<P1..> type?
1725 if (CE->getType()->isObjCQualifiedIdType())
1727 if (const PointerType *PT = CE->getType()->getAsPointerType()) {
1728 if (ObjCInterfaceType *IT =
1729 dyn_cast<ObjCInterfaceType>(PT->getPointeeType())) {
1730 if (IT->getDecl() ==
1731 CurMethodDecl->getClassInterface()->getSuperClass())
1732 return IT->getDecl();
1743 // struct objc_super { struct objc_object *receiver; struct objc_class *super; };
1744 QualType RewriteTest::getSuperStructType() {
1745 if (!SuperStructDecl) {
1746 SuperStructDecl = new RecordDecl(Decl::Struct, SourceLocation(),
1747 &Context->Idents.get("objc_super"), 0);
1748 QualType FieldTypes[2];
1750 // struct objc_object *receiver;
1751 FieldTypes[0] = Context->getObjCIdType();
1752 // struct objc_class *super;
1753 FieldTypes[1] = Context->getObjCClassType();
1755 FieldDecl *FieldDecls[2];
1757 for (unsigned i = 0; i < 2; ++i)
1758 FieldDecls[i] = new FieldDecl(SourceLocation(), 0, FieldTypes[i]);
1760 SuperStructDecl->defineBody(FieldDecls, 4);
1762 return Context->getTagDeclType(SuperStructDecl);
1765 Stmt *RewriteTest::SynthMessageExpr(ObjCMessageExpr *Exp) {
1766 if (!SelGetUidFunctionDecl)
1767 SynthSelGetUidFunctionDecl();
1768 if (!MsgSendFunctionDecl)
1769 SynthMsgSendFunctionDecl();
1770 if (!MsgSendSuperFunctionDecl)
1771 SynthMsgSendSuperFunctionDecl();
1772 if (!MsgSendStretFunctionDecl)
1773 SynthMsgSendStretFunctionDecl();
1774 if (!MsgSendSuperStretFunctionDecl)
1775 SynthMsgSendSuperStretFunctionDecl();
1776 if (!MsgSendFpretFunctionDecl)
1777 SynthMsgSendFpretFunctionDecl();
1778 if (!GetClassFunctionDecl)
1779 SynthGetClassFunctionDecl();
1780 if (!GetMetaClassFunctionDecl)
1781 SynthGetMetaClassFunctionDecl();
1783 // default to objc_msgSend().
1784 FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl;
1785 // May need to use objc_msgSend_stret() as well.
1786 FunctionDecl *MsgSendStretFlavor = 0;
1787 if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) {
1788 QualType resultType = mDecl->getResultType();
1789 if (resultType.getCanonicalType()->isStructureType()
1790 || resultType.getCanonicalType()->isUnionType())
1791 MsgSendStretFlavor = MsgSendStretFunctionDecl;
1792 else if (resultType.getCanonicalType()->isRealFloatingType())
1793 MsgSendFlavor = MsgSendFpretFunctionDecl;
1796 // Synthesize a call to objc_msgSend().
1797 llvm::SmallVector<Expr*, 8> MsgExprs;
1798 IdentifierInfo *clsName = Exp->getClassName();
1800 // Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend().
1801 if (clsName) { // class message.
1802 if (!strcmp(clsName->getName(), "super")) {
1803 MsgSendFlavor = MsgSendSuperFunctionDecl;
1804 if (MsgSendStretFlavor)
1805 MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
1806 assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
1808 ObjCInterfaceDecl *SuperDecl =
1809 CurMethodDecl->getClassInterface()->getSuperClass();
1811 llvm::SmallVector<Expr*, 4> InitExprs;
1813 // set the receiver to self, the first argument to all methods.
1814 InitExprs.push_back(new DeclRefExpr(CurMethodDecl->getSelfDecl(),
1815 Context->getObjCIdType(),
1817 llvm::SmallVector<Expr*, 8> ClsExprs;
1818 QualType argType = Context->getPointerType(Context->CharTy);
1819 ClsExprs.push_back(new StringLiteral(SuperDecl->getIdentifier()->getName(),
1820 SuperDecl->getIdentifier()->getLength(),
1821 false, argType, SourceLocation(),
1823 CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
1826 // To turn off a warning, type-cast to 'id'
1827 InitExprs.push_back(
1828 new CastExpr(Context->getObjCIdType(),
1829 Cls, SourceLocation())); // set 'super class', using objc_getClass().
1830 // struct objc_super
1831 QualType superType = getSuperStructType();
1832 // (struct objc_super) { <exprs from above> }
1833 InitListExpr *ILE = new InitListExpr(SourceLocation(),
1834 &InitExprs[0], InitExprs.size(),
1836 CompoundLiteralExpr *SuperRep = new CompoundLiteralExpr(SourceLocation(),
1837 superType, ILE, false);
1838 // struct objc_super *
1839 Expr *Unop = new UnaryOperator(SuperRep, UnaryOperator::AddrOf,
1840 Context->getPointerType(SuperRep->getType()),
1842 MsgExprs.push_back(Unop);
1844 llvm::SmallVector<Expr*, 8> ClsExprs;
1845 QualType argType = Context->getPointerType(Context->CharTy);
1846 ClsExprs.push_back(new StringLiteral(clsName->getName(),
1847 clsName->getLength(),
1848 false, argType, SourceLocation(),
1850 CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
1853 MsgExprs.push_back(Cls);
1855 } else { // instance message.
1856 Expr *recExpr = Exp->getReceiver();
1858 if (ObjCInterfaceDecl *SuperDecl = isSuperReceiver(recExpr)) {
1859 MsgSendFlavor = MsgSendSuperFunctionDecl;
1860 if (MsgSendStretFlavor)
1861 MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
1862 assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
1864 llvm::SmallVector<Expr*, 4> InitExprs;
1866 InitExprs.push_back(
1867 new CastExpr(Context->getObjCIdType(),
1868 recExpr, SourceLocation())); // set the 'receiver'.
1870 llvm::SmallVector<Expr*, 8> ClsExprs;
1871 QualType argType = Context->getPointerType(Context->CharTy);
1872 ClsExprs.push_back(new StringLiteral(SuperDecl->getIdentifier()->getName(),
1873 SuperDecl->getIdentifier()->getLength(),
1874 false, argType, SourceLocation(),
1876 CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
1879 // To turn off a warning, type-cast to 'id'
1880 InitExprs.push_back(
1881 new CastExpr(Context->getObjCIdType(),
1882 Cls, SourceLocation())); // set 'super class', using objc_getClass().
1883 // struct objc_super
1884 QualType superType = getSuperStructType();
1885 // (struct objc_super) { <exprs from above> }
1886 InitListExpr *ILE = new InitListExpr(SourceLocation(),
1887 &InitExprs[0], InitExprs.size(),
1889 CompoundLiteralExpr *SuperRep = new CompoundLiteralExpr(SourceLocation(),
1890 superType, ILE, false);
1891 // struct objc_super *
1892 Expr *Unop = new UnaryOperator(SuperRep, UnaryOperator::AddrOf,
1893 Context->getPointerType(SuperRep->getType()),
1895 MsgExprs.push_back(Unop);
1897 // Remove all type-casts because it may contain objc-style types; e.g.
1899 while (CastExpr *CE = dyn_cast<CastExpr>(recExpr))
1900 recExpr = CE->getSubExpr();
1901 recExpr = new CastExpr(Context->getObjCIdType(), recExpr, SourceLocation());
1902 MsgExprs.push_back(recExpr);
1905 // Create a call to sel_registerName("selName"), it will be the 2nd argument.
1906 llvm::SmallVector<Expr*, 8> SelExprs;
1907 QualType argType = Context->getPointerType(Context->CharTy);
1908 SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),
1909 Exp->getSelector().getName().size(),
1910 false, argType, SourceLocation(),
1912 CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
1913 &SelExprs[0], SelExprs.size());
1914 MsgExprs.push_back(SelExp);
1916 // Now push any user supplied arguments.
1917 for (unsigned i = 0; i < Exp->getNumArgs(); i++) {
1918 Expr *userExpr = Exp->getArg(i);
1919 // Make all implicit casts explicit...ICE comes in handy:-)
1920 if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) {
1921 // Reuse the ICE type, it is exactly what the doctor ordered.
1922 userExpr = new CastExpr(ICE->getType()->isObjCQualifiedIdType()
1923 ? Context->getObjCIdType()
1924 : ICE->getType(), userExpr, SourceLocation());
1926 // Make id<P...> cast into an 'id' cast.
1927 else if (CastExpr *CE = dyn_cast<CastExpr>(userExpr)) {
1928 if (CE->getType()->isObjCQualifiedIdType()) {
1929 while ((CE = dyn_cast<CastExpr>(userExpr)))
1930 userExpr = CE->getSubExpr();
1931 userExpr = new CastExpr(Context->getObjCIdType(),
1932 userExpr, SourceLocation());
1935 MsgExprs.push_back(userExpr);
1936 // We've transferred the ownership to MsgExprs. Null out the argument in
1937 // the original expression, since we will delete it below.
1940 // Generate the funky cast.
1942 llvm::SmallVector<QualType, 8> ArgTypes;
1943 QualType returnType;
1945 // Push 'id' and 'SEL', the 2 implicit arguments.
1946 if (MsgSendFlavor == MsgSendSuperFunctionDecl)
1947 ArgTypes.push_back(Context->getPointerType(getSuperStructType()));
1949 ArgTypes.push_back(Context->getObjCIdType());
1950 ArgTypes.push_back(Context->getObjCSelType());
1951 if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) {
1952 // Push any user argument types.
1953 for (int i = 0; i < mDecl->getNumParams(); i++) {
1954 QualType t = mDecl->getParamDecl(i)->getType()->isObjCQualifiedIdType()
1955 ? Context->getObjCIdType()
1956 : mDecl->getParamDecl(i)->getType();
1957 ArgTypes.push_back(t);
1959 returnType = mDecl->getResultType()->isObjCQualifiedIdType()
1960 ? Context->getObjCIdType() : mDecl->getResultType();
1962 returnType = Context->getObjCIdType();
1964 // Get the type, we will need to reference it in a couple spots.
1965 QualType msgSendType = MsgSendFlavor->getType();
1967 // Create a reference to the objc_msgSend() declaration.
1968 DeclRefExpr *DRE = new DeclRefExpr(MsgSendFlavor, msgSendType,
1971 // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid).
1972 // If we don't do this cast, we get the following bizarre warning/note:
1973 // xx.m:13: warning: function called through a non-compatible type
1974 // xx.m:13: note: if this code is reached, the program will abort
1975 cast = new CastExpr(Context->getPointerType(Context->VoidTy), DRE,
1978 // Now do the "normal" pointer to function cast.
1979 QualType castType = Context->getFunctionType(returnType,
1980 &ArgTypes[0], ArgTypes.size(),
1981 Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false);
1982 castType = Context->getPointerType(castType);
1983 cast = new CastExpr(castType, cast, SourceLocation());
1985 // Don't forget the parens to enforce the proper binding.
1986 ParenExpr *PE = new ParenExpr(SourceLocation(), SourceLocation(), cast);
1988 const FunctionType *FT = msgSendType->getAsFunctionType();
1989 CallExpr *CE = new CallExpr(PE, &MsgExprs[0], MsgExprs.size(),
1990 FT->getResultType(), SourceLocation());
1991 Stmt *ReplacingStmt = CE;
1992 if (MsgSendStretFlavor) {
1993 // We have the method which returns a struct/union. Must also generate
1994 // call to objc_msgSend_stret and hang both varieties on a conditional
1995 // expression which dictate which one to envoke depending on size of
1996 // method's return type.
1998 // Create a reference to the objc_msgSend_stret() declaration.
1999 DeclRefExpr *STDRE = new DeclRefExpr(MsgSendStretFlavor, msgSendType,
2001 // Need to cast objc_msgSend_stret to "void *" (see above comment).
2002 cast = new CastExpr(Context->getPointerType(Context->VoidTy), STDRE,
2004 // Now do the "normal" pointer to function cast.
2005 castType = Context->getFunctionType(returnType,
2006 &ArgTypes[0], ArgTypes.size(),
2007 Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false);
2008 castType = Context->getPointerType(castType);
2009 cast = new CastExpr(castType, cast, SourceLocation());
2011 // Don't forget the parens to enforce the proper binding.
2012 PE = new ParenExpr(SourceLocation(), SourceLocation(), cast);
2014 FT = msgSendType->getAsFunctionType();
2015 CallExpr *STCE = new CallExpr(PE, &MsgExprs[0], MsgExprs.size(),
2016 FT->getResultType(), SourceLocation());
2018 // Build sizeof(returnType)
2019 SizeOfAlignOfTypeExpr *sizeofExpr = new SizeOfAlignOfTypeExpr(true,
2020 returnType, Context->getSizeType(),
2021 SourceLocation(), SourceLocation());
2022 // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
2023 // FIXME: Value of 8 is base on ppc32/x86 ABI for the most common cases.
2024 // For X86 it is more complicated and some kind of target specific routine
2025 // is needed to decide what to do.
2026 unsigned IntSize = static_cast<unsigned>(
2027 Context->getTypeSize(Context->IntTy, SourceLocation()));
2029 IntegerLiteral *limit = new IntegerLiteral(llvm::APInt(IntSize, 8),
2032 BinaryOperator *lessThanExpr = new BinaryOperator(sizeofExpr, limit,
2036 // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
2037 ConditionalOperator *CondExpr =
2038 new ConditionalOperator(lessThanExpr, CE, STCE, returnType);
2039 ReplacingStmt = new ParenExpr(SourceLocation(), SourceLocation(), CondExpr);
2041 return ReplacingStmt;
2044 Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) {
2045 Stmt *ReplacingStmt = SynthMessageExpr(Exp);
2046 // Now do the actual rewrite.
2047 ReplaceStmt(Exp, ReplacingStmt);
2050 return ReplacingStmt;
2053 /// RewriteObjCProtocolExpr - Rewrite a protocol expression into
2054 /// call to objc_getProtocol("proto-name").
2055 Stmt *RewriteTest::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
2056 if (!GetProtocolFunctionDecl)
2057 SynthGetProtocolFunctionDecl();
2058 // Create a call to objc_getProtocol("ProtocolName").
2059 llvm::SmallVector<Expr*, 8> ProtoExprs;
2060 QualType argType = Context->getPointerType(Context->CharTy);
2061 ProtoExprs.push_back(new StringLiteral(Exp->getProtocol()->getName(),
2062 strlen(Exp->getProtocol()->getName()),
2063 false, argType, SourceLocation(),
2065 CallExpr *ProtoExp = SynthesizeCallToFunctionDecl(GetProtocolFunctionDecl,
2068 ReplaceStmt(Exp, ProtoExp);
2074 /// SynthesizeObjCInternalStruct - Rewrite one internal struct corresponding to
2075 /// an objective-c class with ivars.
2076 void RewriteTest::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
2077 std::string &Result) {
2078 assert(CDecl && "Class missing in SynthesizeObjCInternalStruct");
2079 assert(CDecl->getName() && "Name missing in SynthesizeObjCInternalStruct");
2080 // Do not synthesize more than once.
2081 if (ObjCSynthesizedStructs.count(CDecl))
2083 ObjCInterfaceDecl *RCDecl = CDecl->getSuperClass();
2084 int NumIvars = CDecl->getNumInstanceVariables();
2085 SourceLocation LocStart = CDecl->getLocStart();
2086 SourceLocation LocEnd = CDecl->getLocEnd();
2088 const char *startBuf = SM->getCharacterData(LocStart);
2089 const char *endBuf = SM->getCharacterData(LocEnd);
2090 // If no ivars and no root or if its root, directly or indirectly,
2091 // have no ivars (thus not synthesized) then no need to synthesize this class.
2092 if (NumIvars <= 0 && (!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) {
2093 endBuf += Lexer::MeasureTokenLength(LocEnd, *SM);
2094 ReplaceText(LocStart, endBuf-startBuf, Result.c_str(), Result.size());
2098 // FIXME: This has potential of causing problem. If
2099 // SynthesizeObjCInternalStruct is ever called recursively.
2100 Result += "\nstruct ";
2101 Result += CDecl->getName();
2104 const char *cursor = strchr(startBuf, '{');
2105 assert((cursor && endBuf)
2106 && "SynthesizeObjCInternalStruct - malformed @interface");
2108 // rewrite the original header *without* disturbing the '{'
2109 ReplaceText(LocStart, cursor-startBuf-1, Result.c_str(), Result.size());
2110 if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) {
2111 Result = "\n struct ";
2112 Result += RCDecl->getName();
2113 // Note: We don't name the field decl. This simplifies the "codegen" for
2114 // accessing a superclasses instance variables (and is similar to what gcc
2115 // does internally). The unnamed struct field feature is enabled with
2116 // -fms-extensions. If the struct definition were "inlined", we wouldn't
2117 // need to use this switch. That said, I don't want to inline the def.
2120 // insert the super class structure definition.
2121 SourceLocation OnePastCurly =
2122 LocStart.getFileLocWithOffset(cursor-startBuf+1);
2123 InsertText(OnePastCurly, Result.c_str(), Result.size());
2125 cursor++; // past '{'
2127 // Now comment out any visibility specifiers.
2128 while (cursor < endBuf) {
2129 if (*cursor == '@') {
2130 SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
2132 for (++cursor; cursor[0] == ' ' || cursor[0] == '\t'; ++cursor)
2135 // FIXME: presence of @public, etc. inside comment results in
2136 // this transformation as well, which is still correct c-code.
2137 if (!strncmp(cursor, "public", strlen("public")) ||
2138 !strncmp(cursor, "private", strlen("private")) ||
2139 !strncmp(cursor, "protected", strlen("protected")))
2140 InsertText(atLoc, "// ", 3);
2142 // FIXME: If there are cases where '<' is used in ivar declaration part
2143 // of user code, then scan the ivar list and use needToScanForQualifiers
2144 // for type checking.
2145 else if (*cursor == '<') {
2146 SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
2147 InsertText(atLoc, "/* ", 3);
2148 cursor = strchr(cursor, '>');
2150 atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
2151 InsertText(atLoc, " */", 3);
2155 // Don't forget to add a ';'!!
2156 InsertText(LocEnd.getFileLocWithOffset(1), ";", 1);
2157 } else { // we don't have any instance variables - insert super struct.
2158 endBuf += Lexer::MeasureTokenLength(LocEnd, *SM);
2159 Result += " {\n struct ";
2160 Result += RCDecl->getName();
2161 // Note: We don't name the field decl. This simplifies the "codegen" for
2162 // accessing a superclasses instance variables (and is similar to what gcc
2163 // does internally). The unnamed struct field feature is enabled with
2164 // -fms-extensions. If the struct definition were "inlined", we wouldn't
2165 // need to use this switch. That said, I don't want to inline the def.
2166 Result += ";\n};\n";
2167 ReplaceText(LocStart, endBuf-startBuf, Result.c_str(), Result.size());
2169 // Mark this struct as having been generated.
2170 if (!ObjCSynthesizedStructs.insert(CDecl))
2171 assert(false && "struct already synthesize- SynthesizeObjCInternalStruct");
2174 // RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or
2176 void RewriteTest::RewriteObjCMethodsMetaData(instmeth_iterator MethodBegin,
2177 instmeth_iterator MethodEnd,
2178 bool IsInstanceMethod,
2180 const char *ClassName,
2181 std::string &Result) {
2182 if (MethodBegin == MethodEnd) return;
2184 static bool objc_impl_method = false;
2185 if (!objc_impl_method) {
2186 /* struct _objc_method {
2192 Result += "\nstruct _objc_method {\n";
2193 Result += "\tSEL _cmd;\n";
2194 Result += "\tchar *method_types;\n";
2195 Result += "\tvoid *_imp;\n";
2198 /* struct _objc_method_list {
2199 struct _objc_method_list *next_method;
2201 struct _objc_method method_list[];
2204 Result += "\nstruct _objc_method_list {\n";
2205 Result += "\tstruct _objc_method_list *next_method;\n";
2206 Result += "\tint method_count;\n";
2207 Result += "\tstruct _objc_method method_list[];\n};\n";
2208 objc_impl_method = true;
2211 // Build _objc_method_list for class's methods if needed
2212 Result += "\nstatic struct _objc_method_list _OBJC_";
2214 Result += IsInstanceMethod ? "INSTANCE" : "CLASS";
2215 Result += "_METHODS_";
2216 Result += ClassName;
2217 Result += " __attribute__ ((section (\"__OBJC, __";
2218 Result += IsInstanceMethod ? "inst" : "cls";
2219 Result += "_meth\")))= ";
2220 Result += "{\n\t0, " + utostr(MethodEnd-MethodBegin) + "\n";
2222 Result += "\t,{{(SEL)\"";
2223 Result += (*MethodBegin)->getSelector().getName().c_str();
2224 std::string MethodTypeString;
2225 Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
2227 Result += MethodTypeString;
2229 Result += MethodInternalNames[*MethodBegin];
2231 for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) {
2232 Result += "\t ,{(SEL)\"";
2233 Result += (*MethodBegin)->getSelector().getName().c_str();
2234 std::string MethodTypeString;
2235 Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
2237 Result += MethodTypeString;
2239 Result += MethodInternalNames[*MethodBegin];
2242 Result += "\t }\n};\n";
2245 /// RewriteObjCProtocolsMetaData - Rewrite protocols meta-data.
2246 void RewriteTest::RewriteObjCProtocolsMetaData(ObjCProtocolDecl **Protocols,
2249 const char *ClassName,
2250 std::string &Result) {
2251 static bool objc_protocol_methods = false;
2252 if (NumProtocols > 0) {
2253 for (int i = 0; i < NumProtocols; i++) {
2254 ObjCProtocolDecl *PDecl = Protocols[i];
2255 // Output struct protocol_methods holder of method selector and type.
2256 if (!objc_protocol_methods &&
2257 (PDecl->getNumInstanceMethods() > 0
2258 || PDecl->getNumClassMethods() > 0)) {
2259 /* struct protocol_methods {
2264 Result += "\nstruct protocol_methods {\n";
2265 Result += "\tSEL _cmd;\n";
2266 Result += "\tchar *method_types;\n";
2269 /* struct _objc_protocol_method_list {
2270 int protocol_method_count;
2271 struct protocol_methods protocols[];
2274 Result += "\nstruct _objc_protocol_method_list {\n";
2275 Result += "\tint protocol_method_count;\n";
2276 Result += "\tstruct protocol_methods protocols[];\n};\n";
2277 objc_protocol_methods = true;
2280 int NumMethods = PDecl->getNumInstanceMethods();
2281 if(NumMethods > 0) {
2282 Result += "\nstatic struct _objc_protocol_method_list "
2283 "_OBJC_PROTOCOL_INSTANCE_METHODS_";
2284 Result += PDecl->getName();
2285 Result += " __attribute__ ((section (\"__OBJC, __cat_inst_meth\")))= "
2286 "{\n\t" + utostr(NumMethods) + "\n";
2288 // Output instance methods declared in this protocol.
2289 for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(),
2290 E = PDecl->instmeth_end(); I != E; ++I) {
2291 if (I == PDecl->instmeth_begin())
2292 Result += "\t ,{{(SEL)\"";
2294 Result += "\t ,{(SEL)\"";
2295 Result += (*I)->getSelector().getName().c_str();
2296 std::string MethodTypeString;
2297 Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
2299 Result += MethodTypeString;
2302 Result += "\t }\n};\n";
2305 // Output class methods declared in this protocol.
2306 NumMethods = PDecl->getNumClassMethods();
2307 if (NumMethods > 0) {
2308 Result += "\nstatic struct _objc_protocol_method_list "
2309 "_OBJC_PROTOCOL_CLASS_METHODS_";
2310 Result += PDecl->getName();
2311 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
2313 Result += utostr(NumMethods);
2316 // Output instance methods declared in this protocol.
2317 for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(),
2318 E = PDecl->classmeth_end(); I != E; ++I) {
2319 if (I == PDecl->classmeth_begin())
2320 Result += "\t ,{{(SEL)\"";
2322 Result += "\t ,{(SEL)\"";
2323 Result += (*I)->getSelector().getName().c_str();
2324 std::string MethodTypeString;
2325 Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
2327 Result += MethodTypeString;
2330 Result += "\t }\n};\n";
2333 /* struct _objc_protocol {
2334 // Objective-C 1.0 extensions
2335 struct _objc_protocol_extension *isa;
2336 char *protocol_name;
2337 struct _objc_protocol **protocol_list;
2338 struct _objc_protocol_method_list *instance_methods;
2339 struct _objc_protocol_method_list *class_methods;
2342 static bool objc_protocol = false;
2343 if (!objc_protocol) {
2344 Result += "\nstruct _objc_protocol {\n";
2345 Result += "\tstruct _objc_protocol_extension *isa;\n";
2346 Result += "\tchar *protocol_name;\n";
2347 Result += "\tstruct _objc_protocol **protocol_list;\n";
2348 Result += "\tstruct _objc_protocol_method_list *instance_methods;\n";
2349 Result += "\tstruct _objc_protocol_method_list *class_methods;\n";
2352 /* struct _objc_protocol_list {
2353 struct _objc_protocol_list *next;
2355 struct _objc_protocol *class_protocols[];
2358 Result += "\nstruct _objc_protocol_list {\n";
2359 Result += "\tstruct _objc_protocol_list *next;\n";
2360 Result += "\tint protocol_count;\n";
2361 Result += "\tstruct _objc_protocol *class_protocols[];\n";
2363 objc_protocol = true;
2366 Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_";
2367 Result += PDecl->getName();
2368 Result += " __attribute__ ((section (\"__OBJC, __protocol\")))= "
2370 Result += PDecl->getName();
2371 Result += "\", 0, ";
2372 if (PDecl->getNumInstanceMethods() > 0) {
2373 Result += "&_OBJC_PROTOCOL_INSTANCE_METHODS_";
2374 Result += PDecl->getName();
2379 if (PDecl->getNumClassMethods() > 0) {
2380 Result += "&_OBJC_PROTOCOL_CLASS_METHODS_";
2381 Result += PDecl->getName();
2388 // Output the top lovel protocol meta-data for the class.
2389 Result += "\nstatic struct _objc_protocol_list _OBJC_";
2391 Result += "_PROTOCOLS_";
2392 Result += ClassName;
2393 Result += " __attribute__ ((section (\"__OBJC, __cat_cls_meth\")))= "
2395 Result += utostr(NumProtocols);
2398 Result += "\t,{&_OBJC_PROTOCOL_";
2399 Result += Protocols[0]->getName();
2402 for (int i = 1; i < NumProtocols; i++) {
2403 ObjCProtocolDecl *PDecl = Protocols[i];
2404 Result += "\t ,&_OBJC_PROTOCOL_";
2405 Result += PDecl->getName();
2408 Result += "\t }\n};\n";
2412 /// RewriteObjCCategoryImplDecl - Rewrite metadata for each category
2414 void RewriteTest::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
2415 std::string &Result) {
2416 ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface();
2417 // Find category declaration for this implementation.
2418 ObjCCategoryDecl *CDecl;
2419 for (CDecl = ClassDecl->getCategoryList(); CDecl;
2420 CDecl = CDecl->getNextClassCategory())
2421 if (CDecl->getIdentifier() == IDecl->getIdentifier())
2424 std::string FullCategoryName = ClassDecl->getName();
2425 FullCategoryName += '_';
2426 FullCategoryName += IDecl->getName();
2428 // Build _objc_method_list for class's instance methods if needed
2429 RewriteObjCMethodsMetaData(IDecl->instmeth_begin(), IDecl->instmeth_end(),
2430 true, "CATEGORY_", FullCategoryName.c_str(),
2433 // Build _objc_method_list for class's class methods if needed
2434 RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
2435 false, "CATEGORY_", FullCategoryName.c_str(),
2438 // Protocols referenced in class declaration?
2439 // Null CDecl is case of a category implementation with no category interface
2441 RewriteObjCProtocolsMetaData(CDecl->getReferencedProtocols(),
2442 CDecl->getNumReferencedProtocols(),
2444 FullCategoryName.c_str(), Result);
2446 /* struct _objc_category {
2447 char *category_name;
2449 struct _objc_method_list *instance_methods;
2450 struct _objc_method_list *class_methods;
2451 struct _objc_protocol_list *protocols;
2452 // Objective-C 1.0 extensions
2453 uint32_t size; // sizeof (struct _objc_category)
2454 struct _objc_property_list *instance_properties; // category's own
2459 static bool objc_category = false;
2460 if (!objc_category) {
2461 Result += "\nstruct _objc_category {\n";
2462 Result += "\tchar *category_name;\n";
2463 Result += "\tchar *class_name;\n";
2464 Result += "\tstruct _objc_method_list *instance_methods;\n";
2465 Result += "\tstruct _objc_method_list *class_methods;\n";
2466 Result += "\tstruct _objc_protocol_list *protocols;\n";
2467 Result += "\tunsigned int size;\n";
2468 Result += "\tstruct _objc_property_list *instance_properties;\n";
2470 objc_category = true;
2472 Result += "\nstatic struct _objc_category _OBJC_CATEGORY_";
2473 Result += FullCategoryName;
2474 Result += " __attribute__ ((section (\"__OBJC, __category\")))= {\n\t\"";
2475 Result += IDecl->getName();
2476 Result += "\"\n\t, \"";
2477 Result += ClassDecl->getName();
2480 if (IDecl->getNumInstanceMethods() > 0) {
2481 Result += "\t, (struct _objc_method_list *)"
2482 "&_OBJC_CATEGORY_INSTANCE_METHODS_";
2483 Result += FullCategoryName;
2487 Result += "\t, 0\n";
2488 if (IDecl->getNumClassMethods() > 0) {
2489 Result += "\t, (struct _objc_method_list *)"
2490 "&_OBJC_CATEGORY_CLASS_METHODS_";
2491 Result += FullCategoryName;
2495 Result += "\t, 0\n";
2497 if (CDecl && CDecl->getNumReferencedProtocols() > 0) {
2498 Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";
2499 Result += FullCategoryName;
2503 Result += "\t, 0\n";
2504 Result += "\t, sizeof(struct _objc_category), 0\n};\n";
2507 /// SynthesizeIvarOffsetComputation - This rutine synthesizes computation of
2509 void RewriteTest::SynthesizeIvarOffsetComputation(ObjCImplementationDecl *IDecl,
2511 std::string &Result) {
2512 Result += "offsetof(struct ";
2513 Result += IDecl->getName();
2515 Result += ivar->getName();
2519 //===----------------------------------------------------------------------===//
2520 // Meta Data Emission
2521 //===----------------------------------------------------------------------===//
2523 void RewriteTest::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
2524 std::string &Result) {
2525 ObjCInterfaceDecl *CDecl = IDecl->getClassInterface();
2527 // Explictly declared @interface's are already synthesized.
2528 if (CDecl->ImplicitInterfaceDecl()) {
2529 // FIXME: Implementation of a class with no @interface (legacy) doese not
2530 // produce correct synthesis as yet.
2531 SynthesizeObjCInternalStruct(CDecl, Result);
2534 // Build _objc_ivar_list metadata for classes ivars if needed
2535 int NumIvars = IDecl->getImplDeclNumIvars() > 0
2536 ? IDecl->getImplDeclNumIvars()
2537 : (CDecl ? CDecl->getNumInstanceVariables() : 0);
2539 static bool objc_ivar = false;
2541 /* struct _objc_ivar {
2547 Result += "\nstruct _objc_ivar {\n";
2548 Result += "\tchar *ivar_name;\n";
2549 Result += "\tchar *ivar_type;\n";
2550 Result += "\tint ivar_offset;\n";
2553 /* struct _objc_ivar_list {
2555 struct _objc_ivar ivar_list[];
2558 Result += "\nstruct _objc_ivar_list {\n";
2559 Result += "\tint ivar_count;\n";
2560 Result += "\tstruct _objc_ivar ivar_list[];\n};\n";
2564 Result += "\nstatic struct _objc_ivar_list _OBJC_INSTANCE_VARIABLES_";
2565 Result += IDecl->getName();
2566 Result += " __attribute__ ((section (\"__OBJC, __instance_vars\")))= "
2568 Result += utostr(NumIvars);
2571 ObjCInterfaceDecl::ivar_iterator IVI, IVE;
2572 if (IDecl->getImplDeclNumIvars() > 0) {
2573 IVI = IDecl->ivar_begin();
2574 IVE = IDecl->ivar_end();
2576 IVI = CDecl->ivar_begin();
2577 IVE = CDecl->ivar_end();
2579 Result += "\t,{{\"";
2580 Result += (*IVI)->getName();
2582 std::string StrEncoding;
2583 Context->getObjCEncodingForType((*IVI)->getType(), StrEncoding,
2584 EncodingRecordTypes);
2585 Result += StrEncoding;
2587 SynthesizeIvarOffsetComputation(IDecl, *IVI, Result);
2589 for (++IVI; IVI != IVE; ++IVI) {
2590 Result += "\t ,{\"";
2591 Result += (*IVI)->getName();
2593 std::string StrEncoding;
2594 Context->getObjCEncodingForType((*IVI)->getType(), StrEncoding,
2595 EncodingRecordTypes);
2596 Result += StrEncoding;
2598 SynthesizeIvarOffsetComputation(IDecl, (*IVI), Result);
2602 Result += "\t }\n};\n";
2605 // Build _objc_method_list for class's instance methods if needed
2606 RewriteObjCMethodsMetaData(IDecl->instmeth_begin(), IDecl->instmeth_end(),
2607 true, "", IDecl->getName(), Result);
2609 // Build _objc_method_list for class's class methods if needed
2610 RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
2611 false, "", IDecl->getName(), Result);
2613 // Protocols referenced in class declaration?
2614 RewriteObjCProtocolsMetaData(CDecl->getReferencedProtocols(),
2615 CDecl->getNumIntfRefProtocols(),
2616 "CLASS", CDecl->getName(), Result);
2619 // Declaration of class/meta-class metadata
2620 /* struct _objc_class {
2621 struct _objc_class *isa; // or const char *root_class_name when metadata
2622 const char *super_class_name;
2627 struct _objc_ivar_list *ivars;
2628 struct _objc_method_list *methods;
2629 struct objc_cache *cache;
2630 struct objc_protocol_list *protocols;
2631 const char *ivar_layout;
2632 struct _objc_class_ext *ext;
2635 static bool objc_class = false;
2637 Result += "\nstruct _objc_class {\n";
2638 Result += "\tstruct _objc_class *isa;\n";
2639 Result += "\tconst char *super_class_name;\n";
2640 Result += "\tchar *name;\n";
2641 Result += "\tlong version;\n";
2642 Result += "\tlong info;\n";
2643 Result += "\tlong instance_size;\n";
2644 Result += "\tstruct _objc_ivar_list *ivars;\n";
2645 Result += "\tstruct _objc_method_list *methods;\n";
2646 Result += "\tstruct objc_cache *cache;\n";
2647 Result += "\tstruct _objc_protocol_list *protocols;\n";
2648 Result += "\tconst char *ivar_layout;\n";
2649 Result += "\tstruct _objc_class_ext *ext;\n";
2654 // Meta-class metadata generation.
2655 ObjCInterfaceDecl *RootClass = 0;
2656 ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass();
2657 while (SuperClass) {
2658 RootClass = SuperClass;
2659 SuperClass = SuperClass->getSuperClass();
2661 SuperClass = CDecl->getSuperClass();
2663 Result += "\nstatic struct _objc_class _OBJC_METACLASS_";
2664 Result += CDecl->getName();
2665 Result += " __attribute__ ((section (\"__OBJC, __meta_class\")))= "
2666 "{\n\t(struct _objc_class *)\"";
2667 Result += (RootClass ? RootClass->getName() : CDecl->getName());
2672 Result += SuperClass->getName();
2674 Result += CDecl->getName();
2678 Result += ", 0, \"";
2679 Result += CDecl->getName();
2682 // Set 'ivars' field for root class to 0. ObjC1 runtime does not use it.
2683 // 'info' field is initialized to CLS_META(2) for metaclass
2684 Result += ", 0,2, sizeof(struct _objc_class), 0";
2685 if (IDecl->getNumClassMethods() > 0) {
2686 Result += "\n\t, &_OBJC_CLASS_METHODS_";
2687 Result += IDecl->getName();
2692 if (CDecl->getNumIntfRefProtocols() > 0) {
2693 Result += "\t,0, &_OBJC_CLASS_PROTOCOLS_";
2694 Result += CDecl->getName();
2698 Result += "\t,0,0,0,0\n";
2701 // class metadata generation.
2702 Result += "\nstatic struct _objc_class _OBJC_CLASS_";
2703 Result += CDecl->getName();
2704 Result += " __attribute__ ((section (\"__OBJC, __class\")))= "
2705 "{\n\t&_OBJC_METACLASS_";
2706 Result += CDecl->getName();
2709 Result += SuperClass->getName();
2711 Result += CDecl->getName();
2715 Result += ", 0, \"";
2716 Result += CDecl->getName();
2719 // 'info' field is initialized to CLS_CLASS(1) for class
2721 if (!ObjCSynthesizedStructs.count(CDecl))
2724 // class has size. Must synthesize its size.
2725 Result += ",sizeof(struct ";
2726 Result += CDecl->getName();
2730 Result += ", &_OBJC_INSTANCE_VARIABLES_";
2731 Result += CDecl->getName();
2736 if (IDecl->getNumInstanceMethods() > 0) {
2737 Result += ", &_OBJC_INSTANCE_METHODS_";
2738 Result += CDecl->getName();
2739 Result += ", 0\n\t";
2743 if (CDecl->getNumIntfRefProtocols() > 0) {
2744 Result += ", &_OBJC_CLASS_PROTOCOLS_";
2745 Result += CDecl->getName();
2746 Result += ", 0,0\n";
2749 Result += ",0,0,0\n";
2753 /// RewriteImplementations - This routine rewrites all method implementations
2754 /// and emits meta-data.
2756 void RewriteTest::RewriteImplementations(std::string &Result) {
2757 int ClsDefCount = ClassImplementation.size();
2758 int CatDefCount = CategoryImplementation.size();
2760 if (ClsDefCount == 0 && CatDefCount == 0)
2762 // Rewrite implemented methods
2763 for (int i = 0; i < ClsDefCount; i++)
2764 RewriteImplementationDecl(ClassImplementation[i]);
2766 for (int i = 0; i < CatDefCount; i++)
2767 RewriteImplementationDecl(CategoryImplementation[i]);
2769 // This is needed for use of offsetof
2770 Result += "#include <stddef.h>\n";
2772 // For each implemented class, write out all its meta data.
2773 for (int i = 0; i < ClsDefCount; i++)
2774 RewriteObjCClassMetaData(ClassImplementation[i], Result);
2776 // For each implemented category, write out all its meta data.
2777 for (int i = 0; i < CatDefCount; i++)
2778 RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result);
2780 // Write objc_symtab metadata
2788 void *defs[cls_def_cnt + cat_def_cnt];
2792 Result += "\nstruct _objc_symtab {\n";
2793 Result += "\tlong sel_ref_cnt;\n";
2794 Result += "\tSEL *refs;\n";
2795 Result += "\tshort cls_def_cnt;\n";
2796 Result += "\tshort cat_def_cnt;\n";
2797 Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n";
2800 Result += "static struct _objc_symtab "
2801 "_OBJC_SYMBOLS __attribute__((section (\"__OBJC, __symbols\")))= {\n";
2802 Result += "\t0, 0, " + utostr(ClsDefCount)
2803 + ", " + utostr(CatDefCount) + "\n";
2804 for (int i = 0; i < ClsDefCount; i++) {
2805 Result += "\t,&_OBJC_CLASS_";
2806 Result += ClassImplementation[i]->getName();
2810 for (int i = 0; i < CatDefCount; i++) {
2811 Result += "\t,&_OBJC_CATEGORY_";
2812 Result += CategoryImplementation[i]->getClassInterface()->getName();
2814 Result += CategoryImplementation[i]->getName();
2820 // Write objc_module metadata
2823 struct _objc_module {
2827 struct _objc_symtab *symtab;
2831 Result += "\nstruct _objc_module {\n";
2832 Result += "\tlong version;\n";
2833 Result += "\tlong size;\n";
2834 Result += "\tconst char *name;\n";
2835 Result += "\tstruct _objc_symtab *symtab;\n";
2837 Result += "static struct _objc_module "
2838 "_OBJC_MODULES __attribute__ ((section (\"__OBJC, __module_info\")))= {\n";
2839 Result += "\t" + utostr(OBJC_ABI_VERSION) +
2840 ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";