diff options
Diffstat (limited to 'clang/Driver/RewriteObjC.cpp')
-rw-r--r-- | clang/Driver/RewriteObjC.cpp | 3031 |
1 files changed, 0 insertions, 3031 deletions
diff --git a/clang/Driver/RewriteObjC.cpp b/clang/Driver/RewriteObjC.cpp deleted file mode 100644 index cf715d0c..0000000 --- a/clang/Driver/RewriteObjC.cpp +++ /dev/null @@ -1,3031 +0,0 @@ -//===--- RewriteObjC.cpp - Playground for the code rewriter ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Hacks and fun related to the code rewriter. -// -//===----------------------------------------------------------------------===// - -#include "ASTConsumers.h" -#include "clang/Rewrite/Rewriter.h" -#include "clang/AST/AST.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/IdentifierTable.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Lex/Lexer.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/System/Path.h" -#include <sstream> -#include <fstream> -using namespace clang; -using llvm::utostr; - -static llvm::cl::opt<bool> -SilenceRewriteMacroWarning("Wno-rewrite-macros", llvm::cl::init(false), - llvm::cl::desc("Silence ObjC rewriting warnings")); - -namespace { - class RewriteObjC : public ASTConsumer { - Rewriter Rewrite; - Diagnostic &Diags; - const LangOptions &LangOpts; - unsigned RewriteFailedDiag; - - ASTContext *Context; - SourceManager *SM; - TranslationUnitDecl *TUDecl; - unsigned MainFileID; - const char *MainFileStart, *MainFileEnd; - SourceLocation LastIncLoc; - - llvm::SmallVector<ObjCImplementationDecl *, 8> ClassImplementation; - llvm::SmallVector<ObjCCategoryImplDecl *, 8> CategoryImplementation; - llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCSynthesizedStructs; - llvm::SmallPtrSet<ObjCProtocolDecl*, 8> ObjCSynthesizedProtocols; - llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCForwardDecls; - llvm::DenseMap<ObjCMethodDecl*, std::string> MethodInternalNames; - llvm::SmallVector<Stmt *, 32> Stmts; - llvm::SmallVector<int, 8> ObjCBcLabelNo; - llvm::SmallVector<const RecordType *, 8> EncodingRecordTypes; - - unsigned NumObjCStringLiterals; - - FunctionDecl *MsgSendFunctionDecl; - FunctionDecl *MsgSendSuperFunctionDecl; - FunctionDecl *MsgSendStretFunctionDecl; - FunctionDecl *MsgSendSuperStretFunctionDecl; - FunctionDecl *MsgSendFpretFunctionDecl; - FunctionDecl *GetClassFunctionDecl; - FunctionDecl *GetMetaClassFunctionDecl; - FunctionDecl *SelGetUidFunctionDecl; - FunctionDecl *CFStringFunctionDecl; - FunctionDecl *GetProtocolFunctionDecl; - FunctionDecl *SuperContructorFunctionDecl; - - // ObjC string constant support. - VarDecl *ConstantStringClassReference; - RecordDecl *NSStringRecord; - - // ObjC foreach break/continue generation support. - int BcLabelCount; - - // Needed for super. - ObjCMethodDecl *CurMethodDecl; - RecordDecl *SuperStructDecl; - RecordDecl *ConstantStringDecl; - - // Needed for header files being rewritten - bool IsHeader; - - std::string InFileName; - std::string OutFileName; - - std::string Preamble; - - static const int OBJC_ABI_VERSION =7 ; - public: - void Initialize(ASTContext &context); - - - // Top Level Driver code. - virtual void HandleTopLevelDecl(Decl *D); - void HandleDeclInMainFile(Decl *D); - RewriteObjC(std::string inFile, std::string outFile, - Diagnostic &D, const LangOptions &LOpts); - ~RewriteObjC(); - - void ReplaceStmt(Stmt *Old, Stmt *New) { - // If replacement succeeded or warning disabled return with no warning. - if (!Rewrite.ReplaceStmt(Old, New) || SilenceRewriteMacroWarning) - return; - - SourceRange Range = Old->getSourceRange(); - Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag, - 0, 0, &Range, 1); - } - - void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen, - bool InsertAfter = true) { - // If insertion succeeded or warning disabled return with no warning. - if (!Rewrite.InsertText(Loc, StrData, StrLen, InsertAfter) || - SilenceRewriteMacroWarning) - return; - - Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag); - } - - void RemoveText(SourceLocation Loc, unsigned StrLen) { - // If removal succeeded or warning disabled return with no warning. - if (!Rewrite.RemoveText(Loc, StrLen) || SilenceRewriteMacroWarning) - return; - - Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag); - } - - void ReplaceText(SourceLocation Start, unsigned OrigLength, - const char *NewStr, unsigned NewLength) { - // If removal succeeded or warning disabled return with no warning. - if (!Rewrite.ReplaceText(Start, OrigLength, NewStr, NewLength) || - SilenceRewriteMacroWarning) - return; - - Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag); - } - - // Syntactic Rewriting. - void RewritePrologue(SourceLocation Loc); - void RewriteInclude(); - void RewriteTabs(); - void RewriteForwardClassDecl(ObjCClassDecl *Dcl); - void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl); - void RewriteImplementationDecl(NamedDecl *Dcl); - void RewriteObjCMethodDecl(ObjCMethodDecl *MDecl, std::string &ResultStr); - void RewriteCategoryDecl(ObjCCategoryDecl *Dcl); - void RewriteProtocolDecl(ObjCProtocolDecl *Dcl); - void RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *Dcl); - void RewriteMethodDeclaration(ObjCMethodDecl *Method); - void RewriteProperties(unsigned nProperties, ObjCPropertyDecl **Properties); - void RewriteFunctionDecl(FunctionDecl *FD); - void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl); - bool needToScanForQualifiers(QualType T); - ObjCInterfaceDecl *isSuperReceiver(Expr *recExpr); - QualType getSuperStructType(); - QualType getConstantStringStructType(); - - // Expression Rewriting. - Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S); - Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp); - Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV); - Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp); - Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp); - Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp); - Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp); - Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S); - Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S); - Stmt *RewriteObjCCatchStmt(ObjCAtCatchStmt *S); - Stmt *RewriteObjCFinallyStmt(ObjCAtFinallyStmt *S); - Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S); - Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, - SourceLocation OrigEnd); - CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD, - Expr **args, unsigned nargs); - Stmt *SynthMessageExpr(ObjCMessageExpr *Exp); - Stmt *RewriteBreakStmt(BreakStmt *S); - Stmt *RewriteContinueStmt(ContinueStmt *S); - void SynthCountByEnumWithState(std::string &buf); - - void SynthMsgSendFunctionDecl(); - void SynthMsgSendSuperFunctionDecl(); - void SynthMsgSendStretFunctionDecl(); - void SynthMsgSendFpretFunctionDecl(); - void SynthMsgSendSuperStretFunctionDecl(); - void SynthGetClassFunctionDecl(); - void SynthGetMetaClassFunctionDecl(); - void SynthSelGetUidFunctionDecl(); - void SynthGetProtocolFunctionDecl(); - void SynthSuperContructorFunctionDecl(); - - // Metadata emission. - void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, - std::string &Result); - - void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl, - std::string &Result); - - typedef ObjCCategoryImplDecl::instmeth_iterator instmeth_iterator; - void RewriteObjCMethodsMetaData(instmeth_iterator MethodBegin, - instmeth_iterator MethodEnd, - bool IsInstanceMethod, - const char *prefix, - const char *ClassName, - std::string &Result); - - void RewriteObjCProtocolsMetaData(ObjCProtocolDecl **Protocols, - int NumProtocols, - const char *prefix, - const char *ClassName, - std::string &Result); - void SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, - std::string &Result); - void SynthesizeIvarOffsetComputation(ObjCImplementationDecl *IDecl, - ObjCIvarDecl *ivar, - std::string &Result); - void RewriteImplementations(std::string &Result); - }; -} - -static bool IsHeaderFile(const std::string &Filename) { - std::string::size_type DotPos = Filename.rfind('.'); - - if (DotPos == std::string::npos) { - // no file extension - return false; - } - - std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end()); - // C header: .h - // C++ header: .hh or .H; - return Ext == "h" || Ext == "hh" || Ext == "H"; -} - -RewriteObjC::RewriteObjC(std::string inFile, std::string outFile, - Diagnostic &D, const LangOptions &LOpts) - : Diags(D), LangOpts(LOpts) { - IsHeader = IsHeaderFile(inFile); - InFileName = inFile; - OutFileName = outFile; - RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning, - "rewriting sub-expression within a macro (may not be correct)"); -} - -ASTConsumer *clang::CreateCodeRewriterTest(const std::string& InFile, - const std::string& OutFile, - Diagnostic &Diags, - const LangOptions &LOpts) { - return new RewriteObjC(InFile, OutFile, Diags, LOpts); -} - -void RewriteObjC::Initialize(ASTContext &context) { - Context = &context; - SM = &Context->getSourceManager(); - TUDecl = Context->getTranslationUnitDecl(); - MsgSendFunctionDecl = 0; - MsgSendSuperFunctionDecl = 0; - MsgSendStretFunctionDecl = 0; - MsgSendSuperStretFunctionDecl = 0; - MsgSendFpretFunctionDecl = 0; - GetClassFunctionDecl = 0; - GetMetaClassFunctionDecl = 0; - SelGetUidFunctionDecl = 0; - CFStringFunctionDecl = 0; - GetProtocolFunctionDecl = 0; - ConstantStringClassReference = 0; - NSStringRecord = 0; - CurMethodDecl = 0; - SuperStructDecl = 0; - ConstantStringDecl = 0; - BcLabelCount = 0; - SuperContructorFunctionDecl = 0; - NumObjCStringLiterals = 0; - - // Get the ID and start/end of the main file. - MainFileID = SM->getMainFileID(); - const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID); - MainFileStart = MainBuf->getBufferStart(); - MainFileEnd = MainBuf->getBufferEnd(); - - Rewrite.setSourceMgr(Context->getSourceManager()); - - // declaring objc_selector outside the parameter list removes a silly - // scope related warning... - if (IsHeader) - Preamble = "#pragma once\n"; - Preamble += "struct objc_selector; struct objc_class;\n"; - Preamble += "#ifndef OBJC_SUPER\n"; - Preamble += "struct objc_super { struct objc_object *object; "; - Preamble += "struct objc_object *superClass; "; - if (LangOpts.Microsoft) { - // Add a constructor for creating temporary objects. - Preamble += "objc_super(struct objc_object *o, struct objc_object *s) : "; - Preamble += "object(o), superClass(s) {} "; - } - Preamble += "};\n"; - Preamble += "#define OBJC_SUPER\n"; - Preamble += "#endif\n"; - Preamble += "#ifndef _REWRITER_typedef_Protocol\n"; - Preamble += "typedef struct objc_object Protocol;\n"; - Preamble += "#define _REWRITER_typedef_Protocol\n"; - Preamble += "#endif\n"; - if (LangOpts.Microsoft) - Preamble += "#define __OBJC_RW_EXTERN extern \"C\" __declspec(dllimport)\n"; - else - Preamble += "#define __OBJC_RW_EXTERN extern\n"; - Preamble += "__OBJC_RW_EXTERN struct objc_object *objc_msgSend"; - Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; - Preamble += "__OBJC_RW_EXTERN struct objc_object *objc_msgSendSuper"; - Preamble += "(struct objc_super *, struct objc_selector *, ...);\n"; - Preamble += "__OBJC_RW_EXTERN struct objc_object *objc_msgSend_stret"; - Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; - Preamble += "__OBJC_RW_EXTERN struct objc_object *objc_msgSendSuper_stret"; - Preamble += "(struct objc_super *, struct objc_selector *, ...);\n"; - Preamble += "__OBJC_RW_EXTERN double objc_msgSend_fpret"; - Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; - Preamble += "__OBJC_RW_EXTERN struct objc_object *objc_getClass"; - Preamble += "(const char *);\n"; - Preamble += "__OBJC_RW_EXTERN struct objc_object *objc_getMetaClass"; - Preamble += "(const char *);\n"; - Preamble += "__OBJC_RW_EXTERN void objc_exception_throw(struct objc_object *);\n"; - Preamble += "__OBJC_RW_EXTERN void objc_exception_try_enter(void *);\n"; - Preamble += "__OBJC_RW_EXTERN void objc_exception_try_exit(void *);\n"; - Preamble += "__OBJC_RW_EXTERN struct objc_object *objc_exception_extract(void *);\n"; - Preamble += "__OBJC_RW_EXTERN int objc_exception_match"; - Preamble += "(struct objc_class *, struct objc_object *);\n"; - Preamble += "__OBJC_RW_EXTERN Protocol *objc_getProtocol(const char *);\n"; - if (LangOpts.Microsoft) - Preamble += "#undef __OBJC_RW_EXTERN\n"; - Preamble += "#ifndef __FASTENUMERATIONSTATE\n"; - Preamble += "struct __objcFastEnumerationState {\n\t"; - Preamble += "unsigned long state;\n\t"; - Preamble += "void **itemsPtr;\n\t"; - Preamble += "unsigned long *mutationsPtr;\n\t"; - Preamble += "unsigned long extra[5];\n};\n"; - Preamble += "#define __FASTENUMERATIONSTATE\n"; - Preamble += "#endif\n"; - Preamble += "#ifndef __NSCONSTANTSTRINGIMPL\n"; - Preamble += "struct __NSConstantStringImpl {\n"; - Preamble += " int *isa;\n"; - Preamble += " int flags;\n"; - Preamble += " char *str;\n"; - Preamble += " long length;\n"; - Preamble += "};\n"; - Preamble += "extern int __CFConstantStringClassReference[];\n"; - Preamble += "#define __NSCONSTANTSTRINGIMPL\n"; - Preamble += "#endif\n"; - if (LangOpts.Microsoft) - Preamble += "#define __attribute__(X)\n"; -} - - -//===----------------------------------------------------------------------===// -// Top Level Driver Code -//===----------------------------------------------------------------------===// - -void RewriteObjC::HandleTopLevelDecl(Decl *D) { - // Two cases: either the decl could be in the main file, or it could be in a - // #included file. If the former, rewrite it now. If the later, check to see - // if we rewrote the #include/#import. - SourceLocation Loc = D->getLocation(); - Loc = SM->getLogicalLoc(Loc); - - // If this is for a builtin, ignore it. - if (Loc.isInvalid()) return; - - // Look for built-in declarations that we need to refer during the rewrite. - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - RewriteFunctionDecl(FD); - } else if (VarDecl *FVD = dyn_cast<VarDecl>(D)) { - // declared in <Foundation/NSString.h> - if (strcmp(FVD->getName(), "_NSConstantStringClassReference") == 0) { - ConstantStringClassReference = FVD; - return; - } - } else if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D)) { - RewriteInterfaceDecl(MD); - } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) { - RewriteCategoryDecl(CD); - } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) { - RewriteProtocolDecl(PD); - } else if (ObjCForwardProtocolDecl *FP = - dyn_cast<ObjCForwardProtocolDecl>(D)){ - RewriteForwardProtocolDecl(FP); - } - // If we have a decl in the main file, see if we should rewrite it. - if (SM->isFromMainFile(Loc)) - return HandleDeclInMainFile(D); -} - -/// HandleDeclInMainFile - This is called for each top-level decl defined in the -/// main file of the input. -void RewriteObjC::HandleDeclInMainFile(Decl *D) { - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - if (Stmt *Body = FD->getBody()) - FD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body)); - - if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - if (Stmt *Body = MD->getBody()) { - //Body->dump(); - CurMethodDecl = MD; - MD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body)); - CurMethodDecl = 0; - } - } - if (ObjCImplementationDecl *CI = dyn_cast<ObjCImplementationDecl>(D)) - ClassImplementation.push_back(CI); - else if (ObjCCategoryImplDecl *CI = dyn_cast<ObjCCategoryImplDecl>(D)) - CategoryImplementation.push_back(CI); - else if (ObjCClassDecl *CD = dyn_cast<ObjCClassDecl>(D)) - RewriteForwardClassDecl(CD); - else if (VarDecl *VD = dyn_cast<VarDecl>(D)) { - RewriteObjCQualifiedInterfaceTypes(VD); - if (VD->getInit()) - RewriteFunctionBodyOrGlobalInitializer(VD->getInit()); - } - // Nothing yet. -} - -RewriteObjC::~RewriteObjC() { - // Get the top-level buffer that this corresponds to. - - // Rewrite tabs if we care. - //RewriteTabs(); - - if (Diags.hasErrorOccurred()) - return; - - // Create the output file. - - std::ostream *OutFile; - if (OutFileName == "-") { - OutFile = llvm::cout.stream(); - } else if (!OutFileName.empty()) { - OutFile = new std::ofstream(OutFileName.c_str(), - std::ios_base::binary|std::ios_base::out); - } else if (InFileName == "-") { - OutFile = llvm::cout.stream(); - } else { - llvm::sys::Path Path(InFileName); - Path.eraseSuffix(); - Path.appendSuffix("cpp"); - OutFile = new std::ofstream(Path.toString().c_str(), - std::ios_base::binary|std::ios_base::out); - } - - RewriteInclude(); - - InsertText(SourceLocation::getFileLoc(MainFileID, 0), - Preamble.c_str(), Preamble.size(), false); - - // Rewrite Objective-c meta data* - std::string ResultStr; - RewriteImplementations(ResultStr); - - // Get the buffer corresponding to MainFileID. If we haven't changed it, then - // we are done. - if (const RewriteBuffer *RewriteBuf = - Rewrite.getRewriteBufferFor(MainFileID)) { - //printf("Changed:\n"); - *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end()); - } else { - fprintf(stderr, "No changes\n"); - } - // Emit metadata. - *OutFile << ResultStr; -} - -//===----------------------------------------------------------------------===// -// Syntactic (non-AST) Rewriting Code -//===----------------------------------------------------------------------===// - -void RewriteObjC::RewriteInclude() { - SourceLocation LocStart = SourceLocation::getFileLoc(MainFileID, 0); - std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID); - const char *MainBufStart = MainBuf.first; - const char *MainBufEnd = MainBuf.second; - size_t ImportLen = strlen("import"); - size_t IncludeLen = strlen("include"); - - // Loop over the whole file, looking for includes. - for (const char *BufPtr = MainBufStart; BufPtr < MainBufEnd; ++BufPtr) { - if (*BufPtr == '#') { - if (++BufPtr == MainBufEnd) - return; - while (*BufPtr == ' ' || *BufPtr == '\t') - if (++BufPtr == MainBufEnd) - return; - if (!strncmp(BufPtr, "import", ImportLen)) { - // replace import with include - SourceLocation ImportLoc = - LocStart.getFileLocWithOffset(BufPtr-MainBufStart); - ReplaceText(ImportLoc, ImportLen, "include", IncludeLen); - BufPtr += ImportLen; - } - } - } -} - -void RewriteObjC::RewriteTabs() { - std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID); - const char *MainBufStart = MainBuf.first; - const char *MainBufEnd = MainBuf.second; - - // Loop over the whole file, looking for tabs. - for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) { - if (*BufPtr != '\t') - continue; - - // Okay, we found a tab. This tab will turn into at least one character, - // but it depends on which 'virtual column' it is in. Compute that now. - unsigned VCol = 0; - while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' && - BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r') - ++VCol; - - // Okay, now that we know the virtual column, we know how many spaces to - // insert. We assume 8-character tab-stops. - unsigned Spaces = 8-(VCol & 7); - - // Get the location of the tab. - SourceLocation TabLoc = - SourceLocation::getFileLoc(MainFileID, BufPtr-MainBufStart); - - // Rewrite the single tab character into a sequence of spaces. - ReplaceText(TabLoc, 1, " ", Spaces); - } -} - - -void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) { - int numDecls = ClassDecl->getNumForwardDecls(); - ObjCInterfaceDecl **ForwardDecls = ClassDecl->getForwardDecls(); - - // Get the start location and compute the semi location. - SourceLocation startLoc = ClassDecl->getLocation(); - const char *startBuf = SM->getCharacterData(startLoc); - const char *semiPtr = strchr(startBuf, ';'); - - // Translate to typedef's that forward reference structs with the same name - // as the class. As a convenience, we include the original declaration - // as a comment. - std::string typedefString; - typedefString += "// "; - typedefString.append(startBuf, semiPtr-startBuf+1); - typedefString += "\n"; - for (int i = 0; i < numDecls; i++) { - ObjCInterfaceDecl *ForwardDecl = ForwardDecls[i]; - typedefString += "#ifndef _REWRITER_typedef_"; - typedefString += ForwardDecl->getName(); - typedefString += "\n"; - typedefString += "#define _REWRITER_typedef_"; - typedefString += ForwardDecl->getName(); - typedefString += "\n"; - typedefString += "typedef struct objc_object "; - typedefString += ForwardDecl->getName(); - typedefString += ";\n#endif\n"; - } - - // Replace the @class with typedefs corresponding to the classes. - ReplaceText(startLoc, semiPtr-startBuf+1, - typedefString.c_str(), typedefString.size()); -} - -void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) { - SourceLocation LocStart = Method->getLocStart(); - SourceLocation LocEnd = Method->getLocEnd(); - - if (SM->getLineNumber(LocEnd) > SM->getLineNumber(LocStart)) { - InsertText(LocStart, "/* ", 3); - ReplaceText(LocEnd, 1, ";*/ ", 4); - } else { - InsertText(LocStart, "// ", 3); - } -} - -void RewriteObjC::RewriteProperties(unsigned nProperties, ObjCPropertyDecl **Properties) -{ - for (unsigned i = 0; i < nProperties; i++) { - ObjCPropertyDecl *Property = Properties[i]; - SourceLocation Loc = Property->getLocation(); - - ReplaceText(Loc, 0, "// ", 3); - - // FIXME: handle properties that are declared across multiple lines. - } -} - -void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) { - SourceLocation LocStart = CatDecl->getLocStart(); - - // FIXME: handle category headers that are declared across multiple lines. - ReplaceText(LocStart, 0, "// ", 3); - - for (ObjCCategoryDecl::instmeth_iterator I = CatDecl->instmeth_begin(), - E = CatDecl->instmeth_end(); I != E; ++I) - RewriteMethodDeclaration(*I); - for (ObjCCategoryDecl::classmeth_iterator I = CatDecl->classmeth_begin(), - E = CatDecl->classmeth_end(); I != E; ++I) - RewriteMethodDeclaration(*I); - - // Lastly, comment out the @end. - ReplaceText(CatDecl->getAtEndLoc(), 0, "// ", 3); -} - -void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { - std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID); - - SourceLocation LocStart = PDecl->getLocStart(); - - // FIXME: handle protocol headers that are declared across multiple lines. - ReplaceText(LocStart, 0, "// ", 3); - - for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(), - E = PDecl->instmeth_end(); I != E; ++I) - RewriteMethodDeclaration(*I); - for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(), - E = PDecl->classmeth_end(); I != E; ++I) - RewriteMethodDeclaration(*I); - - // Lastly, comment out the @end. - SourceLocation LocEnd = PDecl->getAtEndLoc(); - ReplaceText(LocEnd, 0, "// ", 3); - - // Must comment out @optional/@required - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - for (const char *p = startBuf; p < endBuf; p++) { - if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) { - std::string CommentedOptional = "/* @optional */"; - SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf); - ReplaceText(OptionalLoc, strlen("@optional"), - CommentedOptional.c_str(), CommentedOptional.size()); - - } - else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) { - std::string CommentedRequired = "/* @required */"; - SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf); - ReplaceText(OptionalLoc, strlen("@required"), - CommentedRequired.c_str(), CommentedRequired.size()); - - } - } -} - -void RewriteObjC::RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *PDecl) { - SourceLocation LocStart = PDecl->getLocation(); - if (LocStart.isInvalid()) - assert(false && "Invalid SourceLocation"); - // FIXME: handle forward protocol that are declared across multiple lines. - ReplaceText(LocStart, 0, "// ", 3); -} - -void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD, - std::string &ResultStr) { - ResultStr += "\nstatic "; - if (OMD->getResultType()->isObjCQualifiedIdType()) - ResultStr += "id"; - else - ResultStr += OMD->getResultType().getAsString(); - ResultStr += " "; - - // Unique method name - std::string NameStr; - - if (OMD->isInstance()) - NameStr += "_I_"; - else - NameStr += "_C_"; - - NameStr += OMD->getClassInterface()->getName(); - NameStr += "_"; - - NamedDecl *MethodContext = OMD->getMethodContext(); - if (ObjCCategoryImplDecl *CID = - dyn_cast<ObjCCategoryImplDecl>(MethodContext)) { - NameStr += CID->getName(); - NameStr += "_"; - } - // Append selector names, replacing ':' with '_' - if (OMD->getSelector().getName().find(':') == std::string::npos) - NameStr += OMD->getSelector().getName(); - else { - std::string selString = OMD->getSelector().getName(); - int len = selString.size(); - for (int i = 0; i < len; i++) - if (selString[i] == ':') - selString[i] = '_'; - NameStr += selString; - } - // Remember this name for metadata emission - MethodInternalNames[OMD] = NameStr; - ResultStr += NameStr; - - // Rewrite arguments - ResultStr += "("; - - // invisible arguments - if (OMD->isInstance()) { - QualType selfTy = Context->getObjCInterfaceType(OMD->getClassInterface()); - selfTy = Context->getPointerType(selfTy); - if (!LangOpts.Microsoft) { - if (ObjCSynthesizedStructs.count(OMD->getClassInterface())) - ResultStr += "struct "; - } - // When rewriting for Microsoft, explicitly omit the structure name. - ResultStr += OMD->getClassInterface()->getName(); - ResultStr += " *"; - } - else - ResultStr += Context->getObjCIdType().getAsString(); - - ResultStr += " self, "; - ResultStr += Context->getObjCSelType().getAsString(); - ResultStr += " _cmd"; - - // Method arguments. - for (unsigned i = 0; i < OMD->getNumParams(); i++) { - ParmVarDecl *PDecl = OMD->getParamDecl(i); - ResultStr += ", "; - if (PDecl->getType()->isObjCQualifiedIdType()) { - ResultStr += "id "; - ResultStr += PDecl->getName(); - } else { - std::string Name = PDecl->getName(); - PDecl->getType().getAsStringInternal(Name); - ResultStr += Name; - } - } - if (OMD->isVariadic()) - ResultStr += ", ..."; - ResultStr += ") "; - -} -void RewriteObjC::RewriteImplementationDecl(NamedDecl *OID) { - ObjCImplementationDecl *IMD = dyn_cast<ObjCImplementationDecl>(OID); - ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(OID); - - if (IMD) - InsertText(IMD->getLocStart(), "// ", 3); - else - InsertText(CID->getLocStart(), "// ", 3); - - for (ObjCCategoryImplDecl::instmeth_iterator - I = IMD ? IMD->instmeth_begin() : CID->instmeth_begin(), - E = IMD ? IMD->instmeth_end() : CID->instmeth_end(); I != E; ++I) { - std::string ResultStr; - ObjCMethodDecl *OMD = *I; - RewriteObjCMethodDecl(OMD, ResultStr); - SourceLocation LocStart = OMD->getLocStart(); - SourceLocation LocEnd = OMD->getBody()->getLocStart(); - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - ReplaceText(LocStart, endBuf-startBuf, - ResultStr.c_str(), ResultStr.size()); - } - - for (ObjCCategoryImplDecl::classmeth_iterator - I = IMD ? IMD->classmeth_begin() : CID->classmeth_begin(), - E = IMD ? IMD->classmeth_end() : CID->classmeth_end(); I != E; ++I) { - std::string ResultStr; - ObjCMethodDecl *OMD = *I; - RewriteObjCMethodDecl(OMD, ResultStr); - SourceLocation LocStart = OMD->getLocStart(); - SourceLocation LocEnd = OMD->getBody()->getLocStart(); - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - ReplaceText(LocStart, endBuf-startBuf, - ResultStr.c_str(), ResultStr.size()); - } - if (IMD) - InsertText(IMD->getLocEnd(), "// ", 3); - else - InsertText(CID->getLocEnd(), "// ", 3); -} - -void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) { - std::string ResultStr; - if (!ObjCForwardDecls.count(ClassDecl)) { - // we haven't seen a forward decl - generate a typedef. - ResultStr = "#ifndef _REWRITER_typedef_"; - ResultStr += ClassDecl->getName(); - ResultStr += "\n"; - ResultStr += "#define _REWRITER_typedef_"; - ResultStr += ClassDecl->getName(); - ResultStr += "\n"; - ResultStr += "typedef struct objc_object "; - ResultStr += ClassDecl->getName(); - ResultStr += ";\n#endif\n"; - // Mark this typedef as having been generated. - ObjCForwardDecls.insert(ClassDecl); - } - SynthesizeObjCInternalStruct(ClassDecl, ResultStr); - - RewriteProperties(ClassDecl->getNumPropertyDecl(), - ClassDecl->getPropertyDecl()); - for (ObjCInterfaceDecl::instmeth_iterator I = ClassDecl->instmeth_begin(), - E = ClassDecl->instmeth_end(); I != E; ++I) - RewriteMethodDeclaration(*I); - for (ObjCInterfaceDecl::classmeth_iterator I = ClassDecl->classmeth_begin(), - E = ClassDecl->classmeth_end(); I != E; ++I) - RewriteMethodDeclaration(*I); - - // Lastly, comment out the @end. - ReplaceText(ClassDecl->getAtEndLoc(), 0, "// ", 3); -} - -Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) { - ObjCIvarDecl *D = IV->getDecl(); - if (CurMethodDecl) { - if (const PointerType *pType = IV->getBase()->getType()->getAsPointerType()) { - ObjCInterfaceType *iFaceDecl = dyn_cast<ObjCInterfaceType>(pType->getPointeeType()); - // lookup which class implements the instance variable. - ObjCInterfaceDecl *clsDeclared = 0; - iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(), clsDeclared); - assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class"); - - // Synthesize an explicit cast to gain access to the ivar. - std::string RecName = clsDeclared->getIdentifier()->getName(); - RecName += "_IMPL"; - IdentifierInfo *II = &Context->Idents.get(RecName.c_str()); - RecordDecl *RD = RecordDecl::Create(*Context, Decl::Struct, TUDecl, - SourceLocation(), II, 0); - assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); - QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); - CastExpr *castExpr = new CastExpr(castT, IV->getBase(), SourceLocation()); - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new ParenExpr(SourceLocation(), SourceLocation(), castExpr); - if (IV->isFreeIvar() && - CurMethodDecl->getClassInterface() == iFaceDecl->getDecl()) { - MemberExpr *ME = new MemberExpr(PE, true, D, IV->getLocation(), D->getType()); - ReplaceStmt(IV, ME); - delete IV; - return ME; - } else { - ReplaceStmt(IV->getBase(), PE); - // Cannot delete IV->getBase(), since PE points to it. - // Replace the old base with the cast. This is important when doing - // embedded rewrites. For example, [newInv->_container addObject:0]. - IV->setBase(PE); - return IV; - } - } - } else { // we are outside a method. - assert(!IV->isFreeIvar() && "Cannot have a free standing ivar outside a method"); - - // Explicit ivar refs need to have a cast inserted. - // FIXME: consider sharing some of this code with the code above. - if (const PointerType *pType = IV->getBase()->getType()->getAsPointerType()) { - ObjCInterfaceType *iFaceDecl = dyn_cast<ObjCInterfaceType>(pType->getPointeeType()); - // lookup which class implements the instance variable. - ObjCInterfaceDecl *clsDeclared = 0; - iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(), clsDeclared); - assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class"); - - // Synthesize an explicit cast to gain access to the ivar. - std::string RecName = clsDeclared->getIdentifier()->getName(); - RecName += "_IMPL"; - IdentifierInfo *II = &Context->Idents.get(RecName.c_str()); - RecordDecl *RD = RecordDecl::Create(*Context, Decl::Struct, TUDecl, - SourceLocation(), II, 0); - assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); - QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); - CastExpr *castExpr = new CastExpr(castT, IV->getBase(), SourceLocation()); - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new ParenExpr(SourceLocation(), SourceLocation(), castExpr); - ReplaceStmt(IV->getBase(), PE); - // Cannot delete IV->getBase(), since PE points to it. - // Replace the old base with the cast. This is important when doing - // embedded rewrites. For example, [newInv->_container addObject:0]. - IV->setBase(PE); - return IV; - } - } - return IV; -} - -//===----------------------------------------------------------------------===// -// Function Body / Expression rewriting -//===----------------------------------------------------------------------===// - -Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { - if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) || - isa<DoStmt>(S) || isa<ForStmt>(S)) - Stmts.push_back(S); - else if (isa<ObjCForCollectionStmt>(S)) { - Stmts.push_back(S); - ObjCBcLabelNo.push_back(++BcLabelCount); - } - - SourceLocation OrigStmtEnd = S->getLocEnd(); - - // Start by rewriting all children. - for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); - CI != E; ++CI) - if (*CI) { - Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(*CI); - if (newStmt) - *CI = newStmt; - } - - // Handle specific things. - if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S)) - return RewriteAtEncode(AtEncode); - - if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) - return RewriteObjCIvarRefExpr(IvarRefExpr); - - if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S)) - return RewriteAtSelector(AtSelector); - - if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S)) - return RewriteObjCStringLiteral(AtString); - - if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) { - // Before we rewrite it, put the original message expression in a comment. - SourceLocation startLoc = MessExpr->getLocStart(); - SourceLocation endLoc = MessExpr->getLocEnd(); - - const char *startBuf = SM->getCharacterData(startLoc); - const char *endBuf = SM->getCharacterData(endLoc); - - std::string messString; - messString += "// "; - messString.append(startBuf, endBuf-startBuf+1); - messString += "\n"; - - // FIXME: Missing definition of - // InsertText(clang::SourceLocation, char const*, unsigned int). - // InsertText(startLoc, messString.c_str(), messString.size()); - // Tried this, but it didn't work either... - // ReplaceText(startLoc, 0, messString.c_str(), messString.size()); - return RewriteMessageExpr(MessExpr); - } - - if (ObjCAtTryStmt *StmtTry = dyn_cast<ObjCAtTryStmt>(S)) - return RewriteObjCTryStmt(StmtTry); - - if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast<ObjCAtSynchronizedStmt>(S)) - return RewriteObjCSynchronizedStmt(StmtTry); - - if (ObjCAtThrowStmt *StmtThrow = dyn_cast<ObjCAtThrowStmt>(S)) - return RewriteObjCThrowStmt(StmtThrow); - - if (ObjCProtocolExpr *ProtocolExp = dyn_cast<ObjCProtocolExpr>(S)) - return RewriteObjCProtocolExpr(ProtocolExp); - - if (ObjCForCollectionStmt *StmtForCollection = - dyn_cast<ObjCForCollectionStmt>(S)) - return RewriteObjCForCollectionStmt(StmtForCollection, OrigStmtEnd); - if (BreakStmt *StmtBreakStmt = - dyn_cast<BreakStmt>(S)) - return RewriteBreakStmt(StmtBreakStmt); - if (ContinueStmt *StmtContinueStmt = - dyn_cast<ContinueStmt>(S)) - return RewriteContinueStmt(StmtContinueStmt); - - if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) || - isa<DoStmt>(S) || isa<ForStmt>(S)) { - assert(!Stmts.empty() && "Statement stack is empty"); - assert ((isa<SwitchStmt>(Stmts.back()) || isa<WhileStmt>(Stmts.back()) || - isa<DoStmt>(Stmts.back()) || isa<ForStmt>(Stmts.back())) - && "Statement stack mismatch"); - Stmts.pop_back(); - } -#if 0 - if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) { - CastExpr *Replacement = new CastExpr(ICE->getType(), ICE->getSubExpr(), SourceLocation()); - // Get the new text. - std::ostringstream Buf; - Replacement->printPretty(Buf); - const std::string &Str = Buf.str(); - - printf("CAST = %s\n", &Str[0]); - InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size()); - delete S; - return Replacement; - } -#endif - // Return this stmt unmodified. - return S; -} - -/// SynthCountByEnumWithState - To print: -/// ((unsigned int (*) -/// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int)) -/// (void *)objc_msgSend)((id)l_collection, -/// sel_registerName( -/// "countByEnumeratingWithState:objects:count:"), -/// &enumState, -/// (id *)items, (unsigned int)16) -/// -void RewriteObjC::SynthCountByEnumWithState(std::string &buf) { - buf += "((unsigned int (*) (id, SEL, struct __objcFastEnumerationState *, " - "id *, unsigned int))(void *)objc_msgSend)"; - buf += "\n\t\t"; - buf += "((id)l_collection,\n\t\t"; - buf += "sel_registerName(\"countByEnumeratingWithState:objects:count:\"),"; - buf += "\n\t\t"; - buf += "&enumState, " - "(id *)items, (unsigned int)16)"; -} - -/// RewriteBreakStmt - Rewrite for a break-stmt inside an ObjC2's foreach -/// statement to exit to its outer synthesized loop. -/// -Stmt *RewriteObjC::RewriteBreakStmt(BreakStmt *S) { - if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back())) - return S; - // replace break with goto __break_label - std::string buf; - - SourceLocation startLoc = S->getLocStart(); - buf = "goto __break_label_"; - buf += utostr(ObjCBcLabelNo.back()); - ReplaceText(startLoc, strlen("break"), buf.c_str(), buf.size()); - - return 0; -} - -/// RewriteContinueStmt - Rewrite for a continue-stmt inside an ObjC2's foreach -/// statement to continue with its inner synthesized loop. -/// -Stmt *RewriteObjC::RewriteContinueStmt(ContinueStmt *S) { - if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back())) - return S; - // replace continue with goto __continue_label - std::string buf; - - SourceLocation startLoc = S->getLocStart(); - buf = "goto __continue_label_"; - buf += utostr(ObjCBcLabelNo.back()); - ReplaceText(startLoc, strlen("continue"), buf.c_str(), buf.size()); - - return 0; -} - -/// RewriteObjCForCollectionStmt - Rewriter for ObjC2's foreach statement. -/// It rewrites: -/// for ( type elem in collection) { stmts; } - -/// Into: -/// { -/// type elem; -/// struct __objcFastEnumerationState enumState = { 0 }; -/// id items[16]; -/// id l_collection = (id)collection; -/// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState -/// objects:items count:16]; -/// if (limit) { -/// unsigned long startMutations = *enumState.mutationsPtr; -/// do { -/// unsigned long counter = 0; -/// do { -/// if (startMutations != *enumState.mutationsPtr) -/// objc_enumerationMutation(l_collection); -/// elem = (type)enumState.itemsPtr[counter++]; -/// stmts; -/// __continue_label: ; -/// } while (counter < limit); -/// } while (limit = [l_collection countByEnumeratingWithState:&enumState -/// objects:items count:16]); -/// elem = nil; -/// __break_label: ; -/// } -/// else -/// elem = nil; -/// } -/// -Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, - SourceLocation OrigEnd) { - assert(!Stmts.empty() && "ObjCForCollectionStmt - Statement stack empty"); - assert(isa<ObjCForCollectionStmt>(Stmts.back()) && - "ObjCForCollectionStmt Statement stack mismatch"); - assert(!ObjCBcLabelNo.empty() && - "ObjCForCollectionStmt - Label No stack empty"); - - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - const char *elementName; - std::string elementTypeAsString; - std::string buf; - buf = "\n{\n\t"; - if (DeclStmt *DS = dyn_cast<DeclStmt>(S->getElement())) { - // type elem; - QualType ElementType = cast<ValueDecl>(DS->getDecl())->getType(); - elementTypeAsString = ElementType.getAsString(); - buf += elementTypeAsString; - buf += " "; - elementName = DS->getDecl()->getName(); - buf += elementName; - buf += ";\n\t"; - } - else { - DeclRefExpr *DR = cast<DeclRefExpr>(S->getElement()); - elementName = DR->getDecl()->getName(); - elementTypeAsString = DR->getDecl()->getType().getAsString(); - } - - // struct __objcFastEnumerationState enumState = { 0 }; - buf += "struct __objcFastEnumerationState enumState = { 0 };\n\t"; - // id items[16]; - buf += "id items[16];\n\t"; - // id l_collection = (id) - buf += "id l_collection = (id)"; - // Find start location of 'collection' the hard way! - const char *startCollectionBuf = startBuf; - startCollectionBuf += 3; // skip 'for' - startCollectionBuf = strchr(startCollectionBuf, '('); - startCollectionBuf++; // skip '(' - // find 'in' and skip it. - while (*startCollectionBuf != ' ' || - *(startCollectionBuf+1) != 'i' || *(startCollectionBuf+2) != 'n' || - (*(startCollectionBuf+3) != ' ' && - *(startCollectionBuf+3) != '[' && *(startCollectionBuf+3) != '(')) - startCollectionBuf++; - startCollectionBuf += 3; - - // Replace: "for (type element in" with string constructed thus far. - ReplaceText(startLoc, startCollectionBuf - startBuf, - buf.c_str(), buf.size()); - // Replace ')' in for '(' type elem in collection ')' with ';' - SourceLocation rightParenLoc = S->getRParenLoc(); - const char *rparenBuf = SM->getCharacterData(rightParenLoc); - SourceLocation lparenLoc = startLoc.getFileLocWithOffset(rparenBuf-startBuf); - buf = ";\n\t"; - - // unsigned long limit = [l_collection countByEnumeratingWithState:&enumState - // objects:items count:16]; - // which is synthesized into: - // unsigned int limit = - // ((unsigned int (*) - // (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int)) - // (void *)objc_msgSend)((id)l_collection, - // sel_registerName( - // "countByEnumeratingWithState:objects:count:"), - // (struct __objcFastEnumerationState *)&state, - // (id *)items, (unsigned int)16); - buf += "unsigned long limit =\n\t\t"; - SynthCountByEnumWithState(buf); - buf += ";\n\t"; - /// if (limit) { - /// unsigned long startMutations = *enumState.mutationsPtr; - /// do { - /// unsigned long counter = 0; - /// do { - /// if (startMutations != *enumState.mutationsPtr) - /// objc_enumerationMutation(l_collection); - /// elem = (type)enumState.itemsPtr[counter++]; - buf += "if (limit) {\n\t"; - buf += "unsigned long startMutations = *enumState.mutationsPtr;\n\t"; - buf += "do {\n\t\t"; - buf += "unsigned long counter = 0;\n\t\t"; - buf += "do {\n\t\t\t"; - buf += "if (startMutations != *enumState.mutationsPtr)\n\t\t\t\t"; - buf += "objc_enumerationMutation(l_collection);\n\t\t\t"; - buf += elementName; - buf += " = ("; - buf += elementTypeAsString; - buf += ")enumState.itemsPtr[counter++];"; - // Replace ')' in for '(' type elem in collection ')' with all of these. - ReplaceText(lparenLoc, 1, buf.c_str(), buf.size()); - - /// __continue_label: ; - /// } while (counter < limit); - /// } while (limit = [l_collection countByEnumeratingWithState:&enumState - /// objects:items count:16]); - /// elem = nil; - /// __break_label: ; - /// } - /// else - /// elem = nil; - /// } - /// - buf = ";\n\t"; - buf += "__continue_label_"; - buf += utostr(ObjCBcLabelNo.back()); - buf += ": ;"; - buf += "\n\t\t"; - buf += "} while (counter < limit);\n\t"; - buf += "} while (limit = "; - SynthCountByEnumWithState(buf); - buf += ");\n\t"; - buf += elementName; - buf += " = nil;\n\t"; - buf += "__break_label_"; - buf += utostr(ObjCBcLabelNo.back()); - buf += ": ;\n\t"; - buf += "}\n\t"; - buf += "else\n\t\t"; - buf += elementName; - buf += " = nil;\n"; - buf += "}\n"; - // Insert all these *after* the statement body. - SourceLocation endBodyLoc = OrigEnd.getFileLocWithOffset(1); - InsertText(endBodyLoc, buf.c_str(), buf.size()); - Stmts.pop_back(); - ObjCBcLabelNo.pop_back(); - return 0; -} - -/// RewriteObjCSynchronizedStmt - -/// This routine rewrites @synchronized(expr) stmt; -/// into: -/// objc_sync_enter(expr); -/// @try stmt @finally { objc_sync_exit(expr); } -/// -Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { - // Get the start location and compute the semi location. - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '@') && "bogus @synchronized location"); - - std::string buf; - buf = "objc_sync_enter"; - ReplaceText(startLoc, 13, buf.c_str(), buf.size()); - SourceLocation endLoc = S->getSynchExpr()->getLocEnd(); - const char *endBuf = SM->getCharacterData(endLoc); - endBuf++; - const char *rparenBuf = strchr(endBuf, ')'); - SourceLocation rparenLoc = startLoc.getFileLocWithOffset(rparenBuf-startBuf); - buf = ");\n"; - // declare a new scope with two variables, _stack and _rethrow. - buf += "/* @try scope begin */ \n{ struct _objc_exception_data {\n"; - buf += "int buf[18/*32-bit i386*/];\n"; - buf += "char *pointers[4];} _stack;\n"; - buf += "id volatile _rethrow = 0;\n"; - buf += "objc_exception_try_enter(&_stack);\n"; - buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n"; - ReplaceText(rparenLoc, 1, buf.c_str(), buf.size()); - startLoc = S->getSynchBody()->getLocEnd(); - startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '}') && "bogus @try block"); - SourceLocation lastCurlyLoc = startLoc; - buf = "}\nelse {\n"; - buf += " _rethrow = objc_exception_extract(&_stack);\n"; - buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; - // FIXME: This must be objc_sync_exit(syncExpr); - buf += " objc_sync_exit();\n"; - buf += " if (_rethrow) objc_exception_throw(_rethrow);\n"; - buf += "}\n"; - buf += "}"; - - ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size()); - return 0; -} - -Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { - // Get the start location and compute the semi location. - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '@') && "bogus @try location"); - - std::string buf; - // declare a new scope with two variables, _stack and _rethrow. - buf = "/* @try scope begin */ { struct _objc_exception_data {\n"; - buf += "int buf[18/*32-bit i386*/];\n"; - buf += "char *pointers[4];} _stack;\n"; - buf += "id volatile _rethrow = 0;\n"; - buf += "objc_exception_try_enter(&_stack);\n"; - buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n"; - - ReplaceText(startLoc, 4, buf.c_str(), buf.size()); - - startLoc = S->getTryBody()->getLocEnd(); - startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '}') && "bogus @try block"); - - SourceLocation lastCurlyLoc = startLoc; - - startLoc = startLoc.getFileLocWithOffset(1); - buf = " /* @catch begin */ else {\n"; - buf += " id _caught = objc_exception_extract(&_stack);\n"; - buf += " objc_exception_try_enter (&_stack);\n"; - buf += " if (_setjmp(_stack.buf))\n"; - buf += " _rethrow = objc_exception_extract(&_stack);\n"; - buf += " else { /* @catch continue */"; - - InsertText(startLoc, buf.c_str(), buf.size()); - - bool sawIdTypedCatch = false; - Stmt *lastCatchBody = 0; - ObjCAtCatchStmt *catchList = S->getCatchStmts(); - while (catchList) { - Stmt *catchStmt = catchList->getCatchParamStmt(); - - if (catchList == S->getCatchStmts()) - buf = "if ("; // we are generating code for the first catch clause - else - buf = "else if ("; - startLoc = catchList->getLocStart(); - startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '@') && "bogus @catch location"); - - const char *lParenLoc = strchr(startBuf, '('); - - if (catchList->hasEllipsis()) { - // Now rewrite the body... - lastCatchBody = catchList->getCatchBody(); - SourceLocation bodyLoc = lastCatchBody->getLocStart(); - const char *bodyBuf = SM->getCharacterData(bodyLoc); - assert(*SM->getCharacterData(catchList->getRParenLoc()) == ')' && - "bogus @catch paren location"); - assert((*bodyBuf == '{') && "bogus @catch body location"); - - buf += "1) { id _tmp = _caught;"; - Rewrite.ReplaceText(startLoc, bodyBuf-startBuf+1, - buf.c_str(), buf.size()); - } else if (DeclStmt *declStmt = dyn_cast<DeclStmt>(catchStmt)) { - QualType t = dyn_cast<ValueDecl>(declStmt->getDecl())->getType(); - if (t == Context->getObjCIdType()) { - buf += "1) { "; - ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size()); - sawIdTypedCatch = true; - } else if (const PointerType *pType = t->getAsPointerType()) { - ObjCInterfaceType *cls; // Should be a pointer to a class. - - cls = dyn_cast<ObjCInterfaceType>(pType->getPointeeType().getTypePtr()); - if (cls) { - buf += "objc_exception_match((struct objc_class *)objc_getClass(\""; - buf += cls->getDecl()->getName(); - buf += "\"), (struct objc_object *)_caught)) { "; - ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size()); - } - } - // Now rewrite the body... - lastCatchBody = catchList->getCatchBody(); - SourceLocation rParenLoc = catchList->getRParenLoc(); - SourceLocation bodyLoc = lastCatchBody->getLocStart(); - const char *bodyBuf = SM->getCharacterData(bodyLoc); - const char *rParenBuf = SM->getCharacterData(rParenLoc); - assert((*rParenBuf == ')') && "bogus @catch paren location"); - assert((*bodyBuf == '{') && "bogus @catch body location"); - - buf = " = _caught;"; - // Here we replace ") {" with "= _caught;" (which initializes and - // declares the @catch parameter). - ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, buf.c_str(), buf.size()); - } else if (!isa<NullStmt>(catchStmt)) { - assert(false && "@catch rewrite bug"); - } - // make sure all the catch bodies get rewritten! - catchList = catchList->getNextCatchStmt(); - } - // Complete the catch list... - if (lastCatchBody) { - SourceLocation bodyLoc = lastCatchBody->getLocEnd(); - assert(*SM->getCharacterData(bodyLoc) == '}' && - "bogus @catch body location"); - bodyLoc = bodyLoc.getFileLocWithOffset(1); - buf = " } } /* @catch end */\n"; - - InsertText(bodyLoc, buf.c_str(), buf.size()); - - // Set lastCurlyLoc - lastCurlyLoc = lastCatchBody->getLocEnd(); - } - if (ObjCAtFinallyStmt *finalStmt = S->getFinallyStmt()) { - startLoc = finalStmt->getLocStart(); - startBuf = SM->getCharacterData(startLoc); - assert((*startBuf == '@') && "bogus @finally start"); - - buf = "/* @finally */"; - ReplaceText(startLoc, 8, buf.c_str(), buf.size()); - - Stmt *body = finalStmt->getFinallyBody(); - SourceLocation startLoc = body->getLocStart(); - SourceLocation endLoc = body->getLocEnd(); - assert(*SM->getCharacterData(startLoc) == '{' && - "bogus @finally body location"); - assert(*SM->getCharacterData(endLoc) == '}' && - "bogus @finally body location"); - - startLoc = startLoc.getFileLocWithOffset(1); - buf = " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; - InsertText(startLoc, buf.c_str(), buf.size()); - endLoc = endLoc.getFileLocWithOffset(-1); - buf = " if (_rethrow) objc_exception_throw(_rethrow);\n"; - InsertText(endLoc, buf.c_str(), buf.size()); - - // Set lastCurlyLoc - lastCurlyLoc = body->getLocEnd(); - } - // Now emit the final closing curly brace... - lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1); - buf = " } /* @try scope end */\n"; - InsertText(lastCurlyLoc, buf.c_str(), buf.size()); - return 0; -} - -Stmt *RewriteObjC::RewriteObjCCatchStmt(ObjCAtCatchStmt *S) { - return 0; -} - -Stmt *RewriteObjC::RewriteObjCFinallyStmt(ObjCAtFinallyStmt *S) { - return 0; -} - -// This can't be done with ReplaceStmt(S, ThrowExpr), since -// the throw expression is typically a message expression that's already -// been rewritten! (which implies the SourceLocation's are invalid). -Stmt *RewriteObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) { - // Get the start location and compute the semi location. - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '@') && "bogus @throw location"); - - std::string buf; - /* void objc_exception_throw(id) __attribute__((noreturn)); */ - if (S->getThrowExpr()) - buf = "objc_exception_throw("; - else // add an implicit argument - buf = "objc_exception_throw(_caught"; - ReplaceText(startLoc, 6, buf.c_str(), buf.size()); - const char *semiBuf = strchr(startBuf, ';'); - assert((*semiBuf == ';') && "@throw: can't find ';'"); - SourceLocation semiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf); - buf = ");"; - ReplaceText(semiLoc, 1, buf.c_str(), buf.size()); - return 0; -} - -Stmt *RewriteObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) { - // Create a new string expression. - QualType StrType = Context->getPointerType(Context->CharTy); - std::string StrEncoding; - Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding, - EncodingRecordTypes); - Expr *Replacement = new StringLiteral(StrEncoding.c_str(), - StrEncoding.length(), false, StrType, - SourceLocation(), SourceLocation()); - ReplaceStmt(Exp, Replacement); - - // Replace this subexpr in the parent. - delete Exp; - return Replacement; -} - -Stmt *RewriteObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) { - assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl"); - // Create a call to sel_registerName("selName"). - llvm::SmallVector<Expr*, 8> SelExprs; - QualType argType = Context->getPointerType(Context->CharTy); - SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(), - Exp->getSelector().getName().size(), - false, argType, SourceLocation(), - SourceLocation())); - CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, - &SelExprs[0], SelExprs.size()); - ReplaceStmt(Exp, SelExp); - delete Exp; - return SelExp; -} - -CallExpr *RewriteObjC::SynthesizeCallToFunctionDecl( - FunctionDecl *FD, Expr **args, unsigned nargs) { - // Get the type, we will need to reference it in a couple spots. - QualType msgSendType = FD->getType(); - - // Create a reference to the objc_msgSend() declaration. - DeclRefExpr *DRE = new DeclRefExpr(FD, msgSendType, SourceLocation()); - - // Now, we cast the reference to a pointer to the objc_msgSend type. - QualType pToFunc = Context->getPointerType(msgSendType); - ImplicitCastExpr *ICE = new ImplicitCastExpr(pToFunc, DRE); - - const FunctionType *FT = msgSendType->getAsFunctionType(); - - return new CallExpr(ICE, args, nargs, FT->getResultType(), SourceLocation()); -} - -static bool scanForProtocolRefs(const char *startBuf, const char *endBuf, - const char *&startRef, const char *&endRef) { - while (startBuf < endBuf) { - if (*startBuf == '<') - startRef = startBuf; // mark the start. - if (*startBuf == '>') { - if (startRef && *startRef == '<') { - endRef = startBuf; // mark the end. - return true; - } - return false; - } - startBuf++; - } - return false; -} - -static void scanToNextArgument(const char *&argRef) { - int angle = 0; - while (*argRef != ')' && (*argRef != ',' || angle > 0)) { - if (*argRef == '<') - angle++; - else if (*argRef == '>') - angle--; - argRef++; - } - assert(angle == 0 && "scanToNextArgument - bad protocol type syntax"); -} - -bool RewriteObjC::needToScanForQualifiers(QualType T) { - - if (T == Context->getObjCIdType()) - return true; - - if (T->isObjCQualifiedIdType()) - return true; - - if (const PointerType *pType = T->getAsPointerType()) { - Type *pointeeType = pType->getPointeeType().getTypePtr(); - if (isa<ObjCQualifiedInterfaceType>(pointeeType)) - return true; // we have "Class <Protocol> *". - } - return false; -} - -void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) { - SourceLocation Loc; - QualType Type; - const FunctionTypeProto *proto = 0; - if (VarDecl *VD = dyn_cast<VarDecl>(Dcl)) { - Loc = VD->getLocation(); - Type = VD->getType(); - } - else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Dcl)) { - Loc = FD->getLocation(); - // Check for ObjC 'id' and class types that have been adorned with protocol - // information (id<p>, C<p>*). The protocol references need to be rewritten! - const FunctionType *funcType = FD->getType()->getAsFunctionType(); - assert(funcType && "missing function type"); - proto = dyn_cast<FunctionTypeProto>(funcType); - if (!proto) - return; - Type = proto->getResultType(); - } - else - return; - - if (needToScanForQualifiers(Type)) { - // Since types are unique, we need to scan the buffer. - - const char *endBuf = SM->getCharacterData(Loc); - const char *startBuf = endBuf; - while (*startBuf != ';' && startBuf != MainFileStart) - startBuf--; // scan backward (from the decl location) for return type. - const char *startRef = 0, *endRef = 0; - if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { - // Get the locations of the startRef, endRef. - SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-endBuf); - SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-endBuf+1); - // Comment out the protocol references. - InsertText(LessLoc, "/*", 2); - InsertText(GreaterLoc, "*/", 2); - } - } - if (!proto) - return; // most likely, was a variable - // Now check arguments. - const char *startBuf = SM->getCharacterData(Loc); - const char *startFuncBuf = startBuf; - for (unsigned i = 0; i < proto->getNumArgs(); i++) { - if (needToScanForQualifiers(proto->getArgType(i))) { - // Since types are unique, we need to scan the buffer. - - const char *endBuf = startBuf; - // scan forward (from the decl location) for argument types. - scanToNextArgument(endBuf); - const char *startRef = 0, *endRef = 0; - if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { - // Get the locations of the startRef, endRef. - SourceLocation LessLoc = - Loc.getFileLocWithOffset(startRef-startFuncBuf); - SourceLocation GreaterLoc = - Loc.getFileLocWithOffset(endRef-startFuncBuf+1); - // Comment out the protocol references. - InsertText(LessLoc, "/*", 2); - InsertText(GreaterLoc, "*/", 2); - } - startBuf = ++endBuf; - } - else { - while (*startBuf != ')' && *startBuf != ',') - startBuf++; // scan forward (from the decl location) for argument types. - startBuf++; - } - } -} - -// SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str); -void RewriteObjC::SynthSelGetUidFunctionDecl() { - IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName"); - llvm::SmallVector<QualType, 16> ArgTys; - ArgTys.push_back(Context->getPointerType( - Context->CharTy.getQualifiedType(QualType::Const))); - QualType getFuncType = Context->getFunctionType(Context->getObjCSelType(), - &ArgTys[0], ArgTys.size(), - false /*isVariadic*/); - SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SelGetUidIdent, getFuncType, - FunctionDecl::Extern, false, 0); -} - -// SynthGetProtocolFunctionDecl - Protocol objc_getProtocol(const char *proto); -void RewriteObjC::SynthGetProtocolFunctionDecl() { - IdentifierInfo *SelGetProtoIdent = &Context->Idents.get("objc_getProtocol"); - llvm::SmallVector<QualType, 16> ArgTys; - ArgTys.push_back(Context->getPointerType( - Context->CharTy.getQualifiedType(QualType::Const))); - QualType getFuncType = Context->getFunctionType(Context->getObjCProtoType(), - &ArgTys[0], ArgTys.size(), - false /*isVariadic*/); - GetProtocolFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SelGetProtoIdent, getFuncType, - FunctionDecl::Extern, false, 0); -} - -void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) { - // declared in <objc/objc.h> - if (strcmp(FD->getName(), "sel_registerName") == 0) { - SelGetUidFunctionDecl = FD; - return; - } - RewriteObjCQualifiedInterfaceTypes(FD); -} - -// SynthSuperContructorFunctionDecl - id objc_super(id obj, id super); -void RewriteObjC::SynthSuperContructorFunctionDecl() { - if (SuperContructorFunctionDecl) - return; - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_super"); - llvm::SmallVector<QualType, 16> ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - ArgTys.push_back(argT); - QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size(), - false); - SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - msgSendIdent, msgSendType, - FunctionDecl::Extern, false, 0); -} - -// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...); -void RewriteObjC::SynthMsgSendFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend"); - llvm::SmallVector<QualType, 16> ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size(), - true /*isVariadic*/); - MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - msgSendIdent, msgSendType, - FunctionDecl::Extern, false, 0); -} - -// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...); -void RewriteObjC::SynthMsgSendSuperFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper"); - llvm::SmallVector<QualType, 16> ArgTys; - RecordDecl *RD = RecordDecl::Create(*Context, Decl::Struct, TUDecl, - SourceLocation(), - &Context->Idents.get("objc_super"), 0); - QualType argT = Context->getPointerType(Context->getTagDeclType(RD)); - assert(!argT.isNull() && "Can't build 'struct objc_super *' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size(), - true /*isVariadic*/); - MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - msgSendIdent, msgSendType, - FunctionDecl::Extern, false, 0); -} - -// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...); -void RewriteObjC::SynthMsgSendStretFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_stret"); - llvm::SmallVector<QualType, 16> ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size(), - true /*isVariadic*/); - MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - msgSendIdent, msgSendType, - FunctionDecl::Extern, false, 0); -} - -// SynthMsgSendSuperStretFunctionDecl - -// id objc_msgSendSuper_stret(struct objc_super *, SEL op, ...); -void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() { - IdentifierInfo *msgSendIdent = - &Context->Idents.get("objc_msgSendSuper_stret"); - llvm::SmallVector<QualType, 16> ArgTys; - RecordDecl *RD = RecordDecl::Create(*Context, Decl::Struct, TUDecl, - SourceLocation(), - &Context->Idents.get("objc_super"), 0); - QualType argT = Context->getPointerType(Context->getTagDeclType(RD)); - assert(!argT.isNull() && "Can't build 'struct objc_super *' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size(), - true /*isVariadic*/); - MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - msgSendIdent, msgSendType, - FunctionDecl::Extern, false, 0); -} - -// SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...); -void RewriteObjC::SynthMsgSendFpretFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_fpret"); - llvm::SmallVector<QualType, 16> ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = Context->getFunctionType(Context->DoubleTy, - &ArgTys[0], ArgTys.size(), - true /*isVariadic*/); - MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - msgSendIdent, msgSendType, - FunctionDecl::Extern, false, 0); -} - -// SynthGetClassFunctionDecl - id objc_getClass(const char *name); -void RewriteObjC::SynthGetClassFunctionDecl() { - IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass"); - llvm::SmallVector<QualType, 16> ArgTys; - ArgTys.push_back(Context->getPointerType( - Context->CharTy.getQualifiedType(QualType::Const))); - QualType getClassType = Context->getFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size(), - false /*isVariadic*/); - GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - getClassIdent, getClassType, - FunctionDecl::Extern, false, 0); -} - -// SynthGetMetaClassFunctionDecl - id objc_getClass(const char *name); -void RewriteObjC::SynthGetMetaClassFunctionDecl() { - IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass"); - llvm::SmallVector<QualType, 16> ArgTys; - ArgTys.push_back(Context->getPointerType( - Context->CharTy.getQualifiedType(QualType::Const))); - QualType getClassType = Context->getFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size(), - false /*isVariadic*/); - GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - getClassIdent, getClassType, - FunctionDecl::Extern, false, 0); -} - -Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { - QualType strType = getConstantStringStructType(); - - std::string S = "__NSConstantStringImpl_"; - S += utostr(NumObjCStringLiterals++); - - Preamble += "static __NSConstantStringImpl " + S; - Preamble += " __attribute__ ((section (\"__DATA, __cfstring\"))) = {__CFConstantStringClassReference,"; - Preamble += "0x000007c8,"; // utf8_str - // The pretty printer for StringLiteral handles escape characters properly. - std::ostringstream prettyBuf; - Exp->getString()->printPretty(prettyBuf); - Preamble += prettyBuf.str(); - Preamble += ","; - // The minus 2 removes the begin/end double quotes. - Preamble += utostr(prettyBuf.str().size()-2) + "};\n"; - - VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), - &Context->Idents.get(S.c_str()), strType, - VarDecl::Static, NULL); - DeclRefExpr *DRE = new DeclRefExpr(NewVD, strType, SourceLocation()); - Expr *Unop = new UnaryOperator(DRE, UnaryOperator::AddrOf, - Context->getPointerType(DRE->getType()), - SourceLocation()); - // cast to NSConstantString * - CastExpr *cast = new CastExpr(Exp->getType(), Unop, SourceLocation()); - ReplaceStmt(Exp, cast); - delete Exp; - return cast; -} - -ObjCInterfaceDecl *RewriteObjC::isSuperReceiver(Expr *recExpr) { - // check if we are sending a message to 'super' - if (!CurMethodDecl || !CurMethodDecl->isInstance()) return 0; - - CastExpr *CE = dyn_cast<CastExpr>(recExpr); - if (!CE) return 0; - - DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr()); - if (!DRE) return 0; - - ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl()); - if (!PVD) return 0; - - if (strcmp(PVD->getName(), "self") != 0) - return 0; - - // is this id<P1..> type? - if (CE->getType()->isObjCQualifiedIdType()) - return 0; - const PointerType *PT = CE->getType()->getAsPointerType(); - if (!PT) return 0; - - ObjCInterfaceType *IT = dyn_cast<ObjCInterfaceType>(PT->getPointeeType()); - if (!IT) return 0; - - if (IT->getDecl() != CurMethodDecl->getClassInterface()->getSuperClass()) - return 0; - - return IT->getDecl(); -} - -// struct objc_super { struct objc_object *receiver; struct objc_class *super; }; -QualType RewriteObjC::getSuperStructType() { - if (!SuperStructDecl) { - SuperStructDecl = RecordDecl::Create(*Context, Decl::Struct, TUDecl, - SourceLocation(), - &Context->Idents.get("objc_super"), 0); - QualType FieldTypes[2]; - - // struct objc_object *receiver; - FieldTypes[0] = Context->getObjCIdType(); - // struct objc_class *super; - FieldTypes[1] = Context->getObjCClassType(); - // Create fields - FieldDecl *FieldDecls[2]; - - for (unsigned i = 0; i < 2; ++i) - FieldDecls[i] = FieldDecl::Create(*Context, SourceLocation(), 0, - FieldTypes[i]); - - SuperStructDecl->defineBody(FieldDecls, 4); - } - return Context->getTagDeclType(SuperStructDecl); -} - -QualType RewriteObjC::getConstantStringStructType() { - if (!ConstantStringDecl) { - ConstantStringDecl = RecordDecl::Create(*Context, Decl::Struct, TUDecl, - SourceLocation(), - &Context->Idents.get("__NSConstantStringImpl"), 0); - QualType FieldTypes[4]; - - // struct objc_object *receiver; - FieldTypes[0] = Context->getObjCIdType(); - // int flags; - FieldTypes[1] = Context->IntTy; - // char *str; - FieldTypes[2] = Context->getPointerType(Context->CharTy); - // long length; - FieldTypes[3] = Context->LongTy; - // Create fields - FieldDecl *FieldDecls[4]; - - for (unsigned i = 0; i < 4; ++i) - FieldDecls[i] = FieldDecl::Create(*Context, SourceLocation(), 0, - FieldTypes[i]); - - ConstantStringDecl->defineBody(FieldDecls, 4); - } - return Context->getTagDeclType(ConstantStringDecl); -} - -Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { - if (!SelGetUidFunctionDecl) - SynthSelGetUidFunctionDecl(); - if (!MsgSendFunctionDecl) - SynthMsgSendFunctionDecl(); - if (!MsgSendSuperFunctionDecl) - SynthMsgSendSuperFunctionDecl(); - if (!MsgSendStretFunctionDecl) - SynthMsgSendStretFunctionDecl(); - if (!MsgSendSuperStretFunctionDecl) - SynthMsgSendSuperStretFunctionDecl(); - if (!MsgSendFpretFunctionDecl) - SynthMsgSendFpretFunctionDecl(); - if (!GetClassFunctionDecl) - SynthGetClassFunctionDecl(); - if (!GetMetaClassFunctionDecl) - SynthGetMetaClassFunctionDecl(); - - // default to objc_msgSend(). - FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; - // May need to use objc_msgSend_stret() as well. - FunctionDecl *MsgSendStretFlavor = 0; - if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) { - QualType resultType = mDecl->getResultType(); - if (resultType.getCanonicalType()->isStructureType() - || resultType.getCanonicalType()->isUnionType()) - MsgSendStretFlavor = MsgSendStretFunctionDecl; - else if (resultType.getCanonicalType()->isRealFloatingType()) - MsgSendFlavor = MsgSendFpretFunctionDecl; - } - - // Synthesize a call to objc_msgSend(). - llvm::SmallVector<Expr*, 8> MsgExprs; - IdentifierInfo *clsName = Exp->getClassName(); - - // Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend(). - if (clsName) { // class message. - if (!strcmp(clsName->getName(), "super")) { - MsgSendFlavor = MsgSendSuperFunctionDecl; - if (MsgSendStretFlavor) - MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; - assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); - - ObjCInterfaceDecl *SuperDecl = - CurMethodDecl->getClassInterface()->getSuperClass(); - - llvm::SmallVector<Expr*, 4> InitExprs; - - // set the receiver to self, the first argument to all methods. - InitExprs.push_back(new DeclRefExpr(CurMethodDecl->getSelfDecl(), - Context->getObjCIdType(), - SourceLocation())); - llvm::SmallVector<Expr*, 8> ClsExprs; - QualType argType = Context->getPointerType(Context->CharTy); - ClsExprs.push_back(new StringLiteral(SuperDecl->getIdentifier()->getName(), - SuperDecl->getIdentifier()->getLength(), - false, argType, SourceLocation(), - SourceLocation())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size()); - // To turn off a warning, type-cast to 'id' - InitExprs.push_back( - new CastExpr(Context->getObjCIdType(), - Cls, SourceLocation())); // set 'super class', using objc_getClass(). - // struct objc_super - QualType superType = getSuperStructType(); - Expr *SuperRep; - - if (LangOpts.Microsoft) { - SynthSuperContructorFunctionDecl(); - // Simulate a contructor call... - DeclRefExpr *DRE = new DeclRefExpr(SuperContructorFunctionDecl, - superType, SourceLocation()); - SuperRep = new CallExpr(DRE, &InitExprs[0], InitExprs.size(), - superType, SourceLocation()); - } else { - // (struct objc_super) { <exprs from above> } - InitListExpr *ILE = new InitListExpr(SourceLocation(), - &InitExprs[0], InitExprs.size(), - SourceLocation()); - SuperRep = new CompoundLiteralExpr(SourceLocation(), superType, ILE, false); - } - // struct objc_super * - Expr *Unop = new UnaryOperator(SuperRep, UnaryOperator::AddrOf, - Context->getPointerType(SuperRep->getType()), - SourceLocation()); - MsgExprs.push_back(Unop); - } else { - llvm::SmallVector<Expr*, 8> ClsExprs; - QualType argType = Context->getPointerType(Context->CharTy); - ClsExprs.push_back(new StringLiteral(clsName->getName(), - clsName->getLength(), - false, argType, SourceLocation(), - SourceLocation())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size()); - MsgExprs.push_back(Cls); - } - } else { // instance message. - Expr *recExpr = Exp->getReceiver(); - - if (ObjCInterfaceDecl *SuperDecl = isSuperReceiver(recExpr)) { - MsgSendFlavor = MsgSendSuperFunctionDecl; - if (MsgSendStretFlavor) - MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; - assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); - - llvm::SmallVector<Expr*, 4> InitExprs; - - InitExprs.push_back( - new CastExpr(Context->getObjCIdType(), - recExpr, SourceLocation())); // set the 'receiver'. - - llvm::SmallVector<Expr*, 8> ClsExprs; - QualType argType = Context->getPointerType(Context->CharTy); - ClsExprs.push_back(new StringLiteral(SuperDecl->getIdentifier()->getName(), - SuperDecl->getIdentifier()->getLength(), - false, argType, SourceLocation(), - SourceLocation())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size()); - // To turn off a warning, type-cast to 'id' - InitExprs.push_back( - new CastExpr(Context->getObjCIdType(), - Cls, SourceLocation())); // set 'super class', using objc_getClass(). - // struct objc_super - QualType superType = getSuperStructType(); - Expr *SuperRep; - - if (LangOpts.Microsoft) { - SynthSuperContructorFunctionDecl(); - // Simulate a contructor call... - DeclRefExpr *DRE = new DeclRefExpr(SuperContructorFunctionDecl, - superType, SourceLocation()); - SuperRep = new CallExpr(DRE, &InitExprs[0], InitExprs.size(), - superType, SourceLocation()); - } else { - // (struct objc_super) { <exprs from above> } - InitListExpr *ILE = new InitListExpr(SourceLocation(), - &InitExprs[0], InitExprs.size(), - SourceLocation()); - SuperRep = new CompoundLiteralExpr(SourceLocation(), superType, ILE, false); - } - // struct objc_super * - Expr *Unop = new UnaryOperator(SuperRep, UnaryOperator::AddrOf, - Context->getPointerType(SuperRep->getType()), - SourceLocation()); - MsgExprs.push_back(Unop); - } else { - // Remove all type-casts because it may contain objc-style types; e.g. - // Foo<Proto> *. - while (CastExpr *CE = dyn_cast<CastExpr>(recExpr)) - recExpr = CE->getSubExpr(); - recExpr = new CastExpr(Context->getObjCIdType(), recExpr, SourceLocation()); - MsgExprs.push_back(recExpr); - } - } - // Create a call to sel_registerName("selName"), it will be the 2nd argument. - llvm::SmallVector<Expr*, 8> SelExprs; - QualType argType = Context->getPointerType(Context->CharTy); - SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(), - Exp->getSelector().getName().size(), - false, argType, SourceLocation(), - SourceLocation())); - CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, - &SelExprs[0], SelExprs.size()); - MsgExprs.push_back(SelExp); - - // Now push any user supplied arguments. - for (unsigned i = 0; i < Exp->getNumArgs(); i++) { - Expr *userExpr = Exp->getArg(i); - // Make all implicit casts explicit...ICE comes in handy:-) - if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) { - // Reuse the ICE type, it is exactly what the doctor ordered. - userExpr = new CastExpr(ICE->getType()->isObjCQualifiedIdType() - ? Context->getObjCIdType() - : ICE->getType(), userExpr, SourceLocation()); - } - // Make id<P...> cast into an 'id' cast. - else if (CastExpr *CE = dyn_cast<CastExpr>(userExpr)) { - if (CE->getType()->isObjCQualifiedIdType()) { - while ((CE = dyn_cast<CastExpr>(userExpr))) - userExpr = CE->getSubExpr(); - userExpr = new CastExpr(Context->getObjCIdType(), - userExpr, SourceLocation()); - } - } - MsgExprs.push_back(userExpr); - // We've transferred the ownership to MsgExprs. Null out the argument in - // the original expression, since we will delete it below. - Exp->setArg(i, 0); - } - // Generate the funky cast. - CastExpr *cast; - llvm::SmallVector<QualType, 8> ArgTypes; - QualType returnType; - - // Push 'id' and 'SEL', the 2 implicit arguments. - if (MsgSendFlavor == MsgSendSuperFunctionDecl) - ArgTypes.push_back(Context->getPointerType(getSuperStructType())); - else - ArgTypes.push_back(Context->getObjCIdType()); - ArgTypes.push_back(Context->getObjCSelType()); - if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) { - // Push any user argument types. - for (unsigned i = 0; i < mDecl->getNumParams(); i++) { - QualType t = mDecl->getParamDecl(i)->getType()->isObjCQualifiedIdType() - ? Context->getObjCIdType() - : mDecl->getParamDecl(i)->getType(); - ArgTypes.push_back(t); - } - returnType = mDecl->getResultType()->isObjCQualifiedIdType() - ? Context->getObjCIdType() : mDecl->getResultType(); - } else { - returnType = Context->getObjCIdType(); - } - // Get the type, we will need to reference it in a couple spots. - QualType msgSendType = MsgSendFlavor->getType(); - - // Create a reference to the objc_msgSend() declaration. - DeclRefExpr *DRE = new DeclRefExpr(MsgSendFlavor, msgSendType, - SourceLocation()); - - // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid). - // If we don't do this cast, we get the following bizarre warning/note: - // xx.m:13: warning: function called through a non-compatible type - // xx.m:13: note: if this code is reached, the program will abort - cast = new CastExpr(Context->getPointerType(Context->VoidTy), DRE, - SourceLocation()); - - // Now do the "normal" pointer to function cast. - QualType castType = Context->getFunctionType(returnType, - &ArgTypes[0], ArgTypes.size(), - // If we don't have a method decl, force a variadic cast. - Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : true); - castType = Context->getPointerType(castType); - cast = new CastExpr(castType, cast, SourceLocation()); - - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new ParenExpr(SourceLocation(), SourceLocation(), cast); - - const FunctionType *FT = msgSendType->getAsFunctionType(); - CallExpr *CE = new CallExpr(PE, &MsgExprs[0], MsgExprs.size(), - FT->getResultType(), SourceLocation()); - Stmt *ReplacingStmt = CE; - if (MsgSendStretFlavor) { - // We have the method which returns a struct/union. Must also generate - // call to objc_msgSend_stret and hang both varieties on a conditional - // expression which dictate which one to envoke depending on size of - // method's return type. - - // Create a reference to the objc_msgSend_stret() declaration. - DeclRefExpr *STDRE = new DeclRefExpr(MsgSendStretFlavor, msgSendType, - SourceLocation()); - // Need to cast objc_msgSend_stret to "void *" (see above comment). - cast = new CastExpr(Context->getPointerType(Context->VoidTy), STDRE, - SourceLocation()); - // Now do the "normal" pointer to function cast. - castType = Context->getFunctionType(returnType, - &ArgTypes[0], ArgTypes.size(), - Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false); - castType = Context->getPointerType(castType); - cast = new CastExpr(castType, cast, SourceLocation()); - - // Don't forget the parens to enforce the proper binding. - PE = new ParenExpr(SourceLocation(), SourceLocation(), cast); - - FT = msgSendType->getAsFunctionType(); - CallExpr *STCE = new CallExpr(PE, &MsgExprs[0], MsgExprs.size(), - FT->getResultType(), SourceLocation()); - - // Build sizeof(returnType) - SizeOfAlignOfTypeExpr *sizeofExpr = new SizeOfAlignOfTypeExpr(true, - returnType, Context->getSizeType(), - SourceLocation(), SourceLocation()); - // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) - // FIXME: Value of 8 is base on ppc32/x86 ABI for the most common cases. - // For X86 it is more complicated and some kind of target specific routine - // is needed to decide what to do. - unsigned IntSize = - static_cast<unsigned>(Context->getTypeSize(Context->IntTy)); - IntegerLiteral *limit = new IntegerLiteral(llvm::APInt(IntSize, 8), - Context->IntTy, - SourceLocation()); - BinaryOperator *lessThanExpr = new BinaryOperator(sizeofExpr, limit, - BinaryOperator::LE, - Context->IntTy, - SourceLocation()); - // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) - ConditionalOperator *CondExpr = - new ConditionalOperator(lessThanExpr, CE, STCE, returnType); - ReplacingStmt = new ParenExpr(SourceLocation(), SourceLocation(), CondExpr); - } - return ReplacingStmt; -} - -Stmt *RewriteObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) { - Stmt *ReplacingStmt = SynthMessageExpr(Exp); - // Now do the actual rewrite. - ReplaceStmt(Exp, ReplacingStmt); - - delete Exp; - return ReplacingStmt; -} - -/// RewriteObjCProtocolExpr - Rewrite a protocol expression into -/// call to objc_getProtocol("proto-name"). -Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) { - if (!GetProtocolFunctionDecl) - SynthGetProtocolFunctionDecl(); - // Create a call to objc_getProtocol("ProtocolName"). - llvm::SmallVector<Expr*, 8> ProtoExprs; - QualType argType = Context->getPointerType(Context->CharTy); - ProtoExprs.push_back(new StringLiteral(Exp->getProtocol()->getName(), - strlen(Exp->getProtocol()->getName()), - false, argType, SourceLocation(), - SourceLocation())); - CallExpr *ProtoExp = SynthesizeCallToFunctionDecl(GetProtocolFunctionDecl, - &ProtoExprs[0], - ProtoExprs.size()); - ReplaceStmt(Exp, ProtoExp); - delete Exp; - return ProtoExp; - -} - -/// SynthesizeObjCInternalStruct - Rewrite one internal struct corresponding to -/// an objective-c class with ivars. -void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, - std::string &Result) { - assert(CDecl && "Class missing in SynthesizeObjCInternalStruct"); - assert(CDecl->getName() && "Name missing in SynthesizeObjCInternalStruct"); - // Do not synthesize more than once. - if (ObjCSynthesizedStructs.count(CDecl)) - return; - ObjCInterfaceDecl *RCDecl = CDecl->getSuperClass(); - int NumIvars = CDecl->ivar_size(); - SourceLocation LocStart = CDecl->getLocStart(); - SourceLocation LocEnd = CDecl->getLocEnd(); - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - // If no ivars and no root or if its root, directly or indirectly, - // have no ivars (thus not synthesized) then no need to synthesize this class. - if ((CDecl->isForwardDecl() || NumIvars == 0) && - (!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) { - endBuf += Lexer::MeasureTokenLength(LocEnd, *SM); - ReplaceText(LocStart, endBuf-startBuf, Result.c_str(), Result.size()); - return; - } - - // FIXME: This has potential of causing problem. If - // SynthesizeObjCInternalStruct is ever called recursively. - Result += "\nstruct "; - Result += CDecl->getName(); - if (LangOpts.Microsoft) - Result += "_IMPL"; - - if (NumIvars > 0) { - const char *cursor = strchr(startBuf, '{'); - assert((cursor && endBuf) - && "SynthesizeObjCInternalStruct - malformed @interface"); - - // rewrite the original header *without* disturbing the '{' - ReplaceText(LocStart, cursor-startBuf-1, Result.c_str(), Result.size()); - if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) { - Result = "\n struct "; - Result += RCDecl->getName(); - Result += "_IMPL "; - Result += RCDecl->getName(); - Result += "_IVARS;\n"; - - // insert the super class structure definition. - SourceLocation OnePastCurly = - LocStart.getFileLocWithOffset(cursor-startBuf+1); - InsertText(OnePastCurly, Result.c_str(), Result.size()); - } - cursor++; // past '{' - - // Now comment out any visibility specifiers. - while (cursor < endBuf) { - if (*cursor == '@') { - SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf); - // Skip whitespace. - for (++cursor; cursor[0] == ' ' || cursor[0] == '\t'; ++cursor) - /*scan*/; - - // FIXME: presence of @public, etc. inside comment results in - // this transformation as well, which is still correct c-code. - if (!strncmp(cursor, "public", strlen("public")) || - !strncmp(cursor, "private", strlen("private")) || - !strncmp(cursor, "package", strlen("package")) || - !strncmp(cursor, "protected", strlen("protected"))) - InsertText(atLoc, "// ", 3); - } - // FIXME: If there are cases where '<' is used in ivar declaration part - // of user code, then scan the ivar list and use needToScanForQualifiers - // for type checking. - else if (*cursor == '<') { - SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf); - InsertText(atLoc, "/* ", 3); - cursor = strchr(cursor, '>'); - cursor++; - atLoc = LocStart.getFileLocWithOffset(cursor-startBuf); - InsertText(atLoc, " */", 3); - } - cursor++; - } - // Don't forget to add a ';'!! - InsertText(LocEnd.getFileLocWithOffset(1), ";", 1); - } else { // we don't have any instance variables - insert super struct. - endBuf += Lexer::MeasureTokenLength(LocEnd, *SM); - Result += " {\n struct "; - Result += RCDecl->getName(); - Result += "_IMPL "; - Result += RCDecl->getName(); - Result += "_IVARS;\n};\n"; - ReplaceText(LocStart, endBuf-startBuf, Result.c_str(), Result.size()); - } - // Mark this struct as having been generated. - if (!ObjCSynthesizedStructs.insert(CDecl)) - assert(false && "struct already synthesize- SynthesizeObjCInternalStruct"); -} - -// RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or -/// class methods. -void RewriteObjC::RewriteObjCMethodsMetaData(instmeth_iterator MethodBegin, - instmeth_iterator MethodEnd, - bool IsInstanceMethod, - const char *prefix, - const char *ClassName, - std::string &Result) { - if (MethodBegin == MethodEnd) return; - - static bool objc_impl_method = false; - if (!objc_impl_method) { - /* struct _objc_method { - SEL _cmd; - char *method_types; - void *_imp; - } - */ - Result += "\nstruct _objc_method {\n"; - Result += "\tSEL _cmd;\n"; - Result += "\tchar *method_types;\n"; - Result += "\tvoid *_imp;\n"; - Result += "};\n"; - - objc_impl_method = true; - } - - // Build _objc_method_list for class's methods if needed - - /* struct { - struct _objc_method_list *next_method; - int method_count; - struct _objc_method method_list[]; - } - */ - Result += "\nstatic struct {\n"; - Result += "\tstruct _objc_method_list *next_method;\n"; - Result += "\tint method_count;\n"; - Result += "\tstruct _objc_method method_list["; - Result += utostr(MethodEnd-MethodBegin); - Result += "];\n} _OBJC_"; - Result += prefix; - Result += IsInstanceMethod ? "INSTANCE" : "CLASS"; - Result += "_METHODS_"; - Result += ClassName; - Result += " __attribute__ ((used, section (\"__OBJC, __"; - Result += IsInstanceMethod ? "inst" : "cls"; - Result += "_meth\")))= "; - Result += "{\n\t0, " + utostr(MethodEnd-MethodBegin) + "\n"; - - Result += "\t,{{(SEL)\""; - Result += (*MethodBegin)->getSelector().getName().c_str(); - std::string MethodTypeString; - Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString); - Result += "\", \""; - Result += MethodTypeString; - Result += "\", (void *)"; - Result += MethodInternalNames[*MethodBegin]; - Result += "}\n"; - for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) { - Result += "\t ,{(SEL)\""; - Result += (*MethodBegin)->getSelector().getName().c_str(); - std::string MethodTypeString; - Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString); - Result += "\", \""; - Result += MethodTypeString; - Result += "\", (void *)"; - Result += MethodInternalNames[*MethodBegin]; - Result += "}\n"; - } - Result += "\t }\n};\n"; -} - -/// RewriteObjCProtocolsMetaData - Rewrite protocols meta-data. -void RewriteObjC::RewriteObjCProtocolsMetaData(ObjCProtocolDecl **Protocols, - int NumProtocols, - const char *prefix, - const char *ClassName, - std::string &Result) { - static bool objc_protocol_methods = false; - if (NumProtocols > 0) { - for (int i = 0; i < NumProtocols; i++) { - ObjCProtocolDecl *PDecl = Protocols[i]; - // Output struct protocol_methods holder of method selector and type. - if (!objc_protocol_methods && !PDecl->isForwardDecl()) { - /* struct protocol_methods { - SEL _cmd; - char *method_types; - } - */ - Result += "\nstruct protocol_methods {\n"; - Result += "\tSEL _cmd;\n"; - Result += "\tchar *method_types;\n"; - Result += "};\n"; - - objc_protocol_methods = true; - } - // Do not synthesize the protocol more than once. - if (ObjCSynthesizedProtocols.count(PDecl)) - continue; - - if (PDecl->instmeth_begin() != PDecl->instmeth_end()) { - unsigned NumMethods = PDecl->getNumInstanceMethods(); - /* struct _objc_protocol_method_list { - int protocol_method_count; - struct protocol_methods protocols[]; - } - */ - Result += "\nstatic struct {\n"; - Result += "\tint protocol_method_count;\n"; - Result += "\tstruct protocol_methods protocols["; - Result += utostr(NumMethods); - Result += "];\n} _OBJC_PROTOCOL_INSTANCE_METHODS_"; - Result += PDecl->getName(); - Result += " __attribute__ ((used, section (\"__OBJC, __cat_inst_meth\")))= " - "{\n\t" + utostr(NumMethods) + "\n"; - - // Output instance methods declared in this protocol. - for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(), - E = PDecl->instmeth_end(); I != E; ++I) { - if (I == PDecl->instmeth_begin()) - Result += "\t ,{{(SEL)\""; - else - Result += "\t ,{(SEL)\""; - Result += (*I)->getSelector().getName().c_str(); - std::string MethodTypeString; - Context->getObjCEncodingForMethodDecl((*I), MethodTypeString); - Result += "\", \""; - Result += MethodTypeString; - Result += "\"}\n"; - } - Result += "\t }\n};\n"; - } - - // Output class methods declared in this protocol. - int NumMethods = PDecl->getNumClassMethods(); - if (NumMethods > 0) { - /* struct _objc_protocol_method_list { - int protocol_method_count; - struct protocol_methods protocols[]; - } - */ - Result += "\nstatic struct {\n"; - Result += "\tint protocol_method_count;\n"; - Result += "\tstruct protocol_methods protocols["; - Result += utostr(NumMethods); - Result += "];\n} _OBJC_PROTOCOL_CLASS_METHODS_"; - Result += PDecl->getName(); - Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= " - "{\n\t"; - Result += utostr(NumMethods); - Result += "\n"; - - // Output instance methods declared in this protocol. - for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(), - E = PDecl->classmeth_end(); I != E; ++I) { - if (I == PDecl->classmeth_begin()) - Result += "\t ,{{(SEL)\""; - else - Result += "\t ,{(SEL)\""; - Result += (*I)->getSelector().getName().c_str(); - std::string MethodTypeString; - Context->getObjCEncodingForMethodDecl((*I), MethodTypeString); - Result += "\", \""; - Result += MethodTypeString; - Result += "\"}\n"; - } - Result += "\t }\n};\n"; - } - - // Output: - /* struct _objc_protocol { - // Objective-C 1.0 extensions - struct _objc_protocol_extension *isa; - char *protocol_name; - struct _objc_protocol **protocol_list; - struct _objc_protocol_method_list *instance_methods; - struct _objc_protocol_method_list *class_methods; - }; - */ - static bool objc_protocol = false; - if (!objc_protocol) { - Result += "\nstruct _objc_protocol {\n"; - Result += "\tstruct _objc_protocol_extension *isa;\n"; - Result += "\tchar *protocol_name;\n"; - Result += "\tstruct _objc_protocol **protocol_list;\n"; - Result += "\tstruct _objc_protocol_method_list *instance_methods;\n"; - Result += "\tstruct _objc_protocol_method_list *class_methods;\n"; - Result += "};\n"; - - objc_protocol = true; - } - - Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_"; - Result += PDecl->getName(); - Result += " __attribute__ ((used, section (\"__OBJC, __protocol\")))= " - "{\n\t0, \""; - Result += PDecl->getName(); - Result += "\", 0, "; - if (PDecl->instmeth_begin() != PDecl->instmeth_end()) { - Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_INSTANCE_METHODS_"; - Result += PDecl->getName(); - Result += ", "; - } - else - Result += "0, "; - if (PDecl->getNumClassMethods() > 0) { - Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_CLASS_METHODS_"; - Result += PDecl->getName(); - Result += "\n"; - } - else - Result += "0\n"; - Result += "};\n"; - - // Mark this protocol as having been generated. - if (!ObjCSynthesizedProtocols.insert(PDecl)) - assert(false && "protocol already synthesized"); - } - // Output the top lovel protocol meta-data for the class. - /* struct _objc_protocol_list { - struct _objc_protocol_list *next; - int protocol_count; - struct _objc_protocol *class_protocols[]; - } - */ - Result += "\nstatic struct {\n"; - Result += "\tstruct _objc_protocol_list *next;\n"; - Result += "\tint protocol_count;\n"; - Result += "\tstruct _objc_protocol *class_protocols["; - Result += utostr(NumProtocols); - Result += "];\n} _OBJC_"; - Result += prefix; - Result += "_PROTOCOLS_"; - Result += ClassName; - Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= " - "{\n\t0, "; - Result += utostr(NumProtocols); - Result += "\n"; - - Result += "\t,{&_OBJC_PROTOCOL_"; - Result += Protocols[0]->getName(); - Result += " \n"; - - for (int i = 1; i < NumProtocols; i++) { - ObjCProtocolDecl *PDecl = Protocols[i]; - Result += "\t ,&_OBJC_PROTOCOL_"; - Result += PDecl->getName(); - Result += "\n"; - } - Result += "\t }\n};\n"; - } -} - -/// RewriteObjCCategoryImplDecl - Rewrite metadata for each category -/// implementation. -void RewriteObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl, - std::string &Result) { - ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface(); - // Find category declaration for this implementation. - ObjCCategoryDecl *CDecl; - for (CDecl = ClassDecl->getCategoryList(); CDecl; - CDecl = CDecl->getNextClassCategory()) - if (CDecl->getIdentifier() == IDecl->getIdentifier()) - break; - - std::string FullCategoryName = ClassDecl->getName(); - FullCategoryName += '_'; - FullCategoryName += IDecl->getName(); - - // Build _objc_method_list for class's instance methods if needed - RewriteObjCMethodsMetaData(IDecl->instmeth_begin(), IDecl->instmeth_end(), - true, "CATEGORY_", FullCategoryName.c_str(), - Result); - - // Build _objc_method_list for class's class methods if needed - RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(), - false, "CATEGORY_", FullCategoryName.c_str(), - Result); - - // Protocols referenced in class declaration? - // Null CDecl is case of a category implementation with no category interface - if (CDecl) - RewriteObjCProtocolsMetaData(CDecl->getReferencedProtocols(), - CDecl->getNumReferencedProtocols(), - "CATEGORY", - FullCategoryName.c_str(), Result); - - /* struct _objc_category { - char *category_name; - char *class_name; - struct _objc_method_list *instance_methods; - struct _objc_method_list *class_methods; - struct _objc_protocol_list *protocols; - // Objective-C 1.0 extensions - uint32_t size; // sizeof (struct _objc_category) - struct _objc_property_list *instance_properties; // category's own - // @property decl. - }; - */ - - static bool objc_category = false; - if (!objc_category) { - Result += "\nstruct _objc_category {\n"; - Result += "\tchar *category_name;\n"; - Result += "\tchar *class_name;\n"; - Result += "\tstruct _objc_method_list *instance_methods;\n"; - Result += "\tstruct _objc_method_list *class_methods;\n"; - Result += "\tstruct _objc_protocol_list *protocols;\n"; - Result += "\tunsigned int size;\n"; - Result += "\tstruct _objc_property_list *instance_properties;\n"; - Result += "};\n"; - objc_category = true; - } - Result += "\nstatic struct _objc_category _OBJC_CATEGORY_"; - Result += FullCategoryName; - Result += " __attribute__ ((used, section (\"__OBJC, __category\")))= {\n\t\""; - Result += IDecl->getName(); - Result += "\"\n\t, \""; - Result += ClassDecl->getName(); - Result += "\"\n"; - - if (IDecl->getNumInstanceMethods() > 0) { - Result += "\t, (struct _objc_method_list *)" - "&_OBJC_CATEGORY_INSTANCE_METHODS_"; - Result += FullCategoryName; - Result += "\n"; - } - else - Result += "\t, 0\n"; - if (IDecl->getNumClassMethods() > 0) { - Result += "\t, (struct _objc_method_list *)" - "&_OBJC_CATEGORY_CLASS_METHODS_"; - Result += FullCategoryName; - Result += "\n"; - } - else - Result += "\t, 0\n"; - - if (CDecl && CDecl->getNumReferencedProtocols() > 0) { - Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_"; - Result += FullCategoryName; - Result += "\n"; - } - else - Result += "\t, 0\n"; - Result += "\t, sizeof(struct _objc_category), 0\n};\n"; -} - -/// SynthesizeIvarOffsetComputation - This rutine synthesizes computation of -/// ivar offset. -void RewriteObjC::SynthesizeIvarOffsetComputation(ObjCImplementationDecl *IDecl, - ObjCIvarDecl *ivar, - std::string &Result) { - Result += "__OFFSETOFIVAR__(struct "; - Result += IDecl->getName(); - if (LangOpts.Microsoft) - Result += "_IMPL"; - Result += ", "; - Result += ivar->getName(); - Result += ")"; -} - -//===----------------------------------------------------------------------===// -// Meta Data Emission -//===----------------------------------------------------------------------===// - -void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, - std::string &Result) { - ObjCInterfaceDecl *CDecl = IDecl->getClassInterface(); - - // Explictly declared @interface's are already synthesized. - if (CDecl->ImplicitInterfaceDecl()) { - // FIXME: Implementation of a class with no @interface (legacy) doese not - // produce correct synthesis as yet. - SynthesizeObjCInternalStruct(CDecl, Result); - } - - // Build _objc_ivar_list metadata for classes ivars if needed - unsigned NumIvars = !IDecl->ivar_empty() - ? IDecl->ivar_size() - : (CDecl ? CDecl->ivar_size() : 0); - if (NumIvars > 0) { - static bool objc_ivar = false; - if (!objc_ivar) { - /* struct _objc_ivar { - char *ivar_name; - char *ivar_type; - int ivar_offset; - }; - */ - Result += "\nstruct _objc_ivar {\n"; - Result += "\tchar *ivar_name;\n"; - Result += "\tchar *ivar_type;\n"; - Result += "\tint ivar_offset;\n"; - Result += "};\n"; - - objc_ivar = true; - } - - /* struct { - int ivar_count; - struct _objc_ivar ivar_list[nIvars]; - }; - */ - Result += "\nstatic struct {\n"; - Result += "\tint ivar_count;\n"; - Result += "\tstruct _objc_ivar ivar_list["; - Result += utostr(NumIvars); - Result += "];\n} _OBJC_INSTANCE_VARIABLES_"; - Result += IDecl->getName(); - Result += " __attribute__ ((used, section (\"__OBJC, __instance_vars\")))= " - "{\n\t"; - Result += utostr(NumIvars); - Result += "\n"; - - ObjCInterfaceDecl::ivar_iterator IVI, IVE; - if (!IDecl->ivar_empty()) { - IVI = IDecl->ivar_begin(); - IVE = IDecl->ivar_end(); - } else { - IVI = CDecl->ivar_begin(); - IVE = CDecl->ivar_end(); - } - Result += "\t,{{\""; - Result += (*IVI)->getName(); - Result += "\", \""; - std::string StrEncoding; - Context->getObjCEncodingForType((*IVI)->getType(), StrEncoding, - EncodingRecordTypes); - Result += StrEncoding; - Result += "\", "; - SynthesizeIvarOffsetComputation(IDecl, *IVI, Result); - Result += "}\n"; - for (++IVI; IVI != IVE; ++IVI) { - Result += "\t ,{\""; - Result += (*IVI)->getName(); - Result += "\", \""; - std::string StrEncoding; - Context->getObjCEncodingForType((*IVI)->getType(), StrEncoding, - EncodingRecordTypes); - Result += StrEncoding; - Result += "\", "; - SynthesizeIvarOffsetComputation(IDecl, (*IVI), Result); - Result += "}\n"; - } - - Result += "\t }\n};\n"; - } - - // Build _objc_method_list for class's instance methods if needed - RewriteObjCMethodsMetaData(IDecl->instmeth_begin(), IDecl->instmeth_end(), - true, "", IDecl->getName(), Result); - - // Build _objc_method_list for class's class methods if needed - RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(), - false, "", IDecl->getName(), Result); - - // Protocols referenced in class declaration? - RewriteObjCProtocolsMetaData(CDecl->getReferencedProtocols(), - CDecl->getNumIntfRefProtocols(), - "CLASS", CDecl->getName(), Result); - - - // Declaration of class/meta-class metadata - /* struct _objc_class { - struct _objc_class *isa; // or const char *root_class_name when metadata - const char *super_class_name; - char *name; - long version; - long info; - long instance_size; - struct _objc_ivar_list *ivars; - struct _objc_method_list *methods; - struct objc_cache *cache; - struct objc_protocol_list *protocols; - const char *ivar_layout; - struct _objc_class_ext *ext; - }; - */ - static bool objc_class = false; - if (!objc_class) { - Result += "\nstruct _objc_class {\n"; - Result += "\tstruct _objc_class *isa;\n"; - Result += "\tconst char *super_class_name;\n"; - Result += "\tchar *name;\n"; - Result += "\tlong version;\n"; - Result += "\tlong info;\n"; - Result += "\tlong instance_size;\n"; - Result += "\tstruct _objc_ivar_list *ivars;\n"; - Result += "\tstruct _objc_method_list *methods;\n"; - Result += "\tstruct objc_cache *cache;\n"; - Result += "\tstruct _objc_protocol_list *protocols;\n"; - Result += "\tconst char *ivar_layout;\n"; - Result += "\tstruct _objc_class_ext *ext;\n"; - Result += "};\n"; - objc_class = true; - } - - // Meta-class metadata generation. - ObjCInterfaceDecl *RootClass = 0; - ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass(); - while (SuperClass) { - RootClass = SuperClass; - SuperClass = SuperClass->getSuperClass(); - } - SuperClass = CDecl->getSuperClass(); - - Result += "\nstatic struct _objc_class _OBJC_METACLASS_"; - Result += CDecl->getName(); - Result += " __attribute__ ((used, section (\"__OBJC, __meta_class\")))= " - "{\n\t(struct _objc_class *)\""; - Result += (RootClass ? RootClass->getName() : CDecl->getName()); - Result += "\""; - - if (SuperClass) { - Result += ", \""; - Result += SuperClass->getName(); - Result += "\", \""; - Result += CDecl->getName(); - Result += "\""; - } - else { - Result += ", 0, \""; - Result += CDecl->getName(); - Result += "\""; - } - // Set 'ivars' field for root class to 0. ObjC1 runtime does not use it. - // 'info' field is initialized to CLS_META(2) for metaclass - Result += ", 0,2, sizeof(struct _objc_class), 0"; - if (IDecl->getNumClassMethods() > 0) { - Result += "\n\t, (struct _objc_method_list *)&_OBJC_CLASS_METHODS_"; - Result += IDecl->getName(); - Result += "\n"; - } - else - Result += ", 0\n"; - if (CDecl->getNumIntfRefProtocols() > 0) { - Result += "\t,0, (struct _objc_protocol_list *)&_OBJC_CLASS_PROTOCOLS_"; - Result += CDecl->getName(); - Result += ",0,0\n"; - } - else - Result += "\t,0,0,0,0\n"; - Result += "};\n"; - - // class metadata generation. - Result += "\nstatic struct _objc_class _OBJC_CLASS_"; - Result += CDecl->getName(); - Result += " __attribute__ ((used, section (\"__OBJC, __class\")))= " - "{\n\t&_OBJC_METACLASS_"; - Result += CDecl->getName(); - if (SuperClass) { - Result += ", \""; - Result += SuperClass->getName(); - Result += "\", \""; - Result += CDecl->getName(); - Result += "\""; - } - else { - Result += ", 0, \""; - Result += CDecl->getName(); - Result += "\""; - } - // 'info' field is initialized to CLS_CLASS(1) for class - Result += ", 0,1"; - if (!ObjCSynthesizedStructs.count(CDecl)) - Result += ",0"; - else { - // class has size. Must synthesize its size. - Result += ",sizeof(struct "; - Result += CDecl->getName(); - if (LangOpts.Microsoft) - Result += "_IMPL"; - Result += ")"; - } - if (NumIvars > 0) { - Result += ", (struct _objc_ivar_list *)&_OBJC_INSTANCE_VARIABLES_"; - Result += CDecl->getName(); - Result += "\n\t"; - } - else - Result += ",0"; - if (IDecl->getNumInstanceMethods() > 0) { - Result += ", (struct _objc_method_list *)&_OBJC_INSTANCE_METHODS_"; - Result += CDecl->getName(); - Result += ", 0\n\t"; - } - else - Result += ",0,0"; - if (CDecl->getNumIntfRefProtocols() > 0) { - Result += ", (struct _objc_protocol_list*)&_OBJC_CLASS_PROTOCOLS_"; - Result += CDecl->getName(); - Result += ", 0,0\n"; - } - else - Result += ",0,0,0\n"; - Result += "};\n"; -} - -/// RewriteImplementations - This routine rewrites all method implementations -/// and emits meta-data. - -void RewriteObjC::RewriteImplementations(std::string &Result) { - int ClsDefCount = ClassImplementation.size(); - int CatDefCount = CategoryImplementation.size(); - - if (ClsDefCount == 0 && CatDefCount == 0) - return; - // Rewrite implemented methods - for (int i = 0; i < ClsDefCount; i++) - RewriteImplementationDecl(ClassImplementation[i]); - - for (int i = 0; i < CatDefCount; i++) - RewriteImplementationDecl(CategoryImplementation[i]); - - // This is needed for determining instance variable offsets. - Result += "#define __OFFSETOFIVAR__(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)\n"; - // For each implemented class, write out all its meta data. - for (int i = 0; i < ClsDefCount; i++) - RewriteObjCClassMetaData(ClassImplementation[i], Result); - - // For each implemented category, write out all its meta data. - for (int i = 0; i < CatDefCount; i++) - RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result); - - // Write objc_symtab metadata - /* - struct _objc_symtab - { - long sel_ref_cnt; - SEL *refs; - short cls_def_cnt; - short cat_def_cnt; - void *defs[cls_def_cnt + cat_def_cnt]; - }; - */ - - Result += "\nstruct _objc_symtab {\n"; - Result += "\tlong sel_ref_cnt;\n"; - Result += "\tSEL *refs;\n"; - Result += "\tshort cls_def_cnt;\n"; - Result += "\tshort cat_def_cnt;\n"; - Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n"; - Result += "};\n\n"; - - Result += "static struct _objc_symtab " - "_OBJC_SYMBOLS __attribute__((used, section (\"__OBJC, __symbols\")))= {\n"; - Result += "\t0, 0, " + utostr(ClsDefCount) - + ", " + utostr(CatDefCount) + "\n"; - for (int i = 0; i < ClsDefCount; i++) { - Result += "\t,&_OBJC_CLASS_"; - Result += ClassImplementation[i]->getName(); - Result += "\n"; - } - - for (int i = 0; i < CatDefCount; i++) { - Result += "\t,&_OBJC_CATEGORY_"; - Result += CategoryImplementation[i]->getClassInterface()->getName(); - Result += "_"; - Result += CategoryImplementation[i]->getName(); - Result += "\n"; - } - - Result += "};\n\n"; - - // Write objc_module metadata - - /* - struct _objc_module { - long version; - long size; - const char *name; - struct _objc_symtab *symtab; - } - */ - - Result += "\nstruct _objc_module {\n"; - Result += "\tlong version;\n"; - Result += "\tlong size;\n"; - Result += "\tconst char *name;\n"; - Result += "\tstruct _objc_symtab *symtab;\n"; - Result += "};\n\n"; - Result += "static struct _objc_module " - "_OBJC_MODULES __attribute__ ((used, section (\"__OBJC, __module_info\")))= {\n"; - Result += "\t" + utostr(OBJC_ABI_VERSION) + - ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n"; - Result += "};\n\n"; - - if (LangOpts.Microsoft) { - Result += "#pragma section(\".objc_module_info$B\",long,read,write)\n"; - Result += "#pragma data_seg(push, \".objc_module_info$B\")\n"; - Result += "static struct _objc_module *_POINTER_OBJC_MODULES = "; - Result += "&_OBJC_MODULES;\n"; - Result += "#pragma data_seg(pop)\n\n"; - } -} - - |