Path: blob/main/contrib/llvm-project/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
35266 views
//===--- RewriteObjC.cpp - Playground for the code rewriter ---------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Hacks and fun related to the code rewriter.9//10//===----------------------------------------------------------------------===//1112#include "clang/Rewrite/Frontend/ASTConsumers.h"13#include "clang/AST/AST.h"14#include "clang/AST/ASTConsumer.h"15#include "clang/AST/Attr.h"16#include "clang/AST/ParentMap.h"17#include "clang/Basic/CharInfo.h"18#include "clang/Basic/Diagnostic.h"19#include "clang/Basic/IdentifierTable.h"20#include "clang/Basic/SourceManager.h"21#include "clang/Config/config.h"22#include "clang/Lex/Lexer.h"23#include "clang/Rewrite/Core/Rewriter.h"24#include "llvm/ADT/DenseSet.h"25#include "llvm/ADT/SmallPtrSet.h"26#include "llvm/ADT/StringExtras.h"27#include "llvm/Support/MemoryBuffer.h"28#include "llvm/Support/raw_ostream.h"29#include <memory>3031#if CLANG_ENABLE_OBJC_REWRITER3233using namespace clang;34using llvm::utostr;3536namespace {37class RewriteObjC : public ASTConsumer {38protected:39enum {40BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)),41block, ... */42BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */43BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the44__block variable */45BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy46helpers */47BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose48support routines */49BLOCK_BYREF_CURRENT_MAX = 25650};5152enum {53BLOCK_NEEDS_FREE = (1 << 24),54BLOCK_HAS_COPY_DISPOSE = (1 << 25),55BLOCK_HAS_CXX_OBJ = (1 << 26),56BLOCK_IS_GC = (1 << 27),57BLOCK_IS_GLOBAL = (1 << 28),58BLOCK_HAS_DESCRIPTOR = (1 << 29)59};60static const int OBJC_ABI_VERSION = 7;6162Rewriter Rewrite;63DiagnosticsEngine &Diags;64const LangOptions &LangOpts;65ASTContext *Context;66SourceManager *SM;67TranslationUnitDecl *TUDecl;68FileID MainFileID;69const char *MainFileStart, *MainFileEnd;70Stmt *CurrentBody;71ParentMap *PropParentMap; // created lazily.72std::string InFileName;73std::unique_ptr<raw_ostream> OutFile;74std::string Preamble;7576TypeDecl *ProtocolTypeDecl;77VarDecl *GlobalVarDecl;78unsigned RewriteFailedDiag;79// ObjC string constant support.80unsigned NumObjCStringLiterals;81VarDecl *ConstantStringClassReference;82RecordDecl *NSStringRecord;8384// ObjC foreach break/continue generation support.85int BcLabelCount;8687unsigned TryFinallyContainsReturnDiag;88// Needed for super.89ObjCMethodDecl *CurMethodDef;90RecordDecl *SuperStructDecl;91RecordDecl *ConstantStringDecl;9293FunctionDecl *MsgSendFunctionDecl;94FunctionDecl *MsgSendSuperFunctionDecl;95FunctionDecl *MsgSendStretFunctionDecl;96FunctionDecl *MsgSendSuperStretFunctionDecl;97FunctionDecl *MsgSendFpretFunctionDecl;98FunctionDecl *GetClassFunctionDecl;99FunctionDecl *GetMetaClassFunctionDecl;100FunctionDecl *GetSuperClassFunctionDecl;101FunctionDecl *SelGetUidFunctionDecl;102FunctionDecl *CFStringFunctionDecl;103FunctionDecl *SuperConstructorFunctionDecl;104FunctionDecl *CurFunctionDef;105FunctionDecl *CurFunctionDeclToDeclareForBlock;106107/* Misc. containers needed for meta-data rewrite. */108SmallVector<ObjCImplementationDecl *, 8> ClassImplementation;109SmallVector<ObjCCategoryImplDecl *, 8> CategoryImplementation;110llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCSynthesizedStructs;111llvm::SmallPtrSet<ObjCProtocolDecl*, 8> ObjCSynthesizedProtocols;112llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCForwardDecls;113llvm::DenseMap<ObjCMethodDecl*, std::string> MethodInternalNames;114SmallVector<Stmt *, 32> Stmts;115SmallVector<int, 8> ObjCBcLabelNo;116// Remember all the @protocol(<expr>) expressions.117llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ProtocolExprDecls;118119llvm::DenseSet<uint64_t> CopyDestroyCache;120121// Block expressions.122SmallVector<BlockExpr *, 32> Blocks;123SmallVector<int, 32> InnerDeclRefsCount;124SmallVector<DeclRefExpr *, 32> InnerDeclRefs;125126SmallVector<DeclRefExpr *, 32> BlockDeclRefs;127128// Block related declarations.129SmallVector<ValueDecl *, 8> BlockByCopyDecls;130llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDeclsPtrSet;131SmallVector<ValueDecl *, 8> BlockByRefDecls;132llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDeclsPtrSet;133llvm::DenseMap<ValueDecl *, unsigned> BlockByRefDeclNo;134llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls;135llvm::SmallPtrSet<VarDecl *, 8> ImportedLocalExternalDecls;136137llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs;138139// This maps an original source AST to it's rewritten form. This allows140// us to avoid rewriting the same node twice (which is very uncommon).141// This is needed to support some of the exotic property rewriting.142llvm::DenseMap<Stmt *, Stmt *> ReplacedNodes;143144// Needed for header files being rewritten145bool IsHeader;146bool SilenceRewriteMacroWarning;147bool objc_impl_method;148149bool DisableReplaceStmt;150class DisableReplaceStmtScope {151RewriteObjC &R;152bool SavedValue;153154public:155DisableReplaceStmtScope(RewriteObjC &R)156: R(R), SavedValue(R.DisableReplaceStmt) {157R.DisableReplaceStmt = true;158}159160~DisableReplaceStmtScope() {161R.DisableReplaceStmt = SavedValue;162}163};164165void InitializeCommon(ASTContext &context);166167public:168// Top Level Driver code.169bool HandleTopLevelDecl(DeclGroupRef D) override {170for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {171if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*I)) {172if (!Class->isThisDeclarationADefinition()) {173RewriteForwardClassDecl(D);174break;175}176}177178if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(*I)) {179if (!Proto->isThisDeclarationADefinition()) {180RewriteForwardProtocolDecl(D);181break;182}183}184185HandleTopLevelSingleDecl(*I);186}187return true;188}189190void HandleTopLevelSingleDecl(Decl *D);191void HandleDeclInMainFile(Decl *D);192RewriteObjC(std::string inFile, std::unique_ptr<raw_ostream> OS,193DiagnosticsEngine &D, const LangOptions &LOpts,194bool silenceMacroWarn);195196~RewriteObjC() override {}197198void HandleTranslationUnit(ASTContext &C) override;199200void ReplaceStmt(Stmt *Old, Stmt *New) {201ReplaceStmtWithRange(Old, New, Old->getSourceRange());202}203204void ReplaceStmtWithRange(Stmt *Old, Stmt *New, SourceRange SrcRange) {205assert(Old != nullptr && New != nullptr && "Expected non-null Stmt's");206207Stmt *ReplacingStmt = ReplacedNodes[Old];208if (ReplacingStmt)209return; // We can't rewrite the same node twice.210211if (DisableReplaceStmt)212return;213214// Measure the old text.215int Size = Rewrite.getRangeSize(SrcRange);216if (Size == -1) {217Diags.Report(Context->getFullLoc(Old->getBeginLoc()), RewriteFailedDiag)218<< Old->getSourceRange();219return;220}221// Get the new text.222std::string SStr;223llvm::raw_string_ostream S(SStr);224New->printPretty(S, nullptr, PrintingPolicy(LangOpts));225const std::string &Str = S.str();226227// If replacement succeeded or warning disabled return with no warning.228if (!Rewrite.ReplaceText(SrcRange.getBegin(), Size, Str)) {229ReplacedNodes[Old] = New;230return;231}232if (SilenceRewriteMacroWarning)233return;234Diags.Report(Context->getFullLoc(Old->getBeginLoc()), RewriteFailedDiag)235<< Old->getSourceRange();236}237238void InsertText(SourceLocation Loc, StringRef Str,239bool InsertAfter = true) {240// If insertion succeeded or warning disabled return with no warning.241if (!Rewrite.InsertText(Loc, Str, InsertAfter) ||242SilenceRewriteMacroWarning)243return;244245Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag);246}247248void ReplaceText(SourceLocation Start, unsigned OrigLength,249StringRef Str) {250// If removal succeeded or warning disabled return with no warning.251if (!Rewrite.ReplaceText(Start, OrigLength, Str) ||252SilenceRewriteMacroWarning)253return;254255Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag);256}257258// Syntactic Rewriting.259void RewriteRecordBody(RecordDecl *RD);260void RewriteInclude();261void RewriteForwardClassDecl(DeclGroupRef D);262void RewriteForwardClassDecl(const SmallVectorImpl<Decl *> &DG);263void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl,264const std::string &typedefString);265void RewriteImplementations();266void RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,267ObjCImplementationDecl *IMD,268ObjCCategoryImplDecl *CID);269void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl);270void RewriteImplementationDecl(Decl *Dcl);271void RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl,272ObjCMethodDecl *MDecl, std::string &ResultStr);273void RewriteTypeIntoString(QualType T, std::string &ResultStr,274const FunctionType *&FPRetType);275void RewriteByRefString(std::string &ResultStr, const std::string &Name,276ValueDecl *VD, bool def=false);277void RewriteCategoryDecl(ObjCCategoryDecl *Dcl);278void RewriteProtocolDecl(ObjCProtocolDecl *Dcl);279void RewriteForwardProtocolDecl(DeclGroupRef D);280void RewriteForwardProtocolDecl(const SmallVectorImpl<Decl *> &DG);281void RewriteMethodDeclaration(ObjCMethodDecl *Method);282void RewriteProperty(ObjCPropertyDecl *prop);283void RewriteFunctionDecl(FunctionDecl *FD);284void RewriteBlockPointerType(std::string& Str, QualType Type);285void RewriteBlockPointerTypeVariable(std::string& Str, ValueDecl *VD);286void RewriteBlockLiteralFunctionDecl(FunctionDecl *FD);287void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl);288void RewriteTypeOfDecl(VarDecl *VD);289void RewriteObjCQualifiedInterfaceTypes(Expr *E);290291// Expression Rewriting.292Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S);293Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);294Stmt *RewritePropertyOrImplicitGetter(PseudoObjectExpr *Pseudo);295Stmt *RewritePropertyOrImplicitSetter(PseudoObjectExpr *Pseudo);296Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp);297Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);298Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp);299Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp);300void RewriteTryReturnStmts(Stmt *S);301void RewriteSyncReturnStmts(Stmt *S, std::string buf);302Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S);303Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S);304Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S);305Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,306SourceLocation OrigEnd);307Stmt *RewriteBreakStmt(BreakStmt *S);308Stmt *RewriteContinueStmt(ContinueStmt *S);309void RewriteCastExpr(CStyleCastExpr *CE);310311// Block rewriting.312void RewriteBlocksInFunctionProtoType(QualType funcType, NamedDecl *D);313314// Block specific rewrite rules.315void RewriteBlockPointerDecl(NamedDecl *VD);316void RewriteByRefVar(VarDecl *VD);317Stmt *RewriteBlockDeclRefExpr(DeclRefExpr *VD);318Stmt *RewriteLocalVariableExternalStorage(DeclRefExpr *DRE);319void RewriteBlockPointerFunctionArgs(FunctionDecl *FD);320321void RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,322std::string &Result);323324void Initialize(ASTContext &context) override = 0;325326// Metadata Rewriting.327virtual void RewriteMetaDataIntoBuffer(std::string &Result) = 0;328virtual void RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Prots,329StringRef prefix,330StringRef ClassName,331std::string &Result) = 0;332virtual void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl,333std::string &Result) = 0;334virtual void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol,335StringRef prefix,336StringRef ClassName,337std::string &Result) = 0;338virtual void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,339std::string &Result) = 0;340341// Rewriting ivar access342virtual Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) = 0;343virtual void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,344std::string &Result) = 0;345346// Misc. AST transformation routines. Sometimes they end up calling347// rewriting routines on the new ASTs.348CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD,349ArrayRef<Expr *> Args,350SourceLocation StartLoc=SourceLocation(),351SourceLocation EndLoc=SourceLocation());352CallExpr *SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor,353QualType msgSendType,354QualType returnType,355SmallVectorImpl<QualType> &ArgTypes,356SmallVectorImpl<Expr*> &MsgExprs,357ObjCMethodDecl *Method);358Stmt *SynthMessageExpr(ObjCMessageExpr *Exp,359SourceLocation StartLoc=SourceLocation(),360SourceLocation EndLoc=SourceLocation());361362void SynthCountByEnumWithState(std::string &buf);363void SynthMsgSendFunctionDecl();364void SynthMsgSendSuperFunctionDecl();365void SynthMsgSendStretFunctionDecl();366void SynthMsgSendFpretFunctionDecl();367void SynthMsgSendSuperStretFunctionDecl();368void SynthGetClassFunctionDecl();369void SynthGetMetaClassFunctionDecl();370void SynthGetSuperClassFunctionDecl();371void SynthSelGetUidFunctionDecl();372void SynthSuperConstructorFunctionDecl();373374std::string SynthesizeByrefCopyDestroyHelper(VarDecl *VD, int flag);375std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,376StringRef funcName, std::string Tag);377std::string SynthesizeBlockFunc(BlockExpr *CE, int i,378StringRef funcName, std::string Tag);379std::string SynthesizeBlockImpl(BlockExpr *CE,380std::string Tag, std::string Desc);381std::string SynthesizeBlockDescriptor(std::string DescTag,382std::string ImplTag,383int i, StringRef funcName,384unsigned hasCopy);385Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp);386void SynthesizeBlockLiterals(SourceLocation FunLocStart,387StringRef FunName);388FunctionDecl *SynthBlockInitFunctionDecl(StringRef name);389Stmt *SynthBlockInitExpr(BlockExpr *Exp,390const SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs);391392// Misc. helper routines.393QualType getProtocolType();394void WarnAboutReturnGotoStmts(Stmt *S);395void HasReturnStmts(Stmt *S, bool &hasReturns);396void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND);397void InsertBlockLiteralsWithinFunction(FunctionDecl *FD);398void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD);399400bool IsDeclStmtInForeachHeader(DeclStmt *DS);401void CollectBlockDeclRefInfo(BlockExpr *Exp);402void GetBlockDeclRefExprs(Stmt *S);403void GetInnerBlockDeclRefExprs(Stmt *S,404SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs,405llvm::SmallPtrSetImpl<const DeclContext *> &InnerContexts);406407// We avoid calling Type::isBlockPointerType(), since it operates on the408// canonical type. We only care if the top-level type is a closure pointer.409bool isTopLevelBlockPointerType(QualType T) {410return isa<BlockPointerType>(T);411}412413/// convertBlockPointerToFunctionPointer - Converts a block-pointer type414/// to a function pointer type and upon success, returns true; false415/// otherwise.416bool convertBlockPointerToFunctionPointer(QualType &T) {417if (isTopLevelBlockPointerType(T)) {418const auto *BPT = T->castAs<BlockPointerType>();419T = Context->getPointerType(BPT->getPointeeType());420return true;421}422return false;423}424425bool needToScanForQualifiers(QualType T);426QualType getSuperStructType();427QualType getConstantStringStructType();428QualType convertFunctionTypeOfBlocks(const FunctionType *FT);429bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf);430431void convertToUnqualifiedObjCType(QualType &T) {432if (T->isObjCQualifiedIdType())433T = Context->getObjCIdType();434else if (T->isObjCQualifiedClassType())435T = Context->getObjCClassType();436else if (T->isObjCObjectPointerType() &&437T->getPointeeType()->isObjCQualifiedInterfaceType()) {438if (const ObjCObjectPointerType * OBJPT =439T->getAsObjCInterfacePointerType()) {440const ObjCInterfaceType *IFaceT = OBJPT->getInterfaceType();441T = QualType(IFaceT, 0);442T = Context->getPointerType(T);443}444}445}446447// FIXME: This predicate seems like it would be useful to add to ASTContext.448bool isObjCType(QualType T) {449if (!LangOpts.ObjC)450return false;451452QualType OCT = Context->getCanonicalType(T).getUnqualifiedType();453454if (OCT == Context->getCanonicalType(Context->getObjCIdType()) ||455OCT == Context->getCanonicalType(Context->getObjCClassType()))456return true;457458if (const PointerType *PT = OCT->getAs<PointerType>()) {459if (isa<ObjCInterfaceType>(PT->getPointeeType()) ||460PT->getPointeeType()->isObjCQualifiedIdType())461return true;462}463return false;464}465bool PointerTypeTakesAnyBlockArguments(QualType QT);466bool PointerTypeTakesAnyObjCQualifiedType(QualType QT);467void GetExtentOfArgList(const char *Name, const char *&LParen,468const char *&RParen);469470void QuoteDoublequotes(std::string &From, std::string &To) {471for (unsigned i = 0; i < From.length(); i++) {472if (From[i] == '"')473To += "\\\"";474else475To += From[i];476}477}478479QualType getSimpleFunctionType(QualType result,480ArrayRef<QualType> args,481bool variadic = false) {482if (result == Context->getObjCInstanceType())483result = Context->getObjCIdType();484FunctionProtoType::ExtProtoInfo fpi;485fpi.Variadic = variadic;486return Context->getFunctionType(result, args, fpi);487}488489// Helper function: create a CStyleCastExpr with trivial type source info.490CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty,491CastKind Kind, Expr *E) {492TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation());493return CStyleCastExpr::Create(*Ctx, Ty, VK_PRValue, Kind, E, nullptr,494FPOptionsOverride(), TInfo,495SourceLocation(), SourceLocation());496}497498StringLiteral *getStringLiteral(StringRef Str) {499QualType StrType = Context->getConstantArrayType(500Context->CharTy, llvm::APInt(32, Str.size() + 1), nullptr,501ArraySizeModifier::Normal, 0);502return StringLiteral::Create(*Context, Str, StringLiteralKind::Ordinary,503/*Pascal=*/false, StrType, SourceLocation());504}505};506507class RewriteObjCFragileABI : public RewriteObjC {508public:509RewriteObjCFragileABI(std::string inFile, std::unique_ptr<raw_ostream> OS,510DiagnosticsEngine &D, const LangOptions &LOpts,511bool silenceMacroWarn)512: RewriteObjC(inFile, std::move(OS), D, LOpts, silenceMacroWarn) {}513514~RewriteObjCFragileABI() override {}515void Initialize(ASTContext &context) override;516517// Rewriting metadata518template<typename MethodIterator>519void RewriteObjCMethodsMetaData(MethodIterator MethodBegin,520MethodIterator MethodEnd,521bool IsInstanceMethod,522StringRef prefix,523StringRef ClassName,524std::string &Result);525void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol,526StringRef prefix, StringRef ClassName,527std::string &Result) override;528void RewriteObjCProtocolListMetaData(529const ObjCList<ObjCProtocolDecl> &Prots,530StringRef prefix, StringRef ClassName, std::string &Result) override;531void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,532std::string &Result) override;533void RewriteMetaDataIntoBuffer(std::string &Result) override;534void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl,535std::string &Result) override;536537// Rewriting ivar538void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,539std::string &Result) override;540Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) override;541};542} // end anonymous namespace543544void RewriteObjC::RewriteBlocksInFunctionProtoType(QualType funcType,545NamedDecl *D) {546if (const FunctionProtoType *fproto547= dyn_cast<FunctionProtoType>(funcType.IgnoreParens())) {548for (const auto &I : fproto->param_types())549if (isTopLevelBlockPointerType(I)) {550// All the args are checked/rewritten. Don't call twice!551RewriteBlockPointerDecl(D);552break;553}554}555}556557void RewriteObjC::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) {558const PointerType *PT = funcType->getAs<PointerType>();559if (PT && PointerTypeTakesAnyBlockArguments(funcType))560RewriteBlocksInFunctionProtoType(PT->getPointeeType(), ND);561}562563static bool IsHeaderFile(const std::string &Filename) {564std::string::size_type DotPos = Filename.rfind('.');565566if (DotPos == std::string::npos) {567// no file extension568return false;569}570571std::string Ext = Filename.substr(DotPos + 1);572// C header: .h573// C++ header: .hh or .H;574return Ext == "h" || Ext == "hh" || Ext == "H";575}576577RewriteObjC::RewriteObjC(std::string inFile, std::unique_ptr<raw_ostream> OS,578DiagnosticsEngine &D, const LangOptions &LOpts,579bool silenceMacroWarn)580: Diags(D), LangOpts(LOpts), InFileName(inFile), OutFile(std::move(OS)),581SilenceRewriteMacroWarning(silenceMacroWarn) {582IsHeader = IsHeaderFile(inFile);583RewriteFailedDiag = Diags.getCustomDiagID(DiagnosticsEngine::Warning,584"rewriting sub-expression within a macro (may not be correct)");585TryFinallyContainsReturnDiag = Diags.getCustomDiagID(586DiagnosticsEngine::Warning,587"rewriter doesn't support user-specified control flow semantics "588"for @try/@finally (code may not execute properly)");589}590591std::unique_ptr<ASTConsumer>592clang::CreateObjCRewriter(const std::string &InFile,593std::unique_ptr<raw_ostream> OS,594DiagnosticsEngine &Diags, const LangOptions &LOpts,595bool SilenceRewriteMacroWarning) {596return std::make_unique<RewriteObjCFragileABI>(597InFile, std::move(OS), Diags, LOpts, SilenceRewriteMacroWarning);598}599600void RewriteObjC::InitializeCommon(ASTContext &context) {601Context = &context;602SM = &Context->getSourceManager();603TUDecl = Context->getTranslationUnitDecl();604MsgSendFunctionDecl = nullptr;605MsgSendSuperFunctionDecl = nullptr;606MsgSendStretFunctionDecl = nullptr;607MsgSendSuperStretFunctionDecl = nullptr;608MsgSendFpretFunctionDecl = nullptr;609GetClassFunctionDecl = nullptr;610GetMetaClassFunctionDecl = nullptr;611GetSuperClassFunctionDecl = nullptr;612SelGetUidFunctionDecl = nullptr;613CFStringFunctionDecl = nullptr;614ConstantStringClassReference = nullptr;615NSStringRecord = nullptr;616CurMethodDef = nullptr;617CurFunctionDef = nullptr;618CurFunctionDeclToDeclareForBlock = nullptr;619GlobalVarDecl = nullptr;620SuperStructDecl = nullptr;621ProtocolTypeDecl = nullptr;622ConstantStringDecl = nullptr;623BcLabelCount = 0;624SuperConstructorFunctionDecl = nullptr;625NumObjCStringLiterals = 0;626PropParentMap = nullptr;627CurrentBody = nullptr;628DisableReplaceStmt = false;629objc_impl_method = false;630631// Get the ID and start/end of the main file.632MainFileID = SM->getMainFileID();633llvm::MemoryBufferRef MainBuf = SM->getBufferOrFake(MainFileID);634MainFileStart = MainBuf.getBufferStart();635MainFileEnd = MainBuf.getBufferEnd();636637Rewrite.setSourceMgr(Context->getSourceManager(), Context->getLangOpts());638}639640//===----------------------------------------------------------------------===//641// Top Level Driver Code642//===----------------------------------------------------------------------===//643644void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {645if (Diags.hasErrorOccurred())646return;647648// Two cases: either the decl could be in the main file, or it could be in a649// #included file. If the former, rewrite it now. If the later, check to see650// if we rewrote the #include/#import.651SourceLocation Loc = D->getLocation();652Loc = SM->getExpansionLoc(Loc);653654// If this is for a builtin, ignore it.655if (Loc.isInvalid()) return;656657// Look for built-in declarations that we need to refer during the rewrite.658if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {659RewriteFunctionDecl(FD);660} else if (VarDecl *FVD = dyn_cast<VarDecl>(D)) {661// declared in <Foundation/NSString.h>662if (FVD->getName() == "_NSConstantStringClassReference") {663ConstantStringClassReference = FVD;664return;665}666} else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {667if (ID->isThisDeclarationADefinition())668RewriteInterfaceDecl(ID);669} else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) {670RewriteCategoryDecl(CD);671} else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {672if (PD->isThisDeclarationADefinition())673RewriteProtocolDecl(PD);674} else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) {675// Recurse into linkage specifications676for (DeclContext::decl_iterator DI = LSD->decls_begin(),677DIEnd = LSD->decls_end();678DI != DIEnd; ) {679if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>((*DI))) {680if (!IFace->isThisDeclarationADefinition()) {681SmallVector<Decl *, 8> DG;682SourceLocation StartLoc = IFace->getBeginLoc();683do {684if (isa<ObjCInterfaceDecl>(*DI) &&685!cast<ObjCInterfaceDecl>(*DI)->isThisDeclarationADefinition() &&686StartLoc == (*DI)->getBeginLoc())687DG.push_back(*DI);688else689break;690691++DI;692} while (DI != DIEnd);693RewriteForwardClassDecl(DG);694continue;695}696}697698if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>((*DI))) {699if (!Proto->isThisDeclarationADefinition()) {700SmallVector<Decl *, 8> DG;701SourceLocation StartLoc = Proto->getBeginLoc();702do {703if (isa<ObjCProtocolDecl>(*DI) &&704!cast<ObjCProtocolDecl>(*DI)->isThisDeclarationADefinition() &&705StartLoc == (*DI)->getBeginLoc())706DG.push_back(*DI);707else708break;709710++DI;711} while (DI != DIEnd);712RewriteForwardProtocolDecl(DG);713continue;714}715}716717HandleTopLevelSingleDecl(*DI);718++DI;719}720}721// If we have a decl in the main file, see if we should rewrite it.722if (SM->isWrittenInMainFile(Loc))723return HandleDeclInMainFile(D);724}725726//===----------------------------------------------------------------------===//727// Syntactic (non-AST) Rewriting Code728//===----------------------------------------------------------------------===//729730void RewriteObjC::RewriteInclude() {731SourceLocation LocStart = SM->getLocForStartOfFile(MainFileID);732StringRef MainBuf = SM->getBufferData(MainFileID);733const char *MainBufStart = MainBuf.begin();734const char *MainBufEnd = MainBuf.end();735size_t ImportLen = strlen("import");736737// Loop over the whole file, looking for includes.738for (const char *BufPtr = MainBufStart; BufPtr < MainBufEnd; ++BufPtr) {739if (*BufPtr == '#') {740if (++BufPtr == MainBufEnd)741return;742while (*BufPtr == ' ' || *BufPtr == '\t')743if (++BufPtr == MainBufEnd)744return;745if (!strncmp(BufPtr, "import", ImportLen)) {746// replace import with include747SourceLocation ImportLoc =748LocStart.getLocWithOffset(BufPtr-MainBufStart);749ReplaceText(ImportLoc, ImportLen, "include");750BufPtr += ImportLen;751}752}753}754}755756static std::string getIvarAccessString(ObjCIvarDecl *OID) {757const ObjCInterfaceDecl *ClassDecl = OID->getContainingInterface();758std::string S;759S = "((struct ";760S += ClassDecl->getIdentifier()->getName();761S += "_IMPL *)self)->";762S += OID->getName();763return S;764}765766void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,767ObjCImplementationDecl *IMD,768ObjCCategoryImplDecl *CID) {769static bool objcGetPropertyDefined = false;770static bool objcSetPropertyDefined = false;771SourceLocation startLoc = PID->getBeginLoc();772InsertText(startLoc, "// ");773const char *startBuf = SM->getCharacterData(startLoc);774assert((*startBuf == '@') && "bogus @synthesize location");775const char *semiBuf = strchr(startBuf, ';');776assert((*semiBuf == ';') && "@synthesize: can't find ';'");777SourceLocation onePastSemiLoc =778startLoc.getLocWithOffset(semiBuf-startBuf+1);779780if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)781return; // FIXME: is this correct?782783// Generate the 'getter' function.784ObjCPropertyDecl *PD = PID->getPropertyDecl();785ObjCIvarDecl *OID = PID->getPropertyIvarDecl();786787if (!OID)788return;789790unsigned Attributes = PD->getPropertyAttributes();791if (PID->getGetterMethodDecl() && !PID->getGetterMethodDecl()->isDefined()) {792bool GenGetProperty =793!(Attributes & ObjCPropertyAttribute::kind_nonatomic) &&794(Attributes & (ObjCPropertyAttribute::kind_retain |795ObjCPropertyAttribute::kind_copy));796std::string Getr;797if (GenGetProperty && !objcGetPropertyDefined) {798objcGetPropertyDefined = true;799// FIXME. Is this attribute correct in all cases?800Getr = "\nextern \"C\" __declspec(dllimport) "801"id objc_getProperty(id, SEL, long, bool);\n";802}803RewriteObjCMethodDecl(OID->getContainingInterface(),804PID->getGetterMethodDecl(), Getr);805Getr += "{ ";806// Synthesize an explicit cast to gain access to the ivar.807// See objc-act.c:objc_synthesize_new_getter() for details.808if (GenGetProperty) {809// return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1)810Getr += "typedef ";811const FunctionType *FPRetType = nullptr;812RewriteTypeIntoString(PID->getGetterMethodDecl()->getReturnType(), Getr,813FPRetType);814Getr += " _TYPE";815if (FPRetType) {816Getr += ")"; // close the precedence "scope" for "*".817818// Now, emit the argument types (if any).819if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(FPRetType)){820Getr += "(";821for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) {822if (i) Getr += ", ";823std::string ParamStr =824FT->getParamType(i).getAsString(Context->getPrintingPolicy());825Getr += ParamStr;826}827if (FT->isVariadic()) {828if (FT->getNumParams())829Getr += ", ";830Getr += "...";831}832Getr += ")";833} else834Getr += "()";835}836Getr += ";\n";837Getr += "return (_TYPE)";838Getr += "objc_getProperty(self, _cmd, ";839RewriteIvarOffsetComputation(OID, Getr);840Getr += ", 1)";841}842else843Getr += "return " + getIvarAccessString(OID);844Getr += "; }";845InsertText(onePastSemiLoc, Getr);846}847848if (PD->isReadOnly() || !PID->getSetterMethodDecl() ||849PID->getSetterMethodDecl()->isDefined())850return;851852// Generate the 'setter' function.853std::string Setr;854bool GenSetProperty = Attributes & (ObjCPropertyAttribute::kind_retain |855ObjCPropertyAttribute::kind_copy);856if (GenSetProperty && !objcSetPropertyDefined) {857objcSetPropertyDefined = true;858// FIXME. Is this attribute correct in all cases?859Setr = "\nextern \"C\" __declspec(dllimport) "860"void objc_setProperty (id, SEL, long, id, bool, bool);\n";861}862863RewriteObjCMethodDecl(OID->getContainingInterface(),864PID->getSetterMethodDecl(), Setr);865Setr += "{ ";866// Synthesize an explicit cast to initialize the ivar.867// See objc-act.c:objc_synthesize_new_setter() for details.868if (GenSetProperty) {869Setr += "objc_setProperty (self, _cmd, ";870RewriteIvarOffsetComputation(OID, Setr);871Setr += ", (id)";872Setr += PD->getName();873Setr += ", ";874if (Attributes & ObjCPropertyAttribute::kind_nonatomic)875Setr += "0, ";876else877Setr += "1, ";878if (Attributes & ObjCPropertyAttribute::kind_copy)879Setr += "1)";880else881Setr += "0)";882}883else {884Setr += getIvarAccessString(OID) + " = ";885Setr += PD->getName();886}887Setr += "; }";888InsertText(onePastSemiLoc, Setr);889}890891static void RewriteOneForwardClassDecl(ObjCInterfaceDecl *ForwardDecl,892std::string &typedefString) {893typedefString += "#ifndef _REWRITER_typedef_";894typedefString += ForwardDecl->getNameAsString();895typedefString += "\n";896typedefString += "#define _REWRITER_typedef_";897typedefString += ForwardDecl->getNameAsString();898typedefString += "\n";899typedefString += "typedef struct objc_object ";900typedefString += ForwardDecl->getNameAsString();901typedefString += ";\n#endif\n";902}903904void RewriteObjC::RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl,905const std::string &typedefString) {906SourceLocation startLoc = ClassDecl->getBeginLoc();907const char *startBuf = SM->getCharacterData(startLoc);908const char *semiPtr = strchr(startBuf, ';');909// Replace the @class with typedefs corresponding to the classes.910ReplaceText(startLoc, semiPtr - startBuf + 1, typedefString);911}912913void RewriteObjC::RewriteForwardClassDecl(DeclGroupRef D) {914std::string typedefString;915for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {916ObjCInterfaceDecl *ForwardDecl = cast<ObjCInterfaceDecl>(*I);917if (I == D.begin()) {918// Translate to typedef's that forward reference structs with the same name919// as the class. As a convenience, we include the original declaration920// as a comment.921typedefString += "// @class ";922typedefString += ForwardDecl->getNameAsString();923typedefString += ";\n";924}925RewriteOneForwardClassDecl(ForwardDecl, typedefString);926}927DeclGroupRef::iterator I = D.begin();928RewriteForwardClassEpilogue(cast<ObjCInterfaceDecl>(*I), typedefString);929}930931void RewriteObjC::RewriteForwardClassDecl(const SmallVectorImpl<Decl *> &D) {932std::string typedefString;933for (unsigned i = 0; i < D.size(); i++) {934ObjCInterfaceDecl *ForwardDecl = cast<ObjCInterfaceDecl>(D[i]);935if (i == 0) {936typedefString += "// @class ";937typedefString += ForwardDecl->getNameAsString();938typedefString += ";\n";939}940RewriteOneForwardClassDecl(ForwardDecl, typedefString);941}942RewriteForwardClassEpilogue(cast<ObjCInterfaceDecl>(D[0]), typedefString);943}944945void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) {946// When method is a synthesized one, such as a getter/setter there is947// nothing to rewrite.948if (Method->isImplicit())949return;950SourceLocation LocStart = Method->getBeginLoc();951SourceLocation LocEnd = Method->getEndLoc();952953if (SM->getExpansionLineNumber(LocEnd) >954SM->getExpansionLineNumber(LocStart)) {955InsertText(LocStart, "#if 0\n");956ReplaceText(LocEnd, 1, ";\n#endif\n");957} else {958InsertText(LocStart, "// ");959}960}961962void RewriteObjC::RewriteProperty(ObjCPropertyDecl *prop) {963SourceLocation Loc = prop->getAtLoc();964965ReplaceText(Loc, 0, "// ");966// FIXME: handle properties that are declared across multiple lines.967}968969void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {970SourceLocation LocStart = CatDecl->getBeginLoc();971972// FIXME: handle category headers that are declared across multiple lines.973ReplaceText(LocStart, 0, "// ");974975for (auto *I : CatDecl->instance_properties())976RewriteProperty(I);977for (auto *I : CatDecl->instance_methods())978RewriteMethodDeclaration(I);979for (auto *I : CatDecl->class_methods())980RewriteMethodDeclaration(I);981982// Lastly, comment out the @end.983ReplaceText(CatDecl->getAtEndRange().getBegin(),984strlen("@end"), "/* @end */");985}986987void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {988SourceLocation LocStart = PDecl->getBeginLoc();989assert(PDecl->isThisDeclarationADefinition());990991// FIXME: handle protocol headers that are declared across multiple lines.992ReplaceText(LocStart, 0, "// ");993994for (auto *I : PDecl->instance_methods())995RewriteMethodDeclaration(I);996for (auto *I : PDecl->class_methods())997RewriteMethodDeclaration(I);998for (auto *I : PDecl->instance_properties())999RewriteProperty(I);10001001// Lastly, comment out the @end.1002SourceLocation LocEnd = PDecl->getAtEndRange().getBegin();1003ReplaceText(LocEnd, strlen("@end"), "/* @end */");10041005// Must comment out @optional/@required1006const char *startBuf = SM->getCharacterData(LocStart);1007const char *endBuf = SM->getCharacterData(LocEnd);1008for (const char *p = startBuf; p < endBuf; p++) {1009if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) {1010SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf);1011ReplaceText(OptionalLoc, strlen("@optional"), "/* @optional */");10121013}1014else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) {1015SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf);1016ReplaceText(OptionalLoc, strlen("@required"), "/* @required */");10171018}1019}1020}10211022void RewriteObjC::RewriteForwardProtocolDecl(DeclGroupRef D) {1023SourceLocation LocStart = (*D.begin())->getBeginLoc();1024if (LocStart.isInvalid())1025llvm_unreachable("Invalid SourceLocation");1026// FIXME: handle forward protocol that are declared across multiple lines.1027ReplaceText(LocStart, 0, "// ");1028}10291030void1031RewriteObjC::RewriteForwardProtocolDecl(const SmallVectorImpl<Decl *> &DG) {1032SourceLocation LocStart = DG[0]->getBeginLoc();1033if (LocStart.isInvalid())1034llvm_unreachable("Invalid SourceLocation");1035// FIXME: handle forward protocol that are declared across multiple lines.1036ReplaceText(LocStart, 0, "// ");1037}10381039void RewriteObjC::RewriteTypeIntoString(QualType T, std::string &ResultStr,1040const FunctionType *&FPRetType) {1041if (T->isObjCQualifiedIdType())1042ResultStr += "id";1043else if (T->isFunctionPointerType() ||1044T->isBlockPointerType()) {1045// needs special handling, since pointer-to-functions have special1046// syntax (where a decaration models use).1047QualType retType = T;1048QualType PointeeTy;1049if (const PointerType* PT = retType->getAs<PointerType>())1050PointeeTy = PT->getPointeeType();1051else if (const BlockPointerType *BPT = retType->getAs<BlockPointerType>())1052PointeeTy = BPT->getPointeeType();1053if ((FPRetType = PointeeTy->getAs<FunctionType>())) {1054ResultStr +=1055FPRetType->getReturnType().getAsString(Context->getPrintingPolicy());1056ResultStr += "(*";1057}1058} else1059ResultStr += T.getAsString(Context->getPrintingPolicy());1060}10611062void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl,1063ObjCMethodDecl *OMD,1064std::string &ResultStr) {1065//fprintf(stderr,"In RewriteObjCMethodDecl\n");1066const FunctionType *FPRetType = nullptr;1067ResultStr += "\nstatic ";1068RewriteTypeIntoString(OMD->getReturnType(), ResultStr, FPRetType);1069ResultStr += " ";10701071// Unique method name1072std::string NameStr;10731074if (OMD->isInstanceMethod())1075NameStr += "_I_";1076else1077NameStr += "_C_";10781079NameStr += IDecl->getNameAsString();1080NameStr += "_";10811082if (ObjCCategoryImplDecl *CID =1083dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) {1084NameStr += CID->getNameAsString();1085NameStr += "_";1086}1087// Append selector names, replacing ':' with '_'1088{1089std::string selString = OMD->getSelector().getAsString();1090int len = selString.size();1091for (int i = 0; i < len; i++)1092if (selString[i] == ':')1093selString[i] = '_';1094NameStr += selString;1095}1096// Remember this name for metadata emission1097MethodInternalNames[OMD] = NameStr;1098ResultStr += NameStr;10991100// Rewrite arguments1101ResultStr += "(";11021103// invisible arguments1104if (OMD->isInstanceMethod()) {1105QualType selfTy = Context->getObjCInterfaceType(IDecl);1106selfTy = Context->getPointerType(selfTy);1107if (!LangOpts.MicrosoftExt) {1108if (ObjCSynthesizedStructs.count(const_cast<ObjCInterfaceDecl*>(IDecl)))1109ResultStr += "struct ";1110}1111// When rewriting for Microsoft, explicitly omit the structure name.1112ResultStr += IDecl->getNameAsString();1113ResultStr += " *";1114}1115else1116ResultStr += Context->getObjCClassType().getAsString(1117Context->getPrintingPolicy());11181119ResultStr += " self, ";1120ResultStr += Context->getObjCSelType().getAsString(Context->getPrintingPolicy());1121ResultStr += " _cmd";11221123// Method arguments.1124for (const auto *PDecl : OMD->parameters()) {1125ResultStr += ", ";1126if (PDecl->getType()->isObjCQualifiedIdType()) {1127ResultStr += "id ";1128ResultStr += PDecl->getNameAsString();1129} else {1130std::string Name = PDecl->getNameAsString();1131QualType QT = PDecl->getType();1132// Make sure we convert "t (^)(...)" to "t (*)(...)".1133(void)convertBlockPointerToFunctionPointer(QT);1134QT.getAsStringInternal(Name, Context->getPrintingPolicy());1135ResultStr += Name;1136}1137}1138if (OMD->isVariadic())1139ResultStr += ", ...";1140ResultStr += ") ";11411142if (FPRetType) {1143ResultStr += ")"; // close the precedence "scope" for "*".11441145// Now, emit the argument types (if any).1146if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(FPRetType)) {1147ResultStr += "(";1148for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) {1149if (i) ResultStr += ", ";1150std::string ParamStr =1151FT->getParamType(i).getAsString(Context->getPrintingPolicy());1152ResultStr += ParamStr;1153}1154if (FT->isVariadic()) {1155if (FT->getNumParams())1156ResultStr += ", ";1157ResultStr += "...";1158}1159ResultStr += ")";1160} else {1161ResultStr += "()";1162}1163}1164}11651166void RewriteObjC::RewriteImplementationDecl(Decl *OID) {1167ObjCImplementationDecl *IMD = dyn_cast<ObjCImplementationDecl>(OID);1168ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(OID);1169assert((IMD || CID) && "Unknown ImplementationDecl");11701171InsertText(IMD ? IMD->getBeginLoc() : CID->getBeginLoc(), "// ");11721173for (auto *OMD : IMD ? IMD->instance_methods() : CID->instance_methods()) {1174if (!OMD->getBody())1175continue;1176std::string ResultStr;1177RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr);1178SourceLocation LocStart = OMD->getBeginLoc();1179SourceLocation LocEnd = OMD->getCompoundBody()->getBeginLoc();11801181const char *startBuf = SM->getCharacterData(LocStart);1182const char *endBuf = SM->getCharacterData(LocEnd);1183ReplaceText(LocStart, endBuf-startBuf, ResultStr);1184}11851186for (auto *OMD : IMD ? IMD->class_methods() : CID->class_methods()) {1187if (!OMD->getBody())1188continue;1189std::string ResultStr;1190RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr);1191SourceLocation LocStart = OMD->getBeginLoc();1192SourceLocation LocEnd = OMD->getCompoundBody()->getBeginLoc();11931194const char *startBuf = SM->getCharacterData(LocStart);1195const char *endBuf = SM->getCharacterData(LocEnd);1196ReplaceText(LocStart, endBuf-startBuf, ResultStr);1197}1198for (auto *I : IMD ? IMD->property_impls() : CID->property_impls())1199RewritePropertyImplDecl(I, IMD, CID);12001201InsertText(IMD ? IMD->getEndLoc() : CID->getEndLoc(), "// ");1202}12031204void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {1205std::string ResultStr;1206if (!ObjCForwardDecls.count(ClassDecl->getCanonicalDecl())) {1207// we haven't seen a forward decl - generate a typedef.1208ResultStr = "#ifndef _REWRITER_typedef_";1209ResultStr += ClassDecl->getNameAsString();1210ResultStr += "\n";1211ResultStr += "#define _REWRITER_typedef_";1212ResultStr += ClassDecl->getNameAsString();1213ResultStr += "\n";1214ResultStr += "typedef struct objc_object ";1215ResultStr += ClassDecl->getNameAsString();1216ResultStr += ";\n#endif\n";1217// Mark this typedef as having been generated.1218ObjCForwardDecls.insert(ClassDecl->getCanonicalDecl());1219}1220RewriteObjCInternalStruct(ClassDecl, ResultStr);12211222for (auto *I : ClassDecl->instance_properties())1223RewriteProperty(I);1224for (auto *I : ClassDecl->instance_methods())1225RewriteMethodDeclaration(I);1226for (auto *I : ClassDecl->class_methods())1227RewriteMethodDeclaration(I);12281229// Lastly, comment out the @end.1230ReplaceText(ClassDecl->getAtEndRange().getBegin(), strlen("@end"),1231"/* @end */");1232}12331234Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(PseudoObjectExpr *PseudoOp) {1235SourceRange OldRange = PseudoOp->getSourceRange();12361237// We just magically know some things about the structure of this1238// expression.1239ObjCMessageExpr *OldMsg =1240cast<ObjCMessageExpr>(PseudoOp->getSemanticExpr(1241PseudoOp->getNumSemanticExprs() - 1));12421243// Because the rewriter doesn't allow us to rewrite rewritten code,1244// we need to suppress rewriting the sub-statements.1245Expr *Base, *RHS;1246{1247DisableReplaceStmtScope S(*this);12481249// Rebuild the base expression if we have one.1250Base = nullptr;1251if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) {1252Base = OldMsg->getInstanceReceiver();1253Base = cast<OpaqueValueExpr>(Base)->getSourceExpr();1254Base = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(Base));1255}12561257// Rebuild the RHS.1258RHS = cast<BinaryOperator>(PseudoOp->getSyntacticForm())->getRHS();1259RHS = cast<OpaqueValueExpr>(RHS)->getSourceExpr();1260RHS = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(RHS));1261}12621263// TODO: avoid this copy.1264SmallVector<SourceLocation, 1> SelLocs;1265OldMsg->getSelectorLocs(SelLocs);12661267ObjCMessageExpr *NewMsg = nullptr;1268switch (OldMsg->getReceiverKind()) {1269case ObjCMessageExpr::Class:1270NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),1271OldMsg->getValueKind(),1272OldMsg->getLeftLoc(),1273OldMsg->getClassReceiverTypeInfo(),1274OldMsg->getSelector(),1275SelLocs,1276OldMsg->getMethodDecl(),1277RHS,1278OldMsg->getRightLoc(),1279OldMsg->isImplicit());1280break;12811282case ObjCMessageExpr::Instance:1283NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),1284OldMsg->getValueKind(),1285OldMsg->getLeftLoc(),1286Base,1287OldMsg->getSelector(),1288SelLocs,1289OldMsg->getMethodDecl(),1290RHS,1291OldMsg->getRightLoc(),1292OldMsg->isImplicit());1293break;12941295case ObjCMessageExpr::SuperClass:1296case ObjCMessageExpr::SuperInstance:1297NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),1298OldMsg->getValueKind(),1299OldMsg->getLeftLoc(),1300OldMsg->getSuperLoc(),1301OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance,1302OldMsg->getSuperType(),1303OldMsg->getSelector(),1304SelLocs,1305OldMsg->getMethodDecl(),1306RHS,1307OldMsg->getRightLoc(),1308OldMsg->isImplicit());1309break;1310}13111312Stmt *Replacement = SynthMessageExpr(NewMsg);1313ReplaceStmtWithRange(PseudoOp, Replacement, OldRange);1314return Replacement;1315}13161317Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(PseudoObjectExpr *PseudoOp) {1318SourceRange OldRange = PseudoOp->getSourceRange();13191320// We just magically know some things about the structure of this1321// expression.1322ObjCMessageExpr *OldMsg =1323cast<ObjCMessageExpr>(PseudoOp->getResultExpr()->IgnoreImplicit());13241325// Because the rewriter doesn't allow us to rewrite rewritten code,1326// we need to suppress rewriting the sub-statements.1327Expr *Base = nullptr;1328{1329DisableReplaceStmtScope S(*this);13301331// Rebuild the base expression if we have one.1332if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) {1333Base = OldMsg->getInstanceReceiver();1334Base = cast<OpaqueValueExpr>(Base)->getSourceExpr();1335Base = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(Base));1336}1337}13381339// Intentionally empty.1340SmallVector<SourceLocation, 1> SelLocs;1341SmallVector<Expr*, 1> Args;13421343ObjCMessageExpr *NewMsg = nullptr;1344switch (OldMsg->getReceiverKind()) {1345case ObjCMessageExpr::Class:1346NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),1347OldMsg->getValueKind(),1348OldMsg->getLeftLoc(),1349OldMsg->getClassReceiverTypeInfo(),1350OldMsg->getSelector(),1351SelLocs,1352OldMsg->getMethodDecl(),1353Args,1354OldMsg->getRightLoc(),1355OldMsg->isImplicit());1356break;13571358case ObjCMessageExpr::Instance:1359NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),1360OldMsg->getValueKind(),1361OldMsg->getLeftLoc(),1362Base,1363OldMsg->getSelector(),1364SelLocs,1365OldMsg->getMethodDecl(),1366Args,1367OldMsg->getRightLoc(),1368OldMsg->isImplicit());1369break;13701371case ObjCMessageExpr::SuperClass:1372case ObjCMessageExpr::SuperInstance:1373NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),1374OldMsg->getValueKind(),1375OldMsg->getLeftLoc(),1376OldMsg->getSuperLoc(),1377OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance,1378OldMsg->getSuperType(),1379OldMsg->getSelector(),1380SelLocs,1381OldMsg->getMethodDecl(),1382Args,1383OldMsg->getRightLoc(),1384OldMsg->isImplicit());1385break;1386}13871388Stmt *Replacement = SynthMessageExpr(NewMsg);1389ReplaceStmtWithRange(PseudoOp, Replacement, OldRange);1390return Replacement;1391}13921393/// SynthCountByEnumWithState - To print:1394/// ((unsigned int (*)1395/// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))1396/// (void *)objc_msgSend)((id)l_collection,1397/// sel_registerName(1398/// "countByEnumeratingWithState:objects:count:"),1399/// &enumState,1400/// (id *)__rw_items, (unsigned int)16)1401///1402void RewriteObjC::SynthCountByEnumWithState(std::string &buf) {1403buf += "((unsigned int (*) (id, SEL, struct __objcFastEnumerationState *, "1404"id *, unsigned int))(void *)objc_msgSend)";1405buf += "\n\t\t";1406buf += "((id)l_collection,\n\t\t";1407buf += "sel_registerName(\"countByEnumeratingWithState:objects:count:\"),";1408buf += "\n\t\t";1409buf += "&enumState, "1410"(id *)__rw_items, (unsigned int)16)";1411}14121413/// RewriteBreakStmt - Rewrite for a break-stmt inside an ObjC2's foreach1414/// statement to exit to its outer synthesized loop.1415///1416Stmt *RewriteObjC::RewriteBreakStmt(BreakStmt *S) {1417if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back()))1418return S;1419// replace break with goto __break_label1420std::string buf;14211422SourceLocation startLoc = S->getBeginLoc();1423buf = "goto __break_label_";1424buf += utostr(ObjCBcLabelNo.back());1425ReplaceText(startLoc, strlen("break"), buf);14261427return nullptr;1428}14291430/// RewriteContinueStmt - Rewrite for a continue-stmt inside an ObjC2's foreach1431/// statement to continue with its inner synthesized loop.1432///1433Stmt *RewriteObjC::RewriteContinueStmt(ContinueStmt *S) {1434if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back()))1435return S;1436// replace continue with goto __continue_label1437std::string buf;14381439SourceLocation startLoc = S->getBeginLoc();1440buf = "goto __continue_label_";1441buf += utostr(ObjCBcLabelNo.back());1442ReplaceText(startLoc, strlen("continue"), buf);14431444return nullptr;1445}14461447/// RewriteObjCForCollectionStmt - Rewriter for ObjC2's foreach statement.1448/// It rewrites:1449/// for ( type elem in collection) { stmts; }14501451/// Into:1452/// {1453/// type elem;1454/// struct __objcFastEnumerationState enumState = { 0 };1455/// id __rw_items[16];1456/// id l_collection = (id)collection;1457/// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState1458/// objects:__rw_items count:16];1459/// if (limit) {1460/// unsigned long startMutations = *enumState.mutationsPtr;1461/// do {1462/// unsigned long counter = 0;1463/// do {1464/// if (startMutations != *enumState.mutationsPtr)1465/// objc_enumerationMutation(l_collection);1466/// elem = (type)enumState.itemsPtr[counter++];1467/// stmts;1468/// __continue_label: ;1469/// } while (counter < limit);1470/// } while (limit = [l_collection countByEnumeratingWithState:&enumState1471/// objects:__rw_items count:16]);1472/// elem = nil;1473/// __break_label: ;1474/// }1475/// else1476/// elem = nil;1477/// }1478///1479Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,1480SourceLocation OrigEnd) {1481assert(!Stmts.empty() && "ObjCForCollectionStmt - Statement stack empty");1482assert(isa<ObjCForCollectionStmt>(Stmts.back()) &&1483"ObjCForCollectionStmt Statement stack mismatch");1484assert(!ObjCBcLabelNo.empty() &&1485"ObjCForCollectionStmt - Label No stack empty");14861487SourceLocation startLoc = S->getBeginLoc();1488const char *startBuf = SM->getCharacterData(startLoc);1489StringRef elementName;1490std::string elementTypeAsString;1491std::string buf;1492buf = "\n{\n\t";1493if (DeclStmt *DS = dyn_cast<DeclStmt>(S->getElement())) {1494// type elem;1495NamedDecl* D = cast<NamedDecl>(DS->getSingleDecl());1496QualType ElementType = cast<ValueDecl>(D)->getType();1497if (ElementType->isObjCQualifiedIdType() ||1498ElementType->isObjCQualifiedInterfaceType())1499// Simply use 'id' for all qualified types.1500elementTypeAsString = "id";1501else1502elementTypeAsString = ElementType.getAsString(Context->getPrintingPolicy());1503buf += elementTypeAsString;1504buf += " ";1505elementName = D->getName();1506buf += elementName;1507buf += ";\n\t";1508}1509else {1510DeclRefExpr *DR = cast<DeclRefExpr>(S->getElement());1511elementName = DR->getDecl()->getName();1512ValueDecl *VD = DR->getDecl();1513if (VD->getType()->isObjCQualifiedIdType() ||1514VD->getType()->isObjCQualifiedInterfaceType())1515// Simply use 'id' for all qualified types.1516elementTypeAsString = "id";1517else1518elementTypeAsString = VD->getType().getAsString(Context->getPrintingPolicy());1519}15201521// struct __objcFastEnumerationState enumState = { 0 };1522buf += "struct __objcFastEnumerationState enumState = { 0 };\n\t";1523// id __rw_items[16];1524buf += "id __rw_items[16];\n\t";1525// id l_collection = (id)1526buf += "id l_collection = (id)";1527// Find start location of 'collection' the hard way!1528const char *startCollectionBuf = startBuf;1529startCollectionBuf += 3; // skip 'for'1530startCollectionBuf = strchr(startCollectionBuf, '(');1531startCollectionBuf++; // skip '('1532// find 'in' and skip it.1533while (*startCollectionBuf != ' ' ||1534*(startCollectionBuf+1) != 'i' || *(startCollectionBuf+2) != 'n' ||1535(*(startCollectionBuf+3) != ' ' &&1536*(startCollectionBuf+3) != '[' && *(startCollectionBuf+3) != '('))1537startCollectionBuf++;1538startCollectionBuf += 3;15391540// Replace: "for (type element in" with string constructed thus far.1541ReplaceText(startLoc, startCollectionBuf - startBuf, buf);1542// Replace ')' in for '(' type elem in collection ')' with ';'1543SourceLocation rightParenLoc = S->getRParenLoc();1544const char *rparenBuf = SM->getCharacterData(rightParenLoc);1545SourceLocation lparenLoc = startLoc.getLocWithOffset(rparenBuf-startBuf);1546buf = ";\n\t";15471548// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState1549// objects:__rw_items count:16];1550// which is synthesized into:1551// unsigned int limit =1552// ((unsigned int (*)1553// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))1554// (void *)objc_msgSend)((id)l_collection,1555// sel_registerName(1556// "countByEnumeratingWithState:objects:count:"),1557// (struct __objcFastEnumerationState *)&state,1558// (id *)__rw_items, (unsigned int)16);1559buf += "unsigned long limit =\n\t\t";1560SynthCountByEnumWithState(buf);1561buf += ";\n\t";1562/// if (limit) {1563/// unsigned long startMutations = *enumState.mutationsPtr;1564/// do {1565/// unsigned long counter = 0;1566/// do {1567/// if (startMutations != *enumState.mutationsPtr)1568/// objc_enumerationMutation(l_collection);1569/// elem = (type)enumState.itemsPtr[counter++];1570buf += "if (limit) {\n\t";1571buf += "unsigned long startMutations = *enumState.mutationsPtr;\n\t";1572buf += "do {\n\t\t";1573buf += "unsigned long counter = 0;\n\t\t";1574buf += "do {\n\t\t\t";1575buf += "if (startMutations != *enumState.mutationsPtr)\n\t\t\t\t";1576buf += "objc_enumerationMutation(l_collection);\n\t\t\t";1577buf += elementName;1578buf += " = (";1579buf += elementTypeAsString;1580buf += ")enumState.itemsPtr[counter++];";1581// Replace ')' in for '(' type elem in collection ')' with all of these.1582ReplaceText(lparenLoc, 1, buf);15831584/// __continue_label: ;1585/// } while (counter < limit);1586/// } while (limit = [l_collection countByEnumeratingWithState:&enumState1587/// objects:__rw_items count:16]);1588/// elem = nil;1589/// __break_label: ;1590/// }1591/// else1592/// elem = nil;1593/// }1594///1595buf = ";\n\t";1596buf += "__continue_label_";1597buf += utostr(ObjCBcLabelNo.back());1598buf += ": ;";1599buf += "\n\t\t";1600buf += "} while (counter < limit);\n\t";1601buf += "} while (limit = ";1602SynthCountByEnumWithState(buf);1603buf += ");\n\t";1604buf += elementName;1605buf += " = ((";1606buf += elementTypeAsString;1607buf += ")0);\n\t";1608buf += "__break_label_";1609buf += utostr(ObjCBcLabelNo.back());1610buf += ": ;\n\t";1611buf += "}\n\t";1612buf += "else\n\t\t";1613buf += elementName;1614buf += " = ((";1615buf += elementTypeAsString;1616buf += ")0);\n\t";1617buf += "}\n";16181619// Insert all these *after* the statement body.1620// FIXME: If this should support Obj-C++, support CXXTryStmt1621if (isa<CompoundStmt>(S->getBody())) {1622SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(1);1623InsertText(endBodyLoc, buf);1624} else {1625/* Need to treat single statements specially. For example:1626*1627* for (A *a in b) if (stuff()) break;1628* for (A *a in b) xxxyy;1629*1630* The following code simply scans ahead to the semi to find the actual end.1631*/1632const char *stmtBuf = SM->getCharacterData(OrigEnd);1633const char *semiBuf = strchr(stmtBuf, ';');1634assert(semiBuf && "Can't find ';'");1635SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(semiBuf-stmtBuf+1);1636InsertText(endBodyLoc, buf);1637}1638Stmts.pop_back();1639ObjCBcLabelNo.pop_back();1640return nullptr;1641}16421643/// RewriteObjCSynchronizedStmt -1644/// This routine rewrites @synchronized(expr) stmt;1645/// into:1646/// objc_sync_enter(expr);1647/// @try stmt @finally { objc_sync_exit(expr); }1648///1649Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {1650// Get the start location and compute the semi location.1651SourceLocation startLoc = S->getBeginLoc();1652const char *startBuf = SM->getCharacterData(startLoc);16531654assert((*startBuf == '@') && "bogus @synchronized location");16551656std::string buf;1657buf = "objc_sync_enter((id)";1658const char *lparenBuf = startBuf;1659while (*lparenBuf != '(') lparenBuf++;1660ReplaceText(startLoc, lparenBuf-startBuf+1, buf);1661// We can't use S->getSynchExpr()->getEndLoc() to find the end location, since1662// the sync expression is typically a message expression that's already1663// been rewritten! (which implies the SourceLocation's are invalid).1664SourceLocation endLoc = S->getSynchBody()->getBeginLoc();1665const char *endBuf = SM->getCharacterData(endLoc);1666while (*endBuf != ')') endBuf--;1667SourceLocation rparenLoc = startLoc.getLocWithOffset(endBuf-startBuf);1668buf = ");\n";1669// declare a new scope with two variables, _stack and _rethrow.1670buf += "/* @try scope begin */ \n{ struct _objc_exception_data {\n";1671buf += "int buf[18/*32-bit i386*/];\n";1672buf += "char *pointers[4];} _stack;\n";1673buf += "id volatile _rethrow = 0;\n";1674buf += "objc_exception_try_enter(&_stack);\n";1675buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";1676ReplaceText(rparenLoc, 1, buf);1677startLoc = S->getSynchBody()->getEndLoc();1678startBuf = SM->getCharacterData(startLoc);16791680assert((*startBuf == '}') && "bogus @synchronized block");1681SourceLocation lastCurlyLoc = startLoc;1682buf = "}\nelse {\n";1683buf += " _rethrow = objc_exception_extract(&_stack);\n";1684buf += "}\n";1685buf += "{ /* implicit finally clause */\n";1686buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n";16871688std::string syncBuf;1689syncBuf += " objc_sync_exit(";16901691Expr *syncExpr = S->getSynchExpr();1692CastKind CK = syncExpr->getType()->isObjCObjectPointerType()1693? CK_BitCast :1694syncExpr->getType()->isBlockPointerType()1695? CK_BlockPointerToObjCPointerCast1696: CK_CPointerToObjCPointerCast;1697syncExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),1698CK, syncExpr);1699std::string syncExprBufS;1700llvm::raw_string_ostream syncExprBuf(syncExprBufS);1701assert(syncExpr != nullptr && "Expected non-null Expr");1702syncExpr->printPretty(syncExprBuf, nullptr, PrintingPolicy(LangOpts));1703syncBuf += syncExprBuf.str();1704syncBuf += ");";17051706buf += syncBuf;1707buf += "\n if (_rethrow) objc_exception_throw(_rethrow);\n";1708buf += "}\n";1709buf += "}";17101711ReplaceText(lastCurlyLoc, 1, buf);17121713bool hasReturns = false;1714HasReturnStmts(S->getSynchBody(), hasReturns);1715if (hasReturns)1716RewriteSyncReturnStmts(S->getSynchBody(), syncBuf);17171718return nullptr;1719}17201721void RewriteObjC::WarnAboutReturnGotoStmts(Stmt *S)1722{1723// Perform a bottom up traversal of all children.1724for (Stmt *SubStmt : S->children())1725if (SubStmt)1726WarnAboutReturnGotoStmts(SubStmt);17271728if (isa<ReturnStmt>(S) || isa<GotoStmt>(S)) {1729Diags.Report(Context->getFullLoc(S->getBeginLoc()),1730TryFinallyContainsReturnDiag);1731}1732}17331734void RewriteObjC::HasReturnStmts(Stmt *S, bool &hasReturns)1735{1736// Perform a bottom up traversal of all children.1737for (Stmt *SubStmt : S->children())1738if (SubStmt)1739HasReturnStmts(SubStmt, hasReturns);17401741if (isa<ReturnStmt>(S))1742hasReturns = true;1743}17441745void RewriteObjC::RewriteTryReturnStmts(Stmt *S) {1746// Perform a bottom up traversal of all children.1747for (Stmt *SubStmt : S->children())1748if (SubStmt) {1749RewriteTryReturnStmts(SubStmt);1750}1751if (isa<ReturnStmt>(S)) {1752SourceLocation startLoc = S->getBeginLoc();1753const char *startBuf = SM->getCharacterData(startLoc);1754const char *semiBuf = strchr(startBuf, ';');1755assert((*semiBuf == ';') && "RewriteTryReturnStmts: can't find ';'");1756SourceLocation onePastSemiLoc = startLoc.getLocWithOffset(semiBuf-startBuf+1);17571758std::string buf;1759buf = "{ objc_exception_try_exit(&_stack); return";17601761ReplaceText(startLoc, 6, buf);1762InsertText(onePastSemiLoc, "}");1763}1764}17651766void RewriteObjC::RewriteSyncReturnStmts(Stmt *S, std::string syncExitBuf) {1767// Perform a bottom up traversal of all children.1768for (Stmt *SubStmt : S->children())1769if (SubStmt) {1770RewriteSyncReturnStmts(SubStmt, syncExitBuf);1771}1772if (isa<ReturnStmt>(S)) {1773SourceLocation startLoc = S->getBeginLoc();1774const char *startBuf = SM->getCharacterData(startLoc);17751776const char *semiBuf = strchr(startBuf, ';');1777assert((*semiBuf == ';') && "RewriteSyncReturnStmts: can't find ';'");1778SourceLocation onePastSemiLoc = startLoc.getLocWithOffset(semiBuf-startBuf+1);17791780std::string buf;1781buf = "{ objc_exception_try_exit(&_stack);";1782buf += syncExitBuf;1783buf += " return";17841785ReplaceText(startLoc, 6, buf);1786InsertText(onePastSemiLoc, "}");1787}1788}17891790Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {1791// Get the start location and compute the semi location.1792SourceLocation startLoc = S->getBeginLoc();1793const char *startBuf = SM->getCharacterData(startLoc);17941795assert((*startBuf == '@') && "bogus @try location");17961797std::string buf;1798// declare a new scope with two variables, _stack and _rethrow.1799buf = "/* @try scope begin */ { struct _objc_exception_data {\n";1800buf += "int buf[18/*32-bit i386*/];\n";1801buf += "char *pointers[4];} _stack;\n";1802buf += "id volatile _rethrow = 0;\n";1803buf += "objc_exception_try_enter(&_stack);\n";1804buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";18051806ReplaceText(startLoc, 4, buf);18071808startLoc = S->getTryBody()->getEndLoc();1809startBuf = SM->getCharacterData(startLoc);18101811assert((*startBuf == '}') && "bogus @try block");18121813SourceLocation lastCurlyLoc = startLoc;1814if (S->getNumCatchStmts()) {1815startLoc = startLoc.getLocWithOffset(1);1816buf = " /* @catch begin */ else {\n";1817buf += " id _caught = objc_exception_extract(&_stack);\n";1818buf += " objc_exception_try_enter (&_stack);\n";1819buf += " if (_setjmp(_stack.buf))\n";1820buf += " _rethrow = objc_exception_extract(&_stack);\n";1821buf += " else { /* @catch continue */";18221823InsertText(startLoc, buf);1824} else { /* no catch list */1825buf = "}\nelse {\n";1826buf += " _rethrow = objc_exception_extract(&_stack);\n";1827buf += "}";1828ReplaceText(lastCurlyLoc, 1, buf);1829}1830Stmt *lastCatchBody = nullptr;1831for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) {1832ObjCAtCatchStmt *Catch = S->getCatchStmt(I);1833VarDecl *catchDecl = Catch->getCatchParamDecl();18341835if (I == 0)1836buf = "if ("; // we are generating code for the first catch clause1837else1838buf = "else if (";1839startLoc = Catch->getBeginLoc();1840startBuf = SM->getCharacterData(startLoc);18411842assert((*startBuf == '@') && "bogus @catch location");18431844const char *lParenLoc = strchr(startBuf, '(');18451846if (Catch->hasEllipsis()) {1847// Now rewrite the body...1848lastCatchBody = Catch->getCatchBody();1849SourceLocation bodyLoc = lastCatchBody->getBeginLoc();1850const char *bodyBuf = SM->getCharacterData(bodyLoc);1851assert(*SM->getCharacterData(Catch->getRParenLoc()) == ')' &&1852"bogus @catch paren location");1853assert((*bodyBuf == '{') && "bogus @catch body location");18541855buf += "1) { id _tmp = _caught;";1856Rewrite.ReplaceText(startLoc, bodyBuf-startBuf+1, buf);1857} else if (catchDecl) {1858QualType t = catchDecl->getType();1859if (t == Context->getObjCIdType()) {1860buf += "1) { ";1861ReplaceText(startLoc, lParenLoc-startBuf+1, buf);1862} else if (const ObjCObjectPointerType *Ptr =1863t->getAs<ObjCObjectPointerType>()) {1864// Should be a pointer to a class.1865ObjCInterfaceDecl *IDecl = Ptr->getObjectType()->getInterface();1866if (IDecl) {1867buf += "objc_exception_match((struct objc_class *)objc_getClass(\"";1868buf += IDecl->getNameAsString();1869buf += "\"), (struct objc_object *)_caught)) { ";1870ReplaceText(startLoc, lParenLoc-startBuf+1, buf);1871}1872}1873// Now rewrite the body...1874lastCatchBody = Catch->getCatchBody();1875SourceLocation rParenLoc = Catch->getRParenLoc();1876SourceLocation bodyLoc = lastCatchBody->getBeginLoc();1877const char *bodyBuf = SM->getCharacterData(bodyLoc);1878const char *rParenBuf = SM->getCharacterData(rParenLoc);1879assert((*rParenBuf == ')') && "bogus @catch paren location");1880assert((*bodyBuf == '{') && "bogus @catch body location");18811882// Here we replace ") {" with "= _caught;" (which initializes and1883// declares the @catch parameter).1884ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, " = _caught;");1885} else {1886llvm_unreachable("@catch rewrite bug");1887}1888}1889// Complete the catch list...1890if (lastCatchBody) {1891SourceLocation bodyLoc = lastCatchBody->getEndLoc();1892assert(*SM->getCharacterData(bodyLoc) == '}' &&1893"bogus @catch body location");18941895// Insert the last (implicit) else clause *before* the right curly brace.1896bodyLoc = bodyLoc.getLocWithOffset(-1);1897buf = "} /* last catch end */\n";1898buf += "else {\n";1899buf += " _rethrow = _caught;\n";1900buf += " objc_exception_try_exit(&_stack);\n";1901buf += "} } /* @catch end */\n";1902if (!S->getFinallyStmt())1903buf += "}\n";1904InsertText(bodyLoc, buf);19051906// Set lastCurlyLoc1907lastCurlyLoc = lastCatchBody->getEndLoc();1908}1909if (ObjCAtFinallyStmt *finalStmt = S->getFinallyStmt()) {1910startLoc = finalStmt->getBeginLoc();1911startBuf = SM->getCharacterData(startLoc);1912assert((*startBuf == '@') && "bogus @finally start");19131914ReplaceText(startLoc, 8, "/* @finally */");19151916Stmt *body = finalStmt->getFinallyBody();1917SourceLocation startLoc = body->getBeginLoc();1918SourceLocation endLoc = body->getEndLoc();1919assert(*SM->getCharacterData(startLoc) == '{' &&1920"bogus @finally body location");1921assert(*SM->getCharacterData(endLoc) == '}' &&1922"bogus @finally body location");19231924startLoc = startLoc.getLocWithOffset(1);1925InsertText(startLoc, " if (!_rethrow) objc_exception_try_exit(&_stack);\n");1926endLoc = endLoc.getLocWithOffset(-1);1927InsertText(endLoc, " if (_rethrow) objc_exception_throw(_rethrow);\n");19281929// Set lastCurlyLoc1930lastCurlyLoc = body->getEndLoc();19311932// Now check for any return/continue/go statements within the @try.1933WarnAboutReturnGotoStmts(S->getTryBody());1934} else { /* no finally clause - make sure we synthesize an implicit one */1935buf = "{ /* implicit finally clause */\n";1936buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n";1937buf += " if (_rethrow) objc_exception_throw(_rethrow);\n";1938buf += "}";1939ReplaceText(lastCurlyLoc, 1, buf);19401941// Now check for any return/continue/go statements within the @try.1942// The implicit finally clause won't called if the @try contains any1943// jump statements.1944bool hasReturns = false;1945HasReturnStmts(S->getTryBody(), hasReturns);1946if (hasReturns)1947RewriteTryReturnStmts(S->getTryBody());1948}1949// Now emit the final closing curly brace...1950lastCurlyLoc = lastCurlyLoc.getLocWithOffset(1);1951InsertText(lastCurlyLoc, " } /* @try scope end */\n");1952return nullptr;1953}19541955// This can't be done with ReplaceStmt(S, ThrowExpr), since1956// the throw expression is typically a message expression that's already1957// been rewritten! (which implies the SourceLocation's are invalid).1958Stmt *RewriteObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) {1959// Get the start location and compute the semi location.1960SourceLocation startLoc = S->getBeginLoc();1961const char *startBuf = SM->getCharacterData(startLoc);19621963assert((*startBuf == '@') && "bogus @throw location");19641965std::string buf;1966/* void objc_exception_throw(id) __attribute__((noreturn)); */1967if (S->getThrowExpr())1968buf = "objc_exception_throw(";1969else // add an implicit argument1970buf = "objc_exception_throw(_caught";19711972// handle "@ throw" correctly.1973const char *wBuf = strchr(startBuf, 'w');1974assert((*wBuf == 'w') && "@throw: can't find 'w'");1975ReplaceText(startLoc, wBuf-startBuf+1, buf);19761977const char *semiBuf = strchr(startBuf, ';');1978assert((*semiBuf == ';') && "@throw: can't find ';'");1979SourceLocation semiLoc = startLoc.getLocWithOffset(semiBuf-startBuf);1980ReplaceText(semiLoc, 1, ");");1981return nullptr;1982}19831984Stmt *RewriteObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) {1985// Create a new string expression.1986std::string StrEncoding;1987Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding);1988Expr *Replacement = getStringLiteral(StrEncoding);1989ReplaceStmt(Exp, Replacement);19901991// Replace this subexpr in the parent.1992// delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.1993return Replacement;1994}19951996Stmt *RewriteObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) {1997if (!SelGetUidFunctionDecl)1998SynthSelGetUidFunctionDecl();1999assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");2000// Create a call to sel_registerName("selName").2001SmallVector<Expr*, 8> SelExprs;2002SelExprs.push_back(getStringLiteral(Exp->getSelector().getAsString()));2003CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,2004SelExprs);2005ReplaceStmt(Exp, SelExp);2006// delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.2007return SelExp;2008}20092010CallExpr *2011RewriteObjC::SynthesizeCallToFunctionDecl(FunctionDecl *FD,2012ArrayRef<Expr *> Args,2013SourceLocation StartLoc,2014SourceLocation EndLoc) {2015// Get the type, we will need to reference it in a couple spots.2016QualType msgSendType = FD->getType();20172018// Create a reference to the objc_msgSend() declaration.2019DeclRefExpr *DRE = new (Context) DeclRefExpr(*Context, FD, false, msgSendType,2020VK_LValue, SourceLocation());20212022// Now, we cast the reference to a pointer to the objc_msgSend type.2023QualType pToFunc = Context->getPointerType(msgSendType);2024ImplicitCastExpr *ICE =2025ImplicitCastExpr::Create(*Context, pToFunc, CK_FunctionToPointerDecay,2026DRE, nullptr, VK_PRValue, FPOptionsOverride());20272028const auto *FT = msgSendType->castAs<FunctionType>();20292030CallExpr *Exp =2031CallExpr::Create(*Context, ICE, Args, FT->getCallResultType(*Context),2032VK_PRValue, EndLoc, FPOptionsOverride());2033return Exp;2034}20352036static bool scanForProtocolRefs(const char *startBuf, const char *endBuf,2037const char *&startRef, const char *&endRef) {2038while (startBuf < endBuf) {2039if (*startBuf == '<')2040startRef = startBuf; // mark the start.2041if (*startBuf == '>') {2042if (startRef && *startRef == '<') {2043endRef = startBuf; // mark the end.2044return true;2045}2046return false;2047}2048startBuf++;2049}2050return false;2051}20522053static void scanToNextArgument(const char *&argRef) {2054int angle = 0;2055while (*argRef != ')' && (*argRef != ',' || angle > 0)) {2056if (*argRef == '<')2057angle++;2058else if (*argRef == '>')2059angle--;2060argRef++;2061}2062assert(angle == 0 && "scanToNextArgument - bad protocol type syntax");2063}20642065bool RewriteObjC::needToScanForQualifiers(QualType T) {2066if (T->isObjCQualifiedIdType())2067return true;2068if (const PointerType *PT = T->getAs<PointerType>()) {2069if (PT->getPointeeType()->isObjCQualifiedIdType())2070return true;2071}2072if (T->isObjCObjectPointerType()) {2073T = T->getPointeeType();2074return T->isObjCQualifiedInterfaceType();2075}2076if (T->isArrayType()) {2077QualType ElemTy = Context->getBaseElementType(T);2078return needToScanForQualifiers(ElemTy);2079}2080return false;2081}20822083void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) {2084QualType Type = E->getType();2085if (needToScanForQualifiers(Type)) {2086SourceLocation Loc, EndLoc;20872088if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E)) {2089Loc = ECE->getLParenLoc();2090EndLoc = ECE->getRParenLoc();2091} else {2092Loc = E->getBeginLoc();2093EndLoc = E->getEndLoc();2094}2095// This will defend against trying to rewrite synthesized expressions.2096if (Loc.isInvalid() || EndLoc.isInvalid())2097return;20982099const char *startBuf = SM->getCharacterData(Loc);2100const char *endBuf = SM->getCharacterData(EndLoc);2101const char *startRef = nullptr, *endRef = nullptr;2102if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {2103// Get the locations of the startRef, endRef.2104SourceLocation LessLoc = Loc.getLocWithOffset(startRef-startBuf);2105SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-startBuf+1);2106// Comment out the protocol references.2107InsertText(LessLoc, "/*");2108InsertText(GreaterLoc, "*/");2109}2110}2111}21122113void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {2114SourceLocation Loc;2115QualType Type;2116const FunctionProtoType *proto = nullptr;2117if (VarDecl *VD = dyn_cast<VarDecl>(Dcl)) {2118Loc = VD->getLocation();2119Type = VD->getType();2120}2121else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Dcl)) {2122Loc = FD->getLocation();2123// Check for ObjC 'id' and class types that have been adorned with protocol2124// information (id<p>, C<p>*). The protocol references need to be rewritten!2125const FunctionType *funcType = FD->getType()->getAs<FunctionType>();2126assert(funcType && "missing function type");2127proto = dyn_cast<FunctionProtoType>(funcType);2128if (!proto)2129return;2130Type = proto->getReturnType();2131}2132else if (FieldDecl *FD = dyn_cast<FieldDecl>(Dcl)) {2133Loc = FD->getLocation();2134Type = FD->getType();2135}2136else2137return;21382139if (needToScanForQualifiers(Type)) {2140// Since types are unique, we need to scan the buffer.21412142const char *endBuf = SM->getCharacterData(Loc);2143const char *startBuf = endBuf;2144while (*startBuf != ';' && *startBuf != '<' && startBuf != MainFileStart)2145startBuf--; // scan backward (from the decl location) for return type.2146const char *startRef = nullptr, *endRef = nullptr;2147if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {2148// Get the locations of the startRef, endRef.2149SourceLocation LessLoc = Loc.getLocWithOffset(startRef-endBuf);2150SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-endBuf+1);2151// Comment out the protocol references.2152InsertText(LessLoc, "/*");2153InsertText(GreaterLoc, "*/");2154}2155}2156if (!proto)2157return; // most likely, was a variable2158// Now check arguments.2159const char *startBuf = SM->getCharacterData(Loc);2160const char *startFuncBuf = startBuf;2161for (unsigned i = 0; i < proto->getNumParams(); i++) {2162if (needToScanForQualifiers(proto->getParamType(i))) {2163// Since types are unique, we need to scan the buffer.21642165const char *endBuf = startBuf;2166// scan forward (from the decl location) for argument types.2167scanToNextArgument(endBuf);2168const char *startRef = nullptr, *endRef = nullptr;2169if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {2170// Get the locations of the startRef, endRef.2171SourceLocation LessLoc =2172Loc.getLocWithOffset(startRef-startFuncBuf);2173SourceLocation GreaterLoc =2174Loc.getLocWithOffset(endRef-startFuncBuf+1);2175// Comment out the protocol references.2176InsertText(LessLoc, "/*");2177InsertText(GreaterLoc, "*/");2178}2179startBuf = ++endBuf;2180}2181else {2182// If the function name is derived from a macro expansion, then the2183// argument buffer will not follow the name. Need to speak with Chris.2184while (*startBuf && *startBuf != ')' && *startBuf != ',')2185startBuf++; // scan forward (from the decl location) for argument types.2186startBuf++;2187}2188}2189}21902191void RewriteObjC::RewriteTypeOfDecl(VarDecl *ND) {2192QualType QT = ND->getType();2193const Type* TypePtr = QT->getAs<Type>();2194if (!isa<TypeOfExprType>(TypePtr))2195return;2196while (isa<TypeOfExprType>(TypePtr)) {2197const TypeOfExprType *TypeOfExprTypePtr = cast<TypeOfExprType>(TypePtr);2198QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType();2199TypePtr = QT->getAs<Type>();2200}2201// FIXME. This will not work for multiple declarators; as in:2202// __typeof__(a) b,c,d;2203std::string TypeAsString(QT.getAsString(Context->getPrintingPolicy()));2204SourceLocation DeclLoc = ND->getTypeSpecStartLoc();2205const char *startBuf = SM->getCharacterData(DeclLoc);2206if (ND->getInit()) {2207std::string Name(ND->getNameAsString());2208TypeAsString += " " + Name + " = ";2209Expr *E = ND->getInit();2210SourceLocation startLoc;2211if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E))2212startLoc = ECE->getLParenLoc();2213else2214startLoc = E->getBeginLoc();2215startLoc = SM->getExpansionLoc(startLoc);2216const char *endBuf = SM->getCharacterData(startLoc);2217ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString);2218}2219else {2220SourceLocation X = ND->getEndLoc();2221X = SM->getExpansionLoc(X);2222const char *endBuf = SM->getCharacterData(X);2223ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString);2224}2225}22262227// SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str);2228void RewriteObjC::SynthSelGetUidFunctionDecl() {2229IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName");2230SmallVector<QualType, 16> ArgTys;2231ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));2232QualType getFuncType =2233getSimpleFunctionType(Context->getObjCSelType(), ArgTys);2234SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl,2235SourceLocation(),2236SourceLocation(),2237SelGetUidIdent, getFuncType,2238nullptr, SC_Extern);2239}22402241void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) {2242// declared in <objc/objc.h>2243if (FD->getIdentifier() &&2244FD->getName() == "sel_registerName") {2245SelGetUidFunctionDecl = FD;2246return;2247}2248RewriteObjCQualifiedInterfaceTypes(FD);2249}22502251void RewriteObjC::RewriteBlockPointerType(std::string& Str, QualType Type) {2252std::string TypeString(Type.getAsString(Context->getPrintingPolicy()));2253const char *argPtr = TypeString.c_str();2254if (!strchr(argPtr, '^')) {2255Str += TypeString;2256return;2257}2258while (*argPtr) {2259Str += (*argPtr == '^' ? '*' : *argPtr);2260argPtr++;2261}2262}22632264// FIXME. Consolidate this routine with RewriteBlockPointerType.2265void RewriteObjC::RewriteBlockPointerTypeVariable(std::string& Str,2266ValueDecl *VD) {2267QualType Type = VD->getType();2268std::string TypeString(Type.getAsString(Context->getPrintingPolicy()));2269const char *argPtr = TypeString.c_str();2270int paren = 0;2271while (*argPtr) {2272switch (*argPtr) {2273case '(':2274Str += *argPtr;2275paren++;2276break;2277case ')':2278Str += *argPtr;2279paren--;2280break;2281case '^':2282Str += '*';2283if (paren == 1)2284Str += VD->getNameAsString();2285break;2286default:2287Str += *argPtr;2288break;2289}2290argPtr++;2291}2292}22932294void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) {2295SourceLocation FunLocStart = FD->getTypeSpecStartLoc();2296const FunctionType *funcType = FD->getType()->getAs<FunctionType>();2297const FunctionProtoType *proto = dyn_cast_or_null<FunctionProtoType>(funcType);2298if (!proto)2299return;2300QualType Type = proto->getReturnType();2301std::string FdStr = Type.getAsString(Context->getPrintingPolicy());2302FdStr += " ";2303FdStr += FD->getName();2304FdStr += "(";2305unsigned numArgs = proto->getNumParams();2306for (unsigned i = 0; i < numArgs; i++) {2307QualType ArgType = proto->getParamType(i);2308RewriteBlockPointerType(FdStr, ArgType);2309if (i+1 < numArgs)2310FdStr += ", ";2311}2312FdStr += ");\n";2313InsertText(FunLocStart, FdStr);2314CurFunctionDeclToDeclareForBlock = nullptr;2315}23162317// SynthSuperConstructorFunctionDecl - id objc_super(id obj, id super);2318void RewriteObjC::SynthSuperConstructorFunctionDecl() {2319if (SuperConstructorFunctionDecl)2320return;2321IdentifierInfo *msgSendIdent = &Context->Idents.get("__rw_objc_super");2322SmallVector<QualType, 16> ArgTys;2323QualType argT = Context->getObjCIdType();2324assert(!argT.isNull() && "Can't find 'id' type");2325ArgTys.push_back(argT);2326ArgTys.push_back(argT);2327QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),2328ArgTys);2329SuperConstructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,2330SourceLocation(),2331SourceLocation(),2332msgSendIdent, msgSendType,2333nullptr, SC_Extern);2334}23352336// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);2337void RewriteObjC::SynthMsgSendFunctionDecl() {2338IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend");2339SmallVector<QualType, 16> ArgTys;2340QualType argT = Context->getObjCIdType();2341assert(!argT.isNull() && "Can't find 'id' type");2342ArgTys.push_back(argT);2343argT = Context->getObjCSelType();2344assert(!argT.isNull() && "Can't find 'SEL' type");2345ArgTys.push_back(argT);2346QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),2347ArgTys, /*variadic=*/true);2348MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl,2349SourceLocation(),2350SourceLocation(),2351msgSendIdent, msgSendType,2352nullptr, SC_Extern);2353}23542355// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...);2356void RewriteObjC::SynthMsgSendSuperFunctionDecl() {2357IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper");2358SmallVector<QualType, 16> ArgTys;2359RecordDecl *RD = RecordDecl::Create(*Context, TagTypeKind::Struct, TUDecl,2360SourceLocation(), SourceLocation(),2361&Context->Idents.get("objc_super"));2362QualType argT = Context->getPointerType(Context->getTagDeclType(RD));2363assert(!argT.isNull() && "Can't build 'struct objc_super *' type");2364ArgTys.push_back(argT);2365argT = Context->getObjCSelType();2366assert(!argT.isNull() && "Can't find 'SEL' type");2367ArgTys.push_back(argT);2368QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),2369ArgTys, /*variadic=*/true);2370MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl,2371SourceLocation(),2372SourceLocation(),2373msgSendIdent, msgSendType,2374nullptr, SC_Extern);2375}23762377// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...);2378void RewriteObjC::SynthMsgSendStretFunctionDecl() {2379IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_stret");2380SmallVector<QualType, 16> ArgTys;2381QualType argT = Context->getObjCIdType();2382assert(!argT.isNull() && "Can't find 'id' type");2383ArgTys.push_back(argT);2384argT = Context->getObjCSelType();2385assert(!argT.isNull() && "Can't find 'SEL' type");2386ArgTys.push_back(argT);2387QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),2388ArgTys, /*variadic=*/true);2389MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,2390SourceLocation(),2391SourceLocation(),2392msgSendIdent, msgSendType,2393nullptr, SC_Extern);2394}23952396// SynthMsgSendSuperStretFunctionDecl -2397// id objc_msgSendSuper_stret(struct objc_super *, SEL op, ...);2398void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() {2399IdentifierInfo *msgSendIdent =2400&Context->Idents.get("objc_msgSendSuper_stret");2401SmallVector<QualType, 16> ArgTys;2402RecordDecl *RD = RecordDecl::Create(*Context, TagTypeKind::Struct, TUDecl,2403SourceLocation(), SourceLocation(),2404&Context->Idents.get("objc_super"));2405QualType argT = Context->getPointerType(Context->getTagDeclType(RD));2406assert(!argT.isNull() && "Can't build 'struct objc_super *' type");2407ArgTys.push_back(argT);2408argT = Context->getObjCSelType();2409assert(!argT.isNull() && "Can't find 'SEL' type");2410ArgTys.push_back(argT);2411QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),2412ArgTys, /*variadic=*/true);2413MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,2414SourceLocation(),2415SourceLocation(),2416msgSendIdent,2417msgSendType, nullptr,2418SC_Extern);2419}24202421// SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...);2422void RewriteObjC::SynthMsgSendFpretFunctionDecl() {2423IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_fpret");2424SmallVector<QualType, 16> ArgTys;2425QualType argT = Context->getObjCIdType();2426assert(!argT.isNull() && "Can't find 'id' type");2427ArgTys.push_back(argT);2428argT = Context->getObjCSelType();2429assert(!argT.isNull() && "Can't find 'SEL' type");2430ArgTys.push_back(argT);2431QualType msgSendType = getSimpleFunctionType(Context->DoubleTy,2432ArgTys, /*variadic=*/true);2433MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,2434SourceLocation(),2435SourceLocation(),2436msgSendIdent, msgSendType,2437nullptr, SC_Extern);2438}24392440// SynthGetClassFunctionDecl - id objc_getClass(const char *name);2441void RewriteObjC::SynthGetClassFunctionDecl() {2442IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass");2443SmallVector<QualType, 16> ArgTys;2444ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));2445QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(),2446ArgTys);2447GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,2448SourceLocation(),2449SourceLocation(),2450getClassIdent, getClassType,2451nullptr, SC_Extern);2452}24532454// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls);2455void RewriteObjC::SynthGetSuperClassFunctionDecl() {2456IdentifierInfo *getSuperClassIdent =2457&Context->Idents.get("class_getSuperclass");2458SmallVector<QualType, 16> ArgTys;2459ArgTys.push_back(Context->getObjCClassType());2460QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(),2461ArgTys);2462GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,2463SourceLocation(),2464SourceLocation(),2465getSuperClassIdent,2466getClassType, nullptr,2467SC_Extern);2468}24692470// SynthGetMetaClassFunctionDecl - id objc_getMetaClass(const char *name);2471void RewriteObjC::SynthGetMetaClassFunctionDecl() {2472IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass");2473SmallVector<QualType, 16> ArgTys;2474ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));2475QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(),2476ArgTys);2477GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,2478SourceLocation(),2479SourceLocation(),2480getClassIdent, getClassType,2481nullptr, SC_Extern);2482}24832484Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {2485assert(Exp != nullptr && "Expected non-null ObjCStringLiteral");2486QualType strType = getConstantStringStructType();24872488std::string S = "__NSConstantStringImpl_";24892490std::string tmpName = InFileName;2491unsigned i;2492for (i=0; i < tmpName.length(); i++) {2493char c = tmpName.at(i);2494// replace any non-alphanumeric characters with '_'.2495if (!isAlphanumeric(c))2496tmpName[i] = '_';2497}2498S += tmpName;2499S += "_";2500S += utostr(NumObjCStringLiterals++);25012502Preamble += "static __NSConstantStringImpl " + S;2503Preamble += " __attribute__ ((section (\"__DATA, __cfstring\"))) = {__CFConstantStringClassReference,";2504Preamble += "0x000007c8,"; // utf8_str2505// The pretty printer for StringLiteral handles escape characters properly.2506std::string prettyBufS;2507llvm::raw_string_ostream prettyBuf(prettyBufS);2508Exp->getString()->printPretty(prettyBuf, nullptr, PrintingPolicy(LangOpts));2509Preamble += prettyBuf.str();2510Preamble += ",";2511Preamble += utostr(Exp->getString()->getByteLength()) + "};\n";25122513VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),2514SourceLocation(), &Context->Idents.get(S),2515strType, nullptr, SC_Static);2516DeclRefExpr *DRE = new (Context)2517DeclRefExpr(*Context, NewVD, false, strType, VK_LValue, SourceLocation());2518Expr *Unop = UnaryOperator::Create(2519const_cast<ASTContext &>(*Context), DRE, UO_AddrOf,2520Context->getPointerType(DRE->getType()), VK_PRValue, OK_Ordinary,2521SourceLocation(), false, FPOptionsOverride());2522// cast to NSConstantString *2523CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(),2524CK_CPointerToObjCPointerCast, Unop);2525ReplaceStmt(Exp, cast);2526// delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.2527return cast;2528}25292530// struct objc_super { struct objc_object *receiver; struct objc_class *super; };2531QualType RewriteObjC::getSuperStructType() {2532if (!SuperStructDecl) {2533SuperStructDecl = RecordDecl::Create(*Context, TagTypeKind::Struct, TUDecl,2534SourceLocation(), SourceLocation(),2535&Context->Idents.get("objc_super"));2536QualType FieldTypes[2];25372538// struct objc_object *receiver;2539FieldTypes[0] = Context->getObjCIdType();2540// struct objc_class *super;2541FieldTypes[1] = Context->getObjCClassType();25422543// Create fields2544for (unsigned i = 0; i < 2; ++i) {2545SuperStructDecl->addDecl(FieldDecl::Create(*Context, SuperStructDecl,2546SourceLocation(),2547SourceLocation(), nullptr,2548FieldTypes[i], nullptr,2549/*BitWidth=*/nullptr,2550/*Mutable=*/false,2551ICIS_NoInit));2552}25532554SuperStructDecl->completeDefinition();2555}2556return Context->getTagDeclType(SuperStructDecl);2557}25582559QualType RewriteObjC::getConstantStringStructType() {2560if (!ConstantStringDecl) {2561ConstantStringDecl = RecordDecl::Create(2562*Context, TagTypeKind::Struct, TUDecl, SourceLocation(),2563SourceLocation(), &Context->Idents.get("__NSConstantStringImpl"));2564QualType FieldTypes[4];25652566// struct objc_object *receiver;2567FieldTypes[0] = Context->getObjCIdType();2568// int flags;2569FieldTypes[1] = Context->IntTy;2570// char *str;2571FieldTypes[2] = Context->getPointerType(Context->CharTy);2572// long length;2573FieldTypes[3] = Context->LongTy;25742575// Create fields2576for (unsigned i = 0; i < 4; ++i) {2577ConstantStringDecl->addDecl(FieldDecl::Create(*Context,2578ConstantStringDecl,2579SourceLocation(),2580SourceLocation(), nullptr,2581FieldTypes[i], nullptr,2582/*BitWidth=*/nullptr,2583/*Mutable=*/true,2584ICIS_NoInit));2585}25862587ConstantStringDecl->completeDefinition();2588}2589return Context->getTagDeclType(ConstantStringDecl);2590}25912592CallExpr *RewriteObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor,2593QualType msgSendType,2594QualType returnType,2595SmallVectorImpl<QualType> &ArgTypes,2596SmallVectorImpl<Expr*> &MsgExprs,2597ObjCMethodDecl *Method) {2598// Create a reference to the objc_msgSend_stret() declaration.2599DeclRefExpr *STDRE =2600new (Context) DeclRefExpr(*Context, MsgSendStretFlavor, false,2601msgSendType, VK_LValue, SourceLocation());2602// Need to cast objc_msgSend_stret to "void *" (see above comment).2603CastExpr *cast = NoTypeInfoCStyleCastExpr(Context,2604Context->getPointerType(Context->VoidTy),2605CK_BitCast, STDRE);2606// Now do the "normal" pointer to function cast.2607QualType castType = getSimpleFunctionType(returnType, ArgTypes,2608Method ? Method->isVariadic()2609: false);2610castType = Context->getPointerType(castType);2611cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,2612cast);26132614// Don't forget the parens to enforce the proper binding.2615ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast);26162617const auto *FT = msgSendType->castAs<FunctionType>();2618CallExpr *STCE =2619CallExpr::Create(*Context, PE, MsgExprs, FT->getReturnType(), VK_PRValue,2620SourceLocation(), FPOptionsOverride());2621return STCE;2622}26232624Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,2625SourceLocation StartLoc,2626SourceLocation EndLoc) {2627if (!SelGetUidFunctionDecl)2628SynthSelGetUidFunctionDecl();2629if (!MsgSendFunctionDecl)2630SynthMsgSendFunctionDecl();2631if (!MsgSendSuperFunctionDecl)2632SynthMsgSendSuperFunctionDecl();2633if (!MsgSendStretFunctionDecl)2634SynthMsgSendStretFunctionDecl();2635if (!MsgSendSuperStretFunctionDecl)2636SynthMsgSendSuperStretFunctionDecl();2637if (!MsgSendFpretFunctionDecl)2638SynthMsgSendFpretFunctionDecl();2639if (!GetClassFunctionDecl)2640SynthGetClassFunctionDecl();2641if (!GetSuperClassFunctionDecl)2642SynthGetSuperClassFunctionDecl();2643if (!GetMetaClassFunctionDecl)2644SynthGetMetaClassFunctionDecl();26452646// default to objc_msgSend().2647FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl;2648// May need to use objc_msgSend_stret() as well.2649FunctionDecl *MsgSendStretFlavor = nullptr;2650if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) {2651QualType resultType = mDecl->getReturnType();2652if (resultType->isRecordType())2653MsgSendStretFlavor = MsgSendStretFunctionDecl;2654else if (resultType->isRealFloatingType())2655MsgSendFlavor = MsgSendFpretFunctionDecl;2656}26572658// Synthesize a call to objc_msgSend().2659SmallVector<Expr*, 8> MsgExprs;2660switch (Exp->getReceiverKind()) {2661case ObjCMessageExpr::SuperClass: {2662MsgSendFlavor = MsgSendSuperFunctionDecl;2663if (MsgSendStretFlavor)2664MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;2665assert(MsgSendFlavor && "MsgSendFlavor is NULL!");26662667ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();26682669SmallVector<Expr*, 4> InitExprs;26702671// set the receiver to self, the first argument to all methods.2672InitExprs.push_back(NoTypeInfoCStyleCastExpr(2673Context, Context->getObjCIdType(), CK_BitCast,2674new (Context) DeclRefExpr(*Context, CurMethodDef->getSelfDecl(), false,2675Context->getObjCIdType(), VK_PRValue,2676SourceLocation()))); // set the 'receiver'.26772678// (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))2679SmallVector<Expr*, 8> ClsExprs;2680ClsExprs.push_back(getStringLiteral(ClassDecl->getIdentifier()->getName()));2681CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,2682ClsExprs, StartLoc, EndLoc);2683// (Class)objc_getClass("CurrentClass")2684CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,2685Context->getObjCClassType(),2686CK_BitCast, Cls);2687ClsExprs.clear();2688ClsExprs.push_back(ArgExpr);2689Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, ClsExprs,2690StartLoc, EndLoc);2691// (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))2692// To turn off a warning, type-cast to 'id'2693InitExprs.push_back( // set 'super class', using class_getSuperclass().2694NoTypeInfoCStyleCastExpr(Context,2695Context->getObjCIdType(),2696CK_BitCast, Cls));2697// struct objc_super2698QualType superType = getSuperStructType();2699Expr *SuperRep;27002701if (LangOpts.MicrosoftExt) {2702SynthSuperConstructorFunctionDecl();2703// Simulate a constructor call...2704DeclRefExpr *DRE = new (Context)2705DeclRefExpr(*Context, SuperConstructorFunctionDecl, false, superType,2706VK_LValue, SourceLocation());2707SuperRep =2708CallExpr::Create(*Context, DRE, InitExprs, superType, VK_LValue,2709SourceLocation(), FPOptionsOverride());2710// The code for super is a little tricky to prevent collision with2711// the structure definition in the header. The rewriter has it's own2712// internal definition (__rw_objc_super) that is uses. This is why2713// we need the cast below. For example:2714// (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))2715//2716SuperRep = UnaryOperator::Create(2717const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,2718Context->getPointerType(SuperRep->getType()), VK_PRValue, OK_Ordinary,2719SourceLocation(), false, FPOptionsOverride());2720SuperRep = NoTypeInfoCStyleCastExpr(Context,2721Context->getPointerType(superType),2722CK_BitCast, SuperRep);2723} else {2724// (struct objc_super) { <exprs from above> }2725InitListExpr *ILE =2726new (Context) InitListExpr(*Context, SourceLocation(), InitExprs,2727SourceLocation());2728TypeSourceInfo *superTInfo2729= Context->getTrivialTypeSourceInfo(superType);2730SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo,2731superType, VK_LValue,2732ILE, false);2733// struct objc_super *2734SuperRep = UnaryOperator::Create(2735const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,2736Context->getPointerType(SuperRep->getType()), VK_PRValue, OK_Ordinary,2737SourceLocation(), false, FPOptionsOverride());2738}2739MsgExprs.push_back(SuperRep);2740break;2741}27422743case ObjCMessageExpr::Class: {2744SmallVector<Expr*, 8> ClsExprs;2745auto *Class =2746Exp->getClassReceiver()->castAs<ObjCObjectType>()->getInterface();2747IdentifierInfo *clsName = Class->getIdentifier();2748ClsExprs.push_back(getStringLiteral(clsName->getName()));2749CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, ClsExprs,2750StartLoc, EndLoc);2751MsgExprs.push_back(Cls);2752break;2753}27542755case ObjCMessageExpr::SuperInstance:{2756MsgSendFlavor = MsgSendSuperFunctionDecl;2757if (MsgSendStretFlavor)2758MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;2759assert(MsgSendFlavor && "MsgSendFlavor is NULL!");2760ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();2761SmallVector<Expr*, 4> InitExprs;27622763InitExprs.push_back(NoTypeInfoCStyleCastExpr(2764Context, Context->getObjCIdType(), CK_BitCast,2765new (Context) DeclRefExpr(*Context, CurMethodDef->getSelfDecl(), false,2766Context->getObjCIdType(), VK_PRValue,2767SourceLocation()))); // set the 'receiver'.27682769// (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))2770SmallVector<Expr*, 8> ClsExprs;2771ClsExprs.push_back(getStringLiteral(ClassDecl->getIdentifier()->getName()));2772CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, ClsExprs,2773StartLoc, EndLoc);2774// (Class)objc_getClass("CurrentClass")2775CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,2776Context->getObjCClassType(),2777CK_BitCast, Cls);2778ClsExprs.clear();2779ClsExprs.push_back(ArgExpr);2780Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, ClsExprs,2781StartLoc, EndLoc);27822783// (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))2784// To turn off a warning, type-cast to 'id'2785InitExprs.push_back(2786// set 'super class', using class_getSuperclass().2787NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),2788CK_BitCast, Cls));2789// struct objc_super2790QualType superType = getSuperStructType();2791Expr *SuperRep;27922793if (LangOpts.MicrosoftExt) {2794SynthSuperConstructorFunctionDecl();2795// Simulate a constructor call...2796DeclRefExpr *DRE = new (Context)2797DeclRefExpr(*Context, SuperConstructorFunctionDecl, false, superType,2798VK_LValue, SourceLocation());2799SuperRep =2800CallExpr::Create(*Context, DRE, InitExprs, superType, VK_LValue,2801SourceLocation(), FPOptionsOverride());2802// The code for super is a little tricky to prevent collision with2803// the structure definition in the header. The rewriter has it's own2804// internal definition (__rw_objc_super) that is uses. This is why2805// we need the cast below. For example:2806// (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))2807//2808SuperRep = UnaryOperator::Create(2809const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,2810Context->getPointerType(SuperRep->getType()), VK_PRValue, OK_Ordinary,2811SourceLocation(), false, FPOptionsOverride());2812SuperRep = NoTypeInfoCStyleCastExpr(Context,2813Context->getPointerType(superType),2814CK_BitCast, SuperRep);2815} else {2816// (struct objc_super) { <exprs from above> }2817InitListExpr *ILE =2818new (Context) InitListExpr(*Context, SourceLocation(), InitExprs,2819SourceLocation());2820TypeSourceInfo *superTInfo2821= Context->getTrivialTypeSourceInfo(superType);2822SuperRep = new (Context) CompoundLiteralExpr(2823SourceLocation(), superTInfo, superType, VK_PRValue, ILE, false);2824}2825MsgExprs.push_back(SuperRep);2826break;2827}28282829case ObjCMessageExpr::Instance: {2830// Remove all type-casts because it may contain objc-style types; e.g.2831// Foo<Proto> *.2832Expr *recExpr = Exp->getInstanceReceiver();2833while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr))2834recExpr = CE->getSubExpr();2835CastKind CK = recExpr->getType()->isObjCObjectPointerType()2836? CK_BitCast : recExpr->getType()->isBlockPointerType()2837? CK_BlockPointerToObjCPointerCast2838: CK_CPointerToObjCPointerCast;28392840recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),2841CK, recExpr);2842MsgExprs.push_back(recExpr);2843break;2844}2845}28462847// Create a call to sel_registerName("selName"), it will be the 2nd argument.2848SmallVector<Expr*, 8> SelExprs;2849SelExprs.push_back(getStringLiteral(Exp->getSelector().getAsString()));2850CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,2851SelExprs, StartLoc, EndLoc);2852MsgExprs.push_back(SelExp);28532854// Now push any user supplied arguments.2855for (unsigned i = 0; i < Exp->getNumArgs(); i++) {2856Expr *userExpr = Exp->getArg(i);2857// Make all implicit casts explicit...ICE comes in handy:-)2858if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) {2859// Reuse the ICE type, it is exactly what the doctor ordered.2860QualType type = ICE->getType();2861if (needToScanForQualifiers(type))2862type = Context->getObjCIdType();2863// Make sure we convert "type (^)(...)" to "type (*)(...)".2864(void)convertBlockPointerToFunctionPointer(type);2865const Expr *SubExpr = ICE->IgnoreParenImpCasts();2866CastKind CK;2867if (SubExpr->getType()->isIntegralType(*Context) &&2868type->isBooleanType()) {2869CK = CK_IntegralToBoolean;2870} else if (type->isObjCObjectPointerType()) {2871if (SubExpr->getType()->isBlockPointerType()) {2872CK = CK_BlockPointerToObjCPointerCast;2873} else if (SubExpr->getType()->isPointerType()) {2874CK = CK_CPointerToObjCPointerCast;2875} else {2876CK = CK_BitCast;2877}2878} else {2879CK = CK_BitCast;2880}28812882userExpr = NoTypeInfoCStyleCastExpr(Context, type, CK, userExpr);2883}2884// Make id<P...> cast into an 'id' cast.2885else if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(userExpr)) {2886if (CE->getType()->isObjCQualifiedIdType()) {2887while ((CE = dyn_cast<CStyleCastExpr>(userExpr)))2888userExpr = CE->getSubExpr();2889CastKind CK;2890if (userExpr->getType()->isIntegralType(*Context)) {2891CK = CK_IntegralToPointer;2892} else if (userExpr->getType()->isBlockPointerType()) {2893CK = CK_BlockPointerToObjCPointerCast;2894} else if (userExpr->getType()->isPointerType()) {2895CK = CK_CPointerToObjCPointerCast;2896} else {2897CK = CK_BitCast;2898}2899userExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),2900CK, userExpr);2901}2902}2903MsgExprs.push_back(userExpr);2904// We've transferred the ownership to MsgExprs. For now, we *don't* null2905// out the argument in the original expression (since we aren't deleting2906// the ObjCMessageExpr). See RewritePropertyOrImplicitSetter() usage for more info.2907//Exp->setArg(i, 0);2908}2909// Generate the funky cast.2910CastExpr *cast;2911SmallVector<QualType, 8> ArgTypes;2912QualType returnType;29132914// Push 'id' and 'SEL', the 2 implicit arguments.2915if (MsgSendFlavor == MsgSendSuperFunctionDecl)2916ArgTypes.push_back(Context->getPointerType(getSuperStructType()));2917else2918ArgTypes.push_back(Context->getObjCIdType());2919ArgTypes.push_back(Context->getObjCSelType());2920if (ObjCMethodDecl *OMD = Exp->getMethodDecl()) {2921// Push any user argument types.2922for (const auto *PI : OMD->parameters()) {2923QualType t = PI->getType()->isObjCQualifiedIdType()2924? Context->getObjCIdType()2925: PI->getType();2926// Make sure we convert "t (^)(...)" to "t (*)(...)".2927(void)convertBlockPointerToFunctionPointer(t);2928ArgTypes.push_back(t);2929}2930returnType = Exp->getType();2931convertToUnqualifiedObjCType(returnType);2932(void)convertBlockPointerToFunctionPointer(returnType);2933} else {2934returnType = Context->getObjCIdType();2935}2936// Get the type, we will need to reference it in a couple spots.2937QualType msgSendType = MsgSendFlavor->getType();29382939// Create a reference to the objc_msgSend() declaration.2940DeclRefExpr *DRE = new (Context) DeclRefExpr(2941*Context, MsgSendFlavor, false, msgSendType, VK_LValue, SourceLocation());29422943// Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid).2944// If we don't do this cast, we get the following bizarre warning/note:2945// xx.m:13: warning: function called through a non-compatible type2946// xx.m:13: note: if this code is reached, the program will abort2947cast = NoTypeInfoCStyleCastExpr(Context,2948Context->getPointerType(Context->VoidTy),2949CK_BitCast, DRE);29502951// Now do the "normal" pointer to function cast.2952// If we don't have a method decl, force a variadic cast.2953const ObjCMethodDecl *MD = Exp->getMethodDecl();2954QualType castType =2955getSimpleFunctionType(returnType, ArgTypes, MD ? MD->isVariadic() : true);2956castType = Context->getPointerType(castType);2957cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,2958cast);29592960// Don't forget the parens to enforce the proper binding.2961ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);29622963const auto *FT = msgSendType->castAs<FunctionType>();2964CallExpr *CE = CallExpr::Create(*Context, PE, MsgExprs, FT->getReturnType(),2965VK_PRValue, EndLoc, FPOptionsOverride());2966Stmt *ReplacingStmt = CE;2967if (MsgSendStretFlavor) {2968// We have the method which returns a struct/union. Must also generate2969// call to objc_msgSend_stret and hang both varieties on a conditional2970// expression which dictate which one to envoke depending on size of2971// method's return type.29722973CallExpr *STCE = SynthMsgSendStretCallExpr(MsgSendStretFlavor,2974msgSendType, returnType,2975ArgTypes, MsgExprs,2976Exp->getMethodDecl());29772978// Build sizeof(returnType)2979UnaryExprOrTypeTraitExpr *sizeofExpr =2980new (Context) UnaryExprOrTypeTraitExpr(UETT_SizeOf,2981Context->getTrivialTypeSourceInfo(returnType),2982Context->getSizeType(), SourceLocation(),2983SourceLocation());2984// (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))2985// FIXME: Value of 8 is base on ppc32/x86 ABI for the most common cases.2986// For X86 it is more complicated and some kind of target specific routine2987// is needed to decide what to do.2988unsigned IntSize =2989static_cast<unsigned>(Context->getTypeSize(Context->IntTy));2990IntegerLiteral *limit = IntegerLiteral::Create(*Context,2991llvm::APInt(IntSize, 8),2992Context->IntTy,2993SourceLocation());2994BinaryOperator *lessThanExpr = BinaryOperator::Create(2995*Context, sizeofExpr, limit, BO_LE, Context->IntTy, VK_PRValue,2996OK_Ordinary, SourceLocation(), FPOptionsOverride());2997// (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))2998ConditionalOperator *CondExpr = new (Context) ConditionalOperator(2999lessThanExpr, SourceLocation(), CE, SourceLocation(), STCE, returnType,3000VK_PRValue, OK_Ordinary);3001ReplacingStmt = new (Context) ParenExpr(SourceLocation(), SourceLocation(),3002CondExpr);3003}3004// delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.3005return ReplacingStmt;3006}30073008Stmt *RewriteObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) {3009Stmt *ReplacingStmt =3010SynthMessageExpr(Exp, Exp->getBeginLoc(), Exp->getEndLoc());30113012// Now do the actual rewrite.3013ReplaceStmt(Exp, ReplacingStmt);30143015// delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.3016return ReplacingStmt;3017}30183019// typedef struct objc_object Protocol;3020QualType RewriteObjC::getProtocolType() {3021if (!ProtocolTypeDecl) {3022TypeSourceInfo *TInfo3023= Context->getTrivialTypeSourceInfo(Context->getObjCIdType());3024ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl,3025SourceLocation(), SourceLocation(),3026&Context->Idents.get("Protocol"),3027TInfo);3028}3029return Context->getTypeDeclType(ProtocolTypeDecl);3030}30313032/// RewriteObjCProtocolExpr - Rewrite a protocol expression into3033/// a synthesized/forward data reference (to the protocol's metadata).3034/// The forward references (and metadata) are generated in3035/// RewriteObjC::HandleTranslationUnit().3036Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {3037std::string Name = "_OBJC_PROTOCOL_" + Exp->getProtocol()->getNameAsString();3038IdentifierInfo *ID = &Context->Idents.get(Name);3039VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(),3040SourceLocation(), ID, getProtocolType(),3041nullptr, SC_Extern);3042DeclRefExpr *DRE = new (Context) DeclRefExpr(3043*Context, VD, false, getProtocolType(), VK_LValue, SourceLocation());3044Expr *DerefExpr = UnaryOperator::Create(3045const_cast<ASTContext &>(*Context), DRE, UO_AddrOf,3046Context->getPointerType(DRE->getType()), VK_PRValue, OK_Ordinary,3047SourceLocation(), false, FPOptionsOverride());3048CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(),3049CK_BitCast,3050DerefExpr);3051ReplaceStmt(Exp, castExpr);3052ProtocolExprDecls.insert(Exp->getProtocol()->getCanonicalDecl());3053// delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.3054return castExpr;3055}30563057bool RewriteObjC::BufferContainsPPDirectives(const char *startBuf,3058const char *endBuf) {3059while (startBuf < endBuf) {3060if (*startBuf == '#') {3061// Skip whitespace.3062for (++startBuf; startBuf[0] == ' ' || startBuf[0] == '\t'; ++startBuf)3063;3064if (!strncmp(startBuf, "if", strlen("if")) ||3065!strncmp(startBuf, "ifdef", strlen("ifdef")) ||3066!strncmp(startBuf, "ifndef", strlen("ifndef")) ||3067!strncmp(startBuf, "define", strlen("define")) ||3068!strncmp(startBuf, "undef", strlen("undef")) ||3069!strncmp(startBuf, "else", strlen("else")) ||3070!strncmp(startBuf, "elif", strlen("elif")) ||3071!strncmp(startBuf, "endif", strlen("endif")) ||3072!strncmp(startBuf, "pragma", strlen("pragma")) ||3073!strncmp(startBuf, "include", strlen("include")) ||3074!strncmp(startBuf, "import", strlen("import")) ||3075!strncmp(startBuf, "include_next", strlen("include_next")))3076return true;3077}3078startBuf++;3079}3080return false;3081}30823083/// RewriteObjCInternalStruct - Rewrite one internal struct corresponding to3084/// an objective-c class with ivars.3085void RewriteObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,3086std::string &Result) {3087assert(CDecl && "Class missing in SynthesizeObjCInternalStruct");3088assert(CDecl->getName() != "" &&3089"Name missing in SynthesizeObjCInternalStruct");3090// Do not synthesize more than once.3091if (ObjCSynthesizedStructs.count(CDecl))3092return;3093ObjCInterfaceDecl *RCDecl = CDecl->getSuperClass();3094int NumIvars = CDecl->ivar_size();3095SourceLocation LocStart = CDecl->getBeginLoc();3096SourceLocation LocEnd = CDecl->getEndOfDefinitionLoc();30973098const char *startBuf = SM->getCharacterData(LocStart);3099const char *endBuf = SM->getCharacterData(LocEnd);31003101// If no ivars and no root or if its root, directly or indirectly,3102// have no ivars (thus not synthesized) then no need to synthesize this class.3103if ((!CDecl->isThisDeclarationADefinition() || NumIvars == 0) &&3104(!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) {3105endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts);3106ReplaceText(LocStart, endBuf-startBuf, Result);3107return;3108}31093110// FIXME: This has potential of causing problem. If3111// SynthesizeObjCInternalStruct is ever called recursively.3112Result += "\nstruct ";3113Result += CDecl->getNameAsString();3114if (LangOpts.MicrosoftExt)3115Result += "_IMPL";31163117if (NumIvars > 0) {3118const char *cursor = strchr(startBuf, '{');3119assert((cursor && endBuf)3120&& "SynthesizeObjCInternalStruct - malformed @interface");3121// If the buffer contains preprocessor directives, we do more fine-grained3122// rewrites. This is intended to fix code that looks like (which occurs in3123// NSURL.h, for example):3124//3125// #ifdef XYZ3126// @interface Foo : NSObject3127// #else3128// @interface FooBar : NSObject3129// #endif3130// {3131// int i;3132// }3133// @end3134//3135// This clause is segregated to avoid breaking the common case.3136if (BufferContainsPPDirectives(startBuf, cursor)) {3137SourceLocation L = RCDecl ? CDecl->getSuperClassLoc() :3138CDecl->getAtStartLoc();3139const char *endHeader = SM->getCharacterData(L);3140endHeader += Lexer::MeasureTokenLength(L, *SM, LangOpts);31413142if (CDecl->protocol_begin() != CDecl->protocol_end()) {3143// advance to the end of the referenced protocols.3144while (endHeader < cursor && *endHeader != '>') endHeader++;3145endHeader++;3146}3147// rewrite the original header3148ReplaceText(LocStart, endHeader-startBuf, Result);3149} else {3150// rewrite the original header *without* disturbing the '{'3151ReplaceText(LocStart, cursor-startBuf, Result);3152}3153if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) {3154Result = "\n struct ";3155Result += RCDecl->getNameAsString();3156Result += "_IMPL ";3157Result += RCDecl->getNameAsString();3158Result += "_IVARS;\n";31593160// insert the super class structure definition.3161SourceLocation OnePastCurly =3162LocStart.getLocWithOffset(cursor-startBuf+1);3163InsertText(OnePastCurly, Result);3164}3165cursor++; // past '{'31663167// Now comment out any visibility specifiers.3168while (cursor < endBuf) {3169if (*cursor == '@') {3170SourceLocation atLoc = LocStart.getLocWithOffset(cursor-startBuf);3171// Skip whitespace.3172for (++cursor; cursor[0] == ' ' || cursor[0] == '\t'; ++cursor)3173/*scan*/;31743175// FIXME: presence of @public, etc. inside comment results in3176// this transformation as well, which is still correct c-code.3177if (!strncmp(cursor, "public", strlen("public")) ||3178!strncmp(cursor, "private", strlen("private")) ||3179!strncmp(cursor, "package", strlen("package")) ||3180!strncmp(cursor, "protected", strlen("protected")))3181InsertText(atLoc, "// ");3182}3183// FIXME: If there are cases where '<' is used in ivar declaration part3184// of user code, then scan the ivar list and use needToScanForQualifiers3185// for type checking.3186else if (*cursor == '<') {3187SourceLocation atLoc = LocStart.getLocWithOffset(cursor-startBuf);3188InsertText(atLoc, "/* ");3189cursor = strchr(cursor, '>');3190cursor++;3191atLoc = LocStart.getLocWithOffset(cursor-startBuf);3192InsertText(atLoc, " */");3193} else if (*cursor == '^') { // rewrite block specifier.3194SourceLocation caretLoc = LocStart.getLocWithOffset(cursor-startBuf);3195ReplaceText(caretLoc, 1, "*");3196}3197cursor++;3198}3199// Don't forget to add a ';'!!3200InsertText(LocEnd.getLocWithOffset(1), ";");3201} else { // we don't have any instance variables - insert super struct.3202endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts);3203Result += " {\n struct ";3204Result += RCDecl->getNameAsString();3205Result += "_IMPL ";3206Result += RCDecl->getNameAsString();3207Result += "_IVARS;\n};\n";3208ReplaceText(LocStart, endBuf-startBuf, Result);3209}3210// Mark this struct as having been generated.3211if (!ObjCSynthesizedStructs.insert(CDecl).second)3212llvm_unreachable("struct already synthesize- SynthesizeObjCInternalStruct");3213}32143215//===----------------------------------------------------------------------===//3216// Meta Data Emission3217//===----------------------------------------------------------------------===//32183219/// RewriteImplementations - This routine rewrites all method implementations3220/// and emits meta-data.32213222void RewriteObjC::RewriteImplementations() {3223int ClsDefCount = ClassImplementation.size();3224int CatDefCount = CategoryImplementation.size();32253226// Rewrite implemented methods3227for (int i = 0; i < ClsDefCount; i++)3228RewriteImplementationDecl(ClassImplementation[i]);32293230for (int i = 0; i < CatDefCount; i++)3231RewriteImplementationDecl(CategoryImplementation[i]);3232}32333234void RewriteObjC::RewriteByRefString(std::string &ResultStr,3235const std::string &Name,3236ValueDecl *VD, bool def) {3237assert(BlockByRefDeclNo.count(VD) &&3238"RewriteByRefString: ByRef decl missing");3239if (def)3240ResultStr += "struct ";3241ResultStr += "__Block_byref_" + Name +3242"_" + utostr(BlockByRefDeclNo[VD]) ;3243}32443245static bool HasLocalVariableExternalStorage(ValueDecl *VD) {3246if (VarDecl *Var = dyn_cast<VarDecl>(VD))3247return (Var->isFunctionOrMethodVarDecl() && !Var->hasLocalStorage());3248return false;3249}32503251std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,3252StringRef funcName,3253std::string Tag) {3254const FunctionType *AFT = CE->getFunctionType();3255QualType RT = AFT->getReturnType();3256std::string StructRef = "struct " + Tag;3257std::string S = "static " + RT.getAsString(Context->getPrintingPolicy()) + " __" +3258funcName.str() + "_" + "block_func_" + utostr(i);32593260BlockDecl *BD = CE->getBlockDecl();32613262if (isa<FunctionNoProtoType>(AFT)) {3263// No user-supplied arguments. Still need to pass in a pointer to the3264// block (to reference imported block decl refs).3265S += "(" + StructRef + " *__cself)";3266} else if (BD->param_empty()) {3267S += "(" + StructRef + " *__cself)";3268} else {3269const FunctionProtoType *FT = cast<FunctionProtoType>(AFT);3270assert(FT && "SynthesizeBlockFunc: No function proto");3271S += '(';3272// first add the implicit argument.3273S += StructRef + " *__cself, ";3274std::string ParamStr;3275for (BlockDecl::param_iterator AI = BD->param_begin(),3276E = BD->param_end(); AI != E; ++AI) {3277if (AI != BD->param_begin()) S += ", ";3278ParamStr = (*AI)->getNameAsString();3279QualType QT = (*AI)->getType();3280(void)convertBlockPointerToFunctionPointer(QT);3281QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy());3282S += ParamStr;3283}3284if (FT->isVariadic()) {3285if (!BD->param_empty()) S += ", ";3286S += "...";3287}3288S += ')';3289}3290S += " {\n";32913292// Create local declarations to avoid rewriting all closure decl ref exprs.3293// First, emit a declaration for all "by ref" decls.3294for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(),3295E = BlockByRefDecls.end(); I != E; ++I) {3296S += " ";3297std::string Name = (*I)->getNameAsString();3298std::string TypeString;3299RewriteByRefString(TypeString, Name, (*I));3300TypeString += " *";3301Name = TypeString + Name;3302S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";3303}3304// Next, emit a declaration for all "by copy" declarations.3305for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(),3306E = BlockByCopyDecls.end(); I != E; ++I) {3307S += " ";3308// Handle nested closure invocation. For example:3309//3310// void (^myImportedClosure)(void);3311// myImportedClosure = ^(void) { setGlobalInt(x + y); };3312//3313// void (^anotherClosure)(void);3314// anotherClosure = ^(void) {3315// myImportedClosure(); // import and invoke the closure3316// };3317//3318if (isTopLevelBlockPointerType((*I)->getType())) {3319RewriteBlockPointerTypeVariable(S, (*I));3320S += " = (";3321RewriteBlockPointerType(S, (*I)->getType());3322S += ")";3323S += "__cself->" + (*I)->getNameAsString() + "; // bound by copy\n";3324}3325else {3326std::string Name = (*I)->getNameAsString();3327QualType QT = (*I)->getType();3328if (HasLocalVariableExternalStorage(*I))3329QT = Context->getPointerType(QT);3330QT.getAsStringInternal(Name, Context->getPrintingPolicy());3331S += Name + " = __cself->" +3332(*I)->getNameAsString() + "; // bound by copy\n";3333}3334}3335std::string RewrittenStr = RewrittenBlockExprs[CE];3336const char *cstr = RewrittenStr.c_str();3337while (*cstr++ != '{') ;3338S += cstr;3339S += "\n";3340return S;3341}33423343std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,3344StringRef funcName,3345std::string Tag) {3346std::string StructRef = "struct " + Tag;3347std::string S = "static void __";33483349S += funcName;3350S += "_block_copy_" + utostr(i);3351S += "(" + StructRef;3352S += "*dst, " + StructRef;3353S += "*src) {";3354for (ValueDecl *VD : ImportedBlockDecls) {3355S += "_Block_object_assign((void*)&dst->";3356S += VD->getNameAsString();3357S += ", (void*)src->";3358S += VD->getNameAsString();3359if (BlockByRefDeclsPtrSet.count(VD))3360S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";3361else if (VD->getType()->isBlockPointerType())3362S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);";3363else3364S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);";3365}3366S += "}\n";33673368S += "\nstatic void __";3369S += funcName;3370S += "_block_dispose_" + utostr(i);3371S += "(" + StructRef;3372S += "*src) {";3373for (ValueDecl *VD : ImportedBlockDecls) {3374S += "_Block_object_dispose((void*)src->";3375S += VD->getNameAsString();3376if (BlockByRefDeclsPtrSet.count(VD))3377S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";3378else if (VD->getType()->isBlockPointerType())3379S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);";3380else3381S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);";3382}3383S += "}\n";3384return S;3385}33863387std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,3388std::string Desc) {3389std::string S = "\nstruct " + Tag;3390std::string Constructor = " " + Tag;33913392S += " {\n struct __block_impl impl;\n";3393S += " struct " + Desc;3394S += "* Desc;\n";33953396Constructor += "(void *fp, "; // Invoke function pointer.3397Constructor += "struct " + Desc; // Descriptor pointer.3398Constructor += " *desc";33993400if (BlockDeclRefs.size()) {3401// Output all "by copy" declarations.3402for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(),3403E = BlockByCopyDecls.end(); I != E; ++I) {3404S += " ";3405std::string FieldName = (*I)->getNameAsString();3406std::string ArgName = "_" + FieldName;3407// Handle nested closure invocation. For example:3408//3409// void (^myImportedBlock)(void);3410// myImportedBlock = ^(void) { setGlobalInt(x + y); };3411//3412// void (^anotherBlock)(void);3413// anotherBlock = ^(void) {3414// myImportedBlock(); // import and invoke the closure3415// };3416//3417if (isTopLevelBlockPointerType((*I)->getType())) {3418S += "struct __block_impl *";3419Constructor += ", void *" + ArgName;3420} else {3421QualType QT = (*I)->getType();3422if (HasLocalVariableExternalStorage(*I))3423QT = Context->getPointerType(QT);3424QT.getAsStringInternal(FieldName, Context->getPrintingPolicy());3425QT.getAsStringInternal(ArgName, Context->getPrintingPolicy());3426Constructor += ", " + ArgName;3427}3428S += FieldName + ";\n";3429}3430// Output all "by ref" declarations.3431for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(),3432E = BlockByRefDecls.end(); I != E; ++I) {3433S += " ";3434std::string FieldName = (*I)->getNameAsString();3435std::string ArgName = "_" + FieldName;3436{3437std::string TypeString;3438RewriteByRefString(TypeString, FieldName, (*I));3439TypeString += " *";3440FieldName = TypeString + FieldName;3441ArgName = TypeString + ArgName;3442Constructor += ", " + ArgName;3443}3444S += FieldName + "; // by ref\n";3445}3446// Finish writing the constructor.3447Constructor += ", int flags=0)";3448// Initialize all "by copy" arguments.3449bool firsTime = true;3450for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(),3451E = BlockByCopyDecls.end(); I != E; ++I) {3452std::string Name = (*I)->getNameAsString();3453if (firsTime) {3454Constructor += " : ";3455firsTime = false;3456}3457else3458Constructor += ", ";3459if (isTopLevelBlockPointerType((*I)->getType()))3460Constructor += Name + "((struct __block_impl *)_" + Name + ")";3461else3462Constructor += Name + "(_" + Name + ")";3463}3464// Initialize all "by ref" arguments.3465for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(),3466E = BlockByRefDecls.end(); I != E; ++I) {3467std::string Name = (*I)->getNameAsString();3468if (firsTime) {3469Constructor += " : ";3470firsTime = false;3471}3472else3473Constructor += ", ";3474Constructor += Name + "(_" + Name + "->__forwarding)";3475}34763477Constructor += " {\n";3478if (GlobalVarDecl)3479Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n";3480else3481Constructor += " impl.isa = &_NSConcreteStackBlock;\n";3482Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n";34833484Constructor += " Desc = desc;\n";3485} else {3486// Finish writing the constructor.3487Constructor += ", int flags=0) {\n";3488if (GlobalVarDecl)3489Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n";3490else3491Constructor += " impl.isa = &_NSConcreteStackBlock;\n";3492Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n";3493Constructor += " Desc = desc;\n";3494}3495Constructor += " ";3496Constructor += "}\n";3497S += Constructor;3498S += "};\n";3499return S;3500}35013502std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag,3503std::string ImplTag, int i,3504StringRef FunName,3505unsigned hasCopy) {3506std::string S = "\nstatic struct " + DescTag;35073508S += " {\n unsigned long reserved;\n";3509S += " unsigned long Block_size;\n";3510if (hasCopy) {3511S += " void (*copy)(struct ";3512S += ImplTag; S += "*, struct ";3513S += ImplTag; S += "*);\n";35143515S += " void (*dispose)(struct ";3516S += ImplTag; S += "*);\n";3517}3518S += "} ";35193520S += DescTag + "_DATA = { 0, sizeof(struct ";3521S += ImplTag + ")";3522if (hasCopy) {3523S += ", __" + FunName.str() + "_block_copy_" + utostr(i);3524S += ", __" + FunName.str() + "_block_dispose_" + utostr(i);3525}3526S += "};\n";3527return S;3528}35293530void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,3531StringRef FunName) {3532// Insert declaration for the function in which block literal is used.3533if (CurFunctionDeclToDeclareForBlock && !Blocks.empty())3534RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock);3535bool RewriteSC = (GlobalVarDecl &&3536!Blocks.empty() &&3537GlobalVarDecl->getStorageClass() == SC_Static &&3538GlobalVarDecl->getType().getCVRQualifiers());3539if (RewriteSC) {3540std::string SC(" void __");3541SC += GlobalVarDecl->getNameAsString();3542SC += "() {}";3543InsertText(FunLocStart, SC);3544}35453546// Insert closures that were part of the function.3547for (unsigned i = 0, count=0; i < Blocks.size(); i++) {3548CollectBlockDeclRefInfo(Blocks[i]);3549// Need to copy-in the inner copied-in variables not actually used in this3550// block.3551for (int j = 0; j < InnerDeclRefsCount[i]; j++) {3552DeclRefExpr *Exp = InnerDeclRefs[count++];3553ValueDecl *VD = Exp->getDecl();3554BlockDeclRefs.push_back(Exp);3555if (!VD->hasAttr<BlocksAttr>() && !BlockByCopyDeclsPtrSet.count(VD)) {3556BlockByCopyDeclsPtrSet.insert(VD);3557BlockByCopyDecls.push_back(VD);3558}3559if (VD->hasAttr<BlocksAttr>() && !BlockByRefDeclsPtrSet.count(VD)) {3560BlockByRefDeclsPtrSet.insert(VD);3561BlockByRefDecls.push_back(VD);3562}3563// imported objects in the inner blocks not used in the outer3564// blocks must be copied/disposed in the outer block as well.3565if (VD->hasAttr<BlocksAttr>() ||3566VD->getType()->isObjCObjectPointerType() ||3567VD->getType()->isBlockPointerType())3568ImportedBlockDecls.insert(VD);3569}35703571std::string ImplTag = "__" + FunName.str() + "_block_impl_" + utostr(i);3572std::string DescTag = "__" + FunName.str() + "_block_desc_" + utostr(i);35733574std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag);35753576InsertText(FunLocStart, CI);35773578std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, ImplTag);35793580InsertText(FunLocStart, CF);35813582if (ImportedBlockDecls.size()) {3583std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, ImplTag);3584InsertText(FunLocStart, HF);3585}3586std::string BD = SynthesizeBlockDescriptor(DescTag, ImplTag, i, FunName,3587ImportedBlockDecls.size() > 0);3588InsertText(FunLocStart, BD);35893590BlockDeclRefs.clear();3591BlockByRefDecls.clear();3592BlockByRefDeclsPtrSet.clear();3593BlockByCopyDecls.clear();3594BlockByCopyDeclsPtrSet.clear();3595ImportedBlockDecls.clear();3596}3597if (RewriteSC) {3598// Must insert any 'const/volatile/static here. Since it has been3599// removed as result of rewriting of block literals.3600std::string SC;3601if (GlobalVarDecl->getStorageClass() == SC_Static)3602SC = "static ";3603if (GlobalVarDecl->getType().isConstQualified())3604SC += "const ";3605if (GlobalVarDecl->getType().isVolatileQualified())3606SC += "volatile ";3607if (GlobalVarDecl->getType().isRestrictQualified())3608SC += "restrict ";3609InsertText(FunLocStart, SC);3610}36113612Blocks.clear();3613InnerDeclRefsCount.clear();3614InnerDeclRefs.clear();3615RewrittenBlockExprs.clear();3616}36173618void RewriteObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {3619SourceLocation FunLocStart = FD->getTypeSpecStartLoc();3620StringRef FuncName = FD->getName();36213622SynthesizeBlockLiterals(FunLocStart, FuncName);3623}36243625static void BuildUniqueMethodName(std::string &Name,3626ObjCMethodDecl *MD) {3627ObjCInterfaceDecl *IFace = MD->getClassInterface();3628Name = std::string(IFace->getName());3629Name += "__" + MD->getSelector().getAsString();3630// Convert colons to underscores.3631std::string::size_type loc = 0;3632while ((loc = Name.find(':', loc)) != std::string::npos)3633Name.replace(loc, 1, "_");3634}36353636void RewriteObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {3637// fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n");3638// SourceLocation FunLocStart = MD->getBeginLoc();3639SourceLocation FunLocStart = MD->getBeginLoc();3640std::string FuncName;3641BuildUniqueMethodName(FuncName, MD);3642SynthesizeBlockLiterals(FunLocStart, FuncName);3643}36443645void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) {3646for (Stmt *SubStmt : S->children())3647if (SubStmt) {3648if (BlockExpr *CBE = dyn_cast<BlockExpr>(SubStmt))3649GetBlockDeclRefExprs(CBE->getBody());3650else3651GetBlockDeclRefExprs(SubStmt);3652}3653// Handle specific things.3654if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S))3655if (DRE->refersToEnclosingVariableOrCapture() ||3656HasLocalVariableExternalStorage(DRE->getDecl()))3657// FIXME: Handle enums.3658BlockDeclRefs.push_back(DRE);3659}36603661void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S,3662SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs,3663llvm::SmallPtrSetImpl<const DeclContext *> &InnerContexts) {3664for (Stmt *SubStmt : S->children())3665if (SubStmt) {3666if (BlockExpr *CBE = dyn_cast<BlockExpr>(SubStmt)) {3667InnerContexts.insert(cast<DeclContext>(CBE->getBlockDecl()));3668GetInnerBlockDeclRefExprs(CBE->getBody(),3669InnerBlockDeclRefs,3670InnerContexts);3671}3672else3673GetInnerBlockDeclRefExprs(SubStmt, InnerBlockDeclRefs, InnerContexts);3674}3675// Handle specific things.3676if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {3677if (DRE->refersToEnclosingVariableOrCapture() ||3678HasLocalVariableExternalStorage(DRE->getDecl())) {3679if (!InnerContexts.count(DRE->getDecl()->getDeclContext()))3680InnerBlockDeclRefs.push_back(DRE);3681if (VarDecl *Var = cast<VarDecl>(DRE->getDecl()))3682if (Var->isFunctionOrMethodVarDecl())3683ImportedLocalExternalDecls.insert(Var);3684}3685}3686}36873688/// convertFunctionTypeOfBlocks - This routine converts a function type3689/// whose result type may be a block pointer or whose argument type(s)3690/// might be block pointers to an equivalent function type replacing3691/// all block pointers to function pointers.3692QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) {3693const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);3694// FTP will be null for closures that don't take arguments.3695// Generate a funky cast.3696SmallVector<QualType, 8> ArgTypes;3697QualType Res = FT->getReturnType();3698bool HasBlockType = convertBlockPointerToFunctionPointer(Res);36993700if (FTP) {3701for (auto &I : FTP->param_types()) {3702QualType t = I;3703// Make sure we convert "t (^)(...)" to "t (*)(...)".3704if (convertBlockPointerToFunctionPointer(t))3705HasBlockType = true;3706ArgTypes.push_back(t);3707}3708}3709QualType FuncType;3710// FIXME. Does this work if block takes no argument but has a return type3711// which is of block type?3712if (HasBlockType)3713FuncType = getSimpleFunctionType(Res, ArgTypes);3714else FuncType = QualType(FT, 0);3715return FuncType;3716}37173718Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {3719// Navigate to relevant type information.3720const BlockPointerType *CPT = nullptr;37213722if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BlockExp)) {3723CPT = DRE->getType()->getAs<BlockPointerType>();3724} else if (const MemberExpr *MExpr = dyn_cast<MemberExpr>(BlockExp)) {3725CPT = MExpr->getType()->getAs<BlockPointerType>();3726}3727else if (const ParenExpr *PRE = dyn_cast<ParenExpr>(BlockExp)) {3728return SynthesizeBlockCall(Exp, PRE->getSubExpr());3729}3730else if (const ImplicitCastExpr *IEXPR = dyn_cast<ImplicitCastExpr>(BlockExp))3731CPT = IEXPR->getType()->getAs<BlockPointerType>();3732else if (const ConditionalOperator *CEXPR =3733dyn_cast<ConditionalOperator>(BlockExp)) {3734Expr *LHSExp = CEXPR->getLHS();3735Stmt *LHSStmt = SynthesizeBlockCall(Exp, LHSExp);3736Expr *RHSExp = CEXPR->getRHS();3737Stmt *RHSStmt = SynthesizeBlockCall(Exp, RHSExp);3738Expr *CONDExp = CEXPR->getCond();3739ConditionalOperator *CondExpr = new (Context) ConditionalOperator(3740CONDExp, SourceLocation(), cast<Expr>(LHSStmt), SourceLocation(),3741cast<Expr>(RHSStmt), Exp->getType(), VK_PRValue, OK_Ordinary);3742return CondExpr;3743} else if (const ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(BlockExp)) {3744CPT = IRE->getType()->getAs<BlockPointerType>();3745} else if (const PseudoObjectExpr *POE3746= dyn_cast<PseudoObjectExpr>(BlockExp)) {3747CPT = POE->getType()->castAs<BlockPointerType>();3748} else {3749assert(false && "RewriteBlockClass: Bad type");3750}3751assert(CPT && "RewriteBlockClass: Bad type");3752const FunctionType *FT = CPT->getPointeeType()->getAs<FunctionType>();3753assert(FT && "RewriteBlockClass: Bad type");3754const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);3755// FTP will be null for closures that don't take arguments.37563757RecordDecl *RD = RecordDecl::Create(*Context, TagTypeKind::Struct, TUDecl,3758SourceLocation(), SourceLocation(),3759&Context->Idents.get("__block_impl"));3760QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD));37613762// Generate a funky cast.3763SmallVector<QualType, 8> ArgTypes;37643765// Push the block argument type.3766ArgTypes.push_back(PtrBlock);3767if (FTP) {3768for (auto &I : FTP->param_types()) {3769QualType t = I;3770// Make sure we convert "t (^)(...)" to "t (*)(...)".3771if (!convertBlockPointerToFunctionPointer(t))3772convertToUnqualifiedObjCType(t);3773ArgTypes.push_back(t);3774}3775}3776// Now do the pointer to function cast.3777QualType PtrToFuncCastType = getSimpleFunctionType(Exp->getType(), ArgTypes);37783779PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType);37803781CastExpr *BlkCast = NoTypeInfoCStyleCastExpr(Context, PtrBlock,3782CK_BitCast,3783const_cast<Expr*>(BlockExp));3784// Don't forget the parens to enforce the proper binding.3785ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),3786BlkCast);3787//PE->dump();37883789FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),3790SourceLocation(),3791&Context->Idents.get("FuncPtr"),3792Context->VoidPtrTy, nullptr,3793/*BitWidth=*/nullptr, /*Mutable=*/true,3794ICIS_NoInit);3795MemberExpr *ME = MemberExpr::CreateImplicit(3796*Context, PE, true, FD, FD->getType(), VK_LValue, OK_Ordinary);37973798CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType,3799CK_BitCast, ME);3800PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast);38013802SmallVector<Expr*, 8> BlkExprs;3803// Add the implicit argument.3804BlkExprs.push_back(BlkCast);3805// Add the user arguments.3806for (CallExpr::arg_iterator I = Exp->arg_begin(),3807E = Exp->arg_end(); I != E; ++I) {3808BlkExprs.push_back(*I);3809}3810CallExpr *CE =3811CallExpr::Create(*Context, PE, BlkExprs, Exp->getType(), VK_PRValue,3812SourceLocation(), FPOptionsOverride());3813return CE;3814}38153816// We need to return the rewritten expression to handle cases where the3817// BlockDeclRefExpr is embedded in another expression being rewritten.3818// For example:3819//3820// int main() {3821// __block Foo *f;3822// __block int i;3823//3824// void (^myblock)() = ^() {3825// [f test]; // f is a BlockDeclRefExpr embedded in a message (which is being rewritten).3826// i = 77;3827// };3828//}3829Stmt *RewriteObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) {3830// Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR3831// for each DeclRefExp where BYREFVAR is name of the variable.3832ValueDecl *VD = DeclRefExp->getDecl();3833bool isArrow = DeclRefExp->refersToEnclosingVariableOrCapture() ||3834HasLocalVariableExternalStorage(DeclRefExp->getDecl());38353836FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),3837SourceLocation(),3838&Context->Idents.get("__forwarding"),3839Context->VoidPtrTy, nullptr,3840/*BitWidth=*/nullptr, /*Mutable=*/true,3841ICIS_NoInit);3842MemberExpr *ME =3843MemberExpr::CreateImplicit(*Context, DeclRefExp, isArrow, FD,3844FD->getType(), VK_LValue, OK_Ordinary);38453846StringRef Name = VD->getName();3847FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), SourceLocation(),3848&Context->Idents.get(Name),3849Context->VoidPtrTy, nullptr,3850/*BitWidth=*/nullptr, /*Mutable=*/true,3851ICIS_NoInit);3852ME = MemberExpr::CreateImplicit(*Context, ME, true, FD, DeclRefExp->getType(),3853VK_LValue, OK_Ordinary);38543855// Need parens to enforce precedence.3856ParenExpr *PE = new (Context) ParenExpr(DeclRefExp->getExprLoc(),3857DeclRefExp->getExprLoc(),3858ME);3859ReplaceStmt(DeclRefExp, PE);3860return PE;3861}38623863// Rewrites the imported local variable V with external storage3864// (static, extern, etc.) as *V3865//3866Stmt *RewriteObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) {3867ValueDecl *VD = DRE->getDecl();3868if (VarDecl *Var = dyn_cast<VarDecl>(VD))3869if (!ImportedLocalExternalDecls.count(Var))3870return DRE;3871Expr *Exp = UnaryOperator::Create(3872const_cast<ASTContext &>(*Context), DRE, UO_Deref, DRE->getType(),3873VK_LValue, OK_Ordinary, DRE->getLocation(), false, FPOptionsOverride());3874// Need parens to enforce precedence.3875ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),3876Exp);3877ReplaceStmt(DRE, PE);3878return PE;3879}38803881void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) {3882SourceLocation LocStart = CE->getLParenLoc();3883SourceLocation LocEnd = CE->getRParenLoc();38843885// Need to avoid trying to rewrite synthesized casts.3886if (LocStart.isInvalid())3887return;3888// Need to avoid trying to rewrite casts contained in macros.3889if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd))3890return;38913892const char *startBuf = SM->getCharacterData(LocStart);3893const char *endBuf = SM->getCharacterData(LocEnd);3894QualType QT = CE->getType();3895const Type* TypePtr = QT->getAs<Type>();3896if (isa<TypeOfExprType>(TypePtr)) {3897const TypeOfExprType *TypeOfExprTypePtr = cast<TypeOfExprType>(TypePtr);3898QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType();3899std::string TypeAsString = "(";3900RewriteBlockPointerType(TypeAsString, QT);3901TypeAsString += ")";3902ReplaceText(LocStart, endBuf-startBuf+1, TypeAsString);3903return;3904}3905// advance the location to startArgList.3906const char *argPtr = startBuf;39073908while (*argPtr++ && (argPtr < endBuf)) {3909switch (*argPtr) {3910case '^':3911// Replace the '^' with '*'.3912LocStart = LocStart.getLocWithOffset(argPtr-startBuf);3913ReplaceText(LocStart, 1, "*");3914break;3915}3916}3917}39183919void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {3920SourceLocation DeclLoc = FD->getLocation();3921unsigned parenCount = 0;39223923// We have 1 or more arguments that have closure pointers.3924const char *startBuf = SM->getCharacterData(DeclLoc);3925const char *startArgList = strchr(startBuf, '(');39263927assert((*startArgList == '(') && "Rewriter fuzzy parser confused");39283929parenCount++;3930// advance the location to startArgList.3931DeclLoc = DeclLoc.getLocWithOffset(startArgList-startBuf);3932assert((DeclLoc.isValid()) && "Invalid DeclLoc");39333934const char *argPtr = startArgList;39353936while (*argPtr++ && parenCount) {3937switch (*argPtr) {3938case '^':3939// Replace the '^' with '*'.3940DeclLoc = DeclLoc.getLocWithOffset(argPtr-startArgList);3941ReplaceText(DeclLoc, 1, "*");3942break;3943case '(':3944parenCount++;3945break;3946case ')':3947parenCount--;3948break;3949}3950}3951}39523953bool RewriteObjC::PointerTypeTakesAnyBlockArguments(QualType QT) {3954const FunctionProtoType *FTP;3955const PointerType *PT = QT->getAs<PointerType>();3956if (PT) {3957FTP = PT->getPointeeType()->getAs<FunctionProtoType>();3958} else {3959const BlockPointerType *BPT = QT->getAs<BlockPointerType>();3960assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");3961FTP = BPT->getPointeeType()->getAs<FunctionProtoType>();3962}3963if (FTP) {3964for (const auto &I : FTP->param_types())3965if (isTopLevelBlockPointerType(I))3966return true;3967}3968return false;3969}39703971bool RewriteObjC::PointerTypeTakesAnyObjCQualifiedType(QualType QT) {3972const FunctionProtoType *FTP;3973const PointerType *PT = QT->getAs<PointerType>();3974if (PT) {3975FTP = PT->getPointeeType()->getAs<FunctionProtoType>();3976} else {3977const BlockPointerType *BPT = QT->getAs<BlockPointerType>();3978assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");3979FTP = BPT->getPointeeType()->getAs<FunctionProtoType>();3980}3981if (FTP) {3982for (const auto &I : FTP->param_types()) {3983if (I->isObjCQualifiedIdType())3984return true;3985if (I->isObjCObjectPointerType() &&3986I->getPointeeType()->isObjCQualifiedInterfaceType())3987return true;3988}39893990}3991return false;3992}39933994void RewriteObjC::GetExtentOfArgList(const char *Name, const char *&LParen,3995const char *&RParen) {3996const char *argPtr = strchr(Name, '(');3997assert((*argPtr == '(') && "Rewriter fuzzy parser confused");39983999LParen = argPtr; // output the start.4000argPtr++; // skip past the left paren.4001unsigned parenCount = 1;40024003while (*argPtr && parenCount) {4004switch (*argPtr) {4005case '(': parenCount++; break;4006case ')': parenCount--; break;4007default: break;4008}4009if (parenCount) argPtr++;4010}4011assert((*argPtr == ')') && "Rewriter fuzzy parser confused");4012RParen = argPtr; // output the end4013}40144015void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {4016if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {4017RewriteBlockPointerFunctionArgs(FD);4018return;4019}4020// Handle Variables and Typedefs.4021SourceLocation DeclLoc = ND->getLocation();4022QualType DeclT;4023if (VarDecl *VD = dyn_cast<VarDecl>(ND))4024DeclT = VD->getType();4025else if (TypedefNameDecl *TDD = dyn_cast<TypedefNameDecl>(ND))4026DeclT = TDD->getUnderlyingType();4027else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND))4028DeclT = FD->getType();4029else4030llvm_unreachable("RewriteBlockPointerDecl(): Decl type not yet handled");40314032const char *startBuf = SM->getCharacterData(DeclLoc);4033const char *endBuf = startBuf;4034// scan backward (from the decl location) for the end of the previous decl.4035while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart)4036startBuf--;4037SourceLocation Start = DeclLoc.getLocWithOffset(startBuf-endBuf);4038std::string buf;4039unsigned OrigLength=0;4040// *startBuf != '^' if we are dealing with a pointer to function that4041// may take block argument types (which will be handled below).4042if (*startBuf == '^') {4043// Replace the '^' with '*', computing a negative offset.4044buf = '*';4045startBuf++;4046OrigLength++;4047}4048while (*startBuf != ')') {4049buf += *startBuf;4050startBuf++;4051OrigLength++;4052}4053buf += ')';4054OrigLength++;40554056if (PointerTypeTakesAnyBlockArguments(DeclT) ||4057PointerTypeTakesAnyObjCQualifiedType(DeclT)) {4058// Replace the '^' with '*' for arguments.4059// Replace id<P> with id/*<>*/4060DeclLoc = ND->getLocation();4061startBuf = SM->getCharacterData(DeclLoc);4062const char *argListBegin, *argListEnd;4063GetExtentOfArgList(startBuf, argListBegin, argListEnd);4064while (argListBegin < argListEnd) {4065if (*argListBegin == '^')4066buf += '*';4067else if (*argListBegin == '<') {4068buf += "/*";4069buf += *argListBegin++;4070OrigLength++;4071while (*argListBegin != '>') {4072buf += *argListBegin++;4073OrigLength++;4074}4075buf += *argListBegin;4076buf += "*/";4077}4078else4079buf += *argListBegin;4080argListBegin++;4081OrigLength++;4082}4083buf += ')';4084OrigLength++;4085}4086ReplaceText(Start, OrigLength, buf);4087}40884089/// SynthesizeByrefCopyDestroyHelper - This routine synthesizes:4090/// void __Block_byref_id_object_copy(struct Block_byref_id_object *dst,4091/// struct Block_byref_id_object *src) {4092/// _Block_object_assign (&_dest->object, _src->object,4093/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT4094/// [|BLOCK_FIELD_IS_WEAK]) // object4095/// _Block_object_assign(&_dest->object, _src->object,4096/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK4097/// [|BLOCK_FIELD_IS_WEAK]) // block4098/// }4099/// And:4100/// void __Block_byref_id_object_dispose(struct Block_byref_id_object *_src) {4101/// _Block_object_dispose(_src->object,4102/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT4103/// [|BLOCK_FIELD_IS_WEAK]) // object4104/// _Block_object_dispose(_src->object,4105/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK4106/// [|BLOCK_FIELD_IS_WEAK]) // block4107/// }41084109std::string RewriteObjC::SynthesizeByrefCopyDestroyHelper(VarDecl *VD,4110int flag) {4111std::string S;4112if (CopyDestroyCache.count(flag))4113return S;4114CopyDestroyCache.insert(flag);4115S = "static void __Block_byref_id_object_copy_";4116S += utostr(flag);4117S += "(void *dst, void *src) {\n";41184119// offset into the object pointer is computed as:4120// void * + void* + int + int + void* + void *4121unsigned IntSize =4122static_cast<unsigned>(Context->getTypeSize(Context->IntTy));4123unsigned VoidPtrSize =4124static_cast<unsigned>(Context->getTypeSize(Context->VoidPtrTy));41254126unsigned offset = (VoidPtrSize*4 + IntSize + IntSize)/Context->getCharWidth();4127S += " _Block_object_assign((char*)dst + ";4128S += utostr(offset);4129S += ", *(void * *) ((char*)src + ";4130S += utostr(offset);4131S += "), ";4132S += utostr(flag);4133S += ");\n}\n";41344135S += "static void __Block_byref_id_object_dispose_";4136S += utostr(flag);4137S += "(void *src) {\n";4138S += " _Block_object_dispose(*(void * *) ((char*)src + ";4139S += utostr(offset);4140S += "), ";4141S += utostr(flag);4142S += ");\n}\n";4143return S;4144}41454146/// RewriteByRefVar - For each __block typex ND variable this routine transforms4147/// the declaration into:4148/// struct __Block_byref_ND {4149/// void *__isa; // NULL for everything except __weak pointers4150/// struct __Block_byref_ND *__forwarding;4151/// int32_t __flags;4152/// int32_t __size;4153/// void *__Block_byref_id_object_copy; // If variable is __block ObjC object4154/// void *__Block_byref_id_object_dispose; // If variable is __block ObjC object4155/// typex ND;4156/// };4157///4158/// It then replaces declaration of ND variable with:4159/// struct __Block_byref_ND ND = {__isa=0B, __forwarding=&ND, __flags=some_flag,4160/// __size=sizeof(struct __Block_byref_ND),4161/// ND=initializer-if-any};4162///4163///4164void RewriteObjC::RewriteByRefVar(VarDecl *ND) {4165// Insert declaration for the function in which block literal is4166// used.4167if (CurFunctionDeclToDeclareForBlock)4168RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock);4169int flag = 0;4170int isa = 0;4171SourceLocation DeclLoc = ND->getTypeSpecStartLoc();4172if (DeclLoc.isInvalid())4173// If type location is missing, it is because of missing type (a warning).4174// Use variable's location which is good for this case.4175DeclLoc = ND->getLocation();4176const char *startBuf = SM->getCharacterData(DeclLoc);4177SourceLocation X = ND->getEndLoc();4178X = SM->getExpansionLoc(X);4179const char *endBuf = SM->getCharacterData(X);4180std::string Name(ND->getNameAsString());4181std::string ByrefType;4182RewriteByRefString(ByrefType, Name, ND, true);4183ByrefType += " {\n";4184ByrefType += " void *__isa;\n";4185RewriteByRefString(ByrefType, Name, ND);4186ByrefType += " *__forwarding;\n";4187ByrefType += " int __flags;\n";4188ByrefType += " int __size;\n";4189// Add void *__Block_byref_id_object_copy;4190// void *__Block_byref_id_object_dispose; if needed.4191QualType Ty = ND->getType();4192bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty, ND);4193if (HasCopyAndDispose) {4194ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n";4195ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n";4196}41974198QualType T = Ty;4199(void)convertBlockPointerToFunctionPointer(T);4200T.getAsStringInternal(Name, Context->getPrintingPolicy());42014202ByrefType += " " + Name + ";\n";4203ByrefType += "};\n";4204// Insert this type in global scope. It is needed by helper function.4205SourceLocation FunLocStart;4206if (CurFunctionDef)4207FunLocStart = CurFunctionDef->getTypeSpecStartLoc();4208else {4209assert(CurMethodDef && "RewriteByRefVar - CurMethodDef is null");4210FunLocStart = CurMethodDef->getBeginLoc();4211}4212InsertText(FunLocStart, ByrefType);4213if (Ty.isObjCGCWeak()) {4214flag |= BLOCK_FIELD_IS_WEAK;4215isa = 1;4216}42174218if (HasCopyAndDispose) {4219flag = BLOCK_BYREF_CALLER;4220QualType Ty = ND->getType();4221// FIXME. Handle __weak variable (BLOCK_FIELD_IS_WEAK) as well.4222if (Ty->isBlockPointerType())4223flag |= BLOCK_FIELD_IS_BLOCK;4224else4225flag |= BLOCK_FIELD_IS_OBJECT;4226std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag);4227if (!HF.empty())4228InsertText(FunLocStart, HF);4229}42304231// struct __Block_byref_ND ND =4232// {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND),4233// initializer-if-any};4234bool hasInit = (ND->getInit() != nullptr);4235unsigned flags = 0;4236if (HasCopyAndDispose)4237flags |= BLOCK_HAS_COPY_DISPOSE;4238Name = ND->getNameAsString();4239ByrefType.clear();4240RewriteByRefString(ByrefType, Name, ND);4241std::string ForwardingCastType("(");4242ForwardingCastType += ByrefType + " *)";4243if (!hasInit) {4244ByrefType += " " + Name + " = {(void*)";4245ByrefType += utostr(isa);4246ByrefType += "," + ForwardingCastType + "&" + Name + ", ";4247ByrefType += utostr(flags);4248ByrefType += ", ";4249ByrefType += "sizeof(";4250RewriteByRefString(ByrefType, Name, ND);4251ByrefType += ")";4252if (HasCopyAndDispose) {4253ByrefType += ", __Block_byref_id_object_copy_";4254ByrefType += utostr(flag);4255ByrefType += ", __Block_byref_id_object_dispose_";4256ByrefType += utostr(flag);4257}4258ByrefType += "};\n";4259unsigned nameSize = Name.size();4260// for block or function pointer declaration. Name is already4261// part of the declaration.4262if (Ty->isBlockPointerType() || Ty->isFunctionPointerType())4263nameSize = 1;4264ReplaceText(DeclLoc, endBuf-startBuf+nameSize, ByrefType);4265}4266else {4267SourceLocation startLoc;4268Expr *E = ND->getInit();4269if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E))4270startLoc = ECE->getLParenLoc();4271else4272startLoc = E->getBeginLoc();4273startLoc = SM->getExpansionLoc(startLoc);4274endBuf = SM->getCharacterData(startLoc);4275ByrefType += " " + Name;4276ByrefType += " = {(void*)";4277ByrefType += utostr(isa);4278ByrefType += "," + ForwardingCastType + "&" + Name + ", ";4279ByrefType += utostr(flags);4280ByrefType += ", ";4281ByrefType += "sizeof(";4282RewriteByRefString(ByrefType, Name, ND);4283ByrefType += "), ";4284if (HasCopyAndDispose) {4285ByrefType += "__Block_byref_id_object_copy_";4286ByrefType += utostr(flag);4287ByrefType += ", __Block_byref_id_object_dispose_";4288ByrefType += utostr(flag);4289ByrefType += ", ";4290}4291ReplaceText(DeclLoc, endBuf-startBuf, ByrefType);42924293// Complete the newly synthesized compound expression by inserting a right4294// curly brace before the end of the declaration.4295// FIXME: This approach avoids rewriting the initializer expression. It4296// also assumes there is only one declarator. For example, the following4297// isn't currently supported by this routine (in general):4298//4299// double __block BYREFVAR = 1.34, BYREFVAR2 = 1.37;4300//4301const char *startInitializerBuf = SM->getCharacterData(startLoc);4302const char *semiBuf = strchr(startInitializerBuf, ';');4303assert((*semiBuf == ';') && "RewriteByRefVar: can't find ';'");4304SourceLocation semiLoc =4305startLoc.getLocWithOffset(semiBuf-startInitializerBuf);43064307InsertText(semiLoc, "}");4308}4309}43104311void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) {4312// Add initializers for any closure decl refs.4313GetBlockDeclRefExprs(Exp->getBody());4314if (BlockDeclRefs.size()) {4315// Unique all "by copy" declarations.4316for (unsigned i = 0; i < BlockDeclRefs.size(); i++)4317if (!BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>()) {4318if (!BlockByCopyDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) {4319BlockByCopyDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl());4320BlockByCopyDecls.push_back(BlockDeclRefs[i]->getDecl());4321}4322}4323// Unique all "by ref" declarations.4324for (unsigned i = 0; i < BlockDeclRefs.size(); i++)4325if (BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>()) {4326if (!BlockByRefDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) {4327BlockByRefDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl());4328BlockByRefDecls.push_back(BlockDeclRefs[i]->getDecl());4329}4330}4331// Find any imported blocks...they will need special attention.4332for (unsigned i = 0; i < BlockDeclRefs.size(); i++)4333if (BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>() ||4334BlockDeclRefs[i]->getType()->isObjCObjectPointerType() ||4335BlockDeclRefs[i]->getType()->isBlockPointerType())4336ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl());4337}4338}43394340FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(StringRef name) {4341IdentifierInfo *ID = &Context->Idents.get(name);4342QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy);4343return FunctionDecl::Create(*Context, TUDecl, SourceLocation(),4344SourceLocation(), ID, FType, nullptr, SC_Extern,4345false, false);4346}43474348Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,4349const SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs) {4350const BlockDecl *block = Exp->getBlockDecl();4351Blocks.push_back(Exp);43524353CollectBlockDeclRefInfo(Exp);43544355// Add inner imported variables now used in current block.4356int countOfInnerDecls = 0;4357if (!InnerBlockDeclRefs.empty()) {4358for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) {4359DeclRefExpr *Exp = InnerBlockDeclRefs[i];4360ValueDecl *VD = Exp->getDecl();4361if (!VD->hasAttr<BlocksAttr>() && !BlockByCopyDeclsPtrSet.count(VD)) {4362// We need to save the copied-in variables in nested4363// blocks because it is needed at the end for some of the API generations.4364// See SynthesizeBlockLiterals routine.4365InnerDeclRefs.push_back(Exp); countOfInnerDecls++;4366BlockDeclRefs.push_back(Exp);4367BlockByCopyDeclsPtrSet.insert(VD);4368BlockByCopyDecls.push_back(VD);4369}4370if (VD->hasAttr<BlocksAttr>() && !BlockByRefDeclsPtrSet.count(VD)) {4371InnerDeclRefs.push_back(Exp); countOfInnerDecls++;4372BlockDeclRefs.push_back(Exp);4373BlockByRefDeclsPtrSet.insert(VD);4374BlockByRefDecls.push_back(VD);4375}4376}4377// Find any imported blocks...they will need special attention.4378for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++)4379if (InnerBlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>() ||4380InnerBlockDeclRefs[i]->getType()->isObjCObjectPointerType() ||4381InnerBlockDeclRefs[i]->getType()->isBlockPointerType())4382ImportedBlockDecls.insert(InnerBlockDeclRefs[i]->getDecl());4383}4384InnerDeclRefsCount.push_back(countOfInnerDecls);43854386std::string FuncName;43874388if (CurFunctionDef)4389FuncName = CurFunctionDef->getNameAsString();4390else if (CurMethodDef)4391BuildUniqueMethodName(FuncName, CurMethodDef);4392else if (GlobalVarDecl)4393FuncName = std::string(GlobalVarDecl->getNameAsString());43944395std::string BlockNumber = utostr(Blocks.size()-1);43964397std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber;4398std::string Func = "__" + FuncName + "_block_func_" + BlockNumber;43994400// Get a pointer to the function type so we can cast appropriately.4401QualType BFT = convertFunctionTypeOfBlocks(Exp->getFunctionType());4402QualType FType = Context->getPointerType(BFT);44034404FunctionDecl *FD;4405Expr *NewRep;44064407// Simulate a constructor call...4408FD = SynthBlockInitFunctionDecl(Tag);4409DeclRefExpr *DRE = new (Context)4410DeclRefExpr(*Context, FD, false, FType, VK_PRValue, SourceLocation());44114412SmallVector<Expr*, 4> InitExprs;44134414// Initialize the block function.4415FD = SynthBlockInitFunctionDecl(Func);4416DeclRefExpr *Arg = new (Context) DeclRefExpr(4417*Context, FD, false, FD->getType(), VK_LValue, SourceLocation());4418CastExpr *castExpr =4419NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, CK_BitCast, Arg);4420InitExprs.push_back(castExpr);44214422// Initialize the block descriptor.4423std::string DescData = "__" + FuncName + "_block_desc_" + BlockNumber + "_DATA";44244425VarDecl *NewVD = VarDecl::Create(4426*Context, TUDecl, SourceLocation(), SourceLocation(),4427&Context->Idents.get(DescData), Context->VoidPtrTy, nullptr, SC_Static);4428UnaryOperator *DescRefExpr = UnaryOperator::Create(4429const_cast<ASTContext &>(*Context),4430new (Context) DeclRefExpr(*Context, NewVD, false, Context->VoidPtrTy,4431VK_LValue, SourceLocation()),4432UO_AddrOf, Context->getPointerType(Context->VoidPtrTy), VK_PRValue,4433OK_Ordinary, SourceLocation(), false, FPOptionsOverride());4434InitExprs.push_back(DescRefExpr);44354436// Add initializers for any closure decl refs.4437if (BlockDeclRefs.size()) {4438Expr *Exp;4439// Output all "by copy" declarations.4440for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(),4441E = BlockByCopyDecls.end(); I != E; ++I) {4442if (isObjCType((*I)->getType())) {4443// FIXME: Conform to ABI ([[obj retain] autorelease]).4444FD = SynthBlockInitFunctionDecl((*I)->getName());4445Exp = new (Context) DeclRefExpr(*Context, FD, false, FD->getType(),4446VK_LValue, SourceLocation());4447if (HasLocalVariableExternalStorage(*I)) {4448QualType QT = (*I)->getType();4449QT = Context->getPointerType(QT);4450Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), Exp,4451UO_AddrOf, QT, VK_PRValue, OK_Ordinary,4452SourceLocation(), false,4453FPOptionsOverride());4454}4455} else if (isTopLevelBlockPointerType((*I)->getType())) {4456FD = SynthBlockInitFunctionDecl((*I)->getName());4457Arg = new (Context) DeclRefExpr(*Context, FD, false, FD->getType(),4458VK_LValue, SourceLocation());4459Exp = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, CK_BitCast,4460Arg);4461} else {4462FD = SynthBlockInitFunctionDecl((*I)->getName());4463Exp = new (Context) DeclRefExpr(*Context, FD, false, FD->getType(),4464VK_LValue, SourceLocation());4465if (HasLocalVariableExternalStorage(*I)) {4466QualType QT = (*I)->getType();4467QT = Context->getPointerType(QT);4468Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), Exp,4469UO_AddrOf, QT, VK_PRValue, OK_Ordinary,4470SourceLocation(), false,4471FPOptionsOverride());4472}4473}4474InitExprs.push_back(Exp);4475}4476// Output all "by ref" declarations.4477for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(),4478E = BlockByRefDecls.end(); I != E; ++I) {4479ValueDecl *ND = (*I);4480std::string Name(ND->getNameAsString());4481std::string RecName;4482RewriteByRefString(RecName, Name, ND, true);4483IdentifierInfo *II = &Context->Idents.get(RecName.c_str()4484+ sizeof("struct"));4485RecordDecl *RD =4486RecordDecl::Create(*Context, TagTypeKind::Struct, TUDecl,4487SourceLocation(), SourceLocation(), II);4488assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl");4489QualType castT = Context->getPointerType(Context->getTagDeclType(RD));44904491FD = SynthBlockInitFunctionDecl((*I)->getName());4492Exp = new (Context) DeclRefExpr(*Context, FD, false, FD->getType(),4493VK_LValue, SourceLocation());4494bool isNestedCapturedVar = false;4495if (block)4496for (const auto &CI : block->captures()) {4497const VarDecl *variable = CI.getVariable();4498if (variable == ND && CI.isNested()) {4499assert (CI.isByRef() &&4500"SynthBlockInitExpr - captured block variable is not byref");4501isNestedCapturedVar = true;4502break;4503}4504}4505// captured nested byref variable has its address passed. Do not take4506// its address again.4507if (!isNestedCapturedVar)4508Exp = UnaryOperator::Create(4509const_cast<ASTContext &>(*Context), Exp, UO_AddrOf,4510Context->getPointerType(Exp->getType()), VK_PRValue, OK_Ordinary,4511SourceLocation(), false, FPOptionsOverride());4512Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp);4513InitExprs.push_back(Exp);4514}4515}4516if (ImportedBlockDecls.size()) {4517// generate BLOCK_HAS_COPY_DISPOSE(have helper funcs) | BLOCK_HAS_DESCRIPTOR4518int flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR);4519unsigned IntSize =4520static_cast<unsigned>(Context->getTypeSize(Context->IntTy));4521Expr *FlagExp = IntegerLiteral::Create(*Context, llvm::APInt(IntSize, flag),4522Context->IntTy, SourceLocation());4523InitExprs.push_back(FlagExp);4524}4525NewRep = CallExpr::Create(*Context, DRE, InitExprs, FType, VK_LValue,4526SourceLocation(), FPOptionsOverride());4527NewRep = UnaryOperator::Create(4528const_cast<ASTContext &>(*Context), NewRep, UO_AddrOf,4529Context->getPointerType(NewRep->getType()), VK_PRValue, OK_Ordinary,4530SourceLocation(), false, FPOptionsOverride());4531NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast,4532NewRep);4533BlockDeclRefs.clear();4534BlockByRefDecls.clear();4535BlockByRefDeclsPtrSet.clear();4536BlockByCopyDecls.clear();4537BlockByCopyDeclsPtrSet.clear();4538ImportedBlockDecls.clear();4539return NewRep;4540}45414542bool RewriteObjC::IsDeclStmtInForeachHeader(DeclStmt *DS) {4543if (const ObjCForCollectionStmt * CS =4544dyn_cast<ObjCForCollectionStmt>(Stmts.back()))4545return CS->getElement() == DS;4546return false;4547}45484549//===----------------------------------------------------------------------===//4550// Function Body / Expression rewriting4551//===----------------------------------------------------------------------===//45524553Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {4554if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||4555isa<DoStmt>(S) || isa<ForStmt>(S))4556Stmts.push_back(S);4557else if (isa<ObjCForCollectionStmt>(S)) {4558Stmts.push_back(S);4559ObjCBcLabelNo.push_back(++BcLabelCount);4560}45614562// Pseudo-object operations and ivar references need special4563// treatment because we're going to recursively rewrite them.4564if (PseudoObjectExpr *PseudoOp = dyn_cast<PseudoObjectExpr>(S)) {4565if (isa<BinaryOperator>(PseudoOp->getSyntacticForm())) {4566return RewritePropertyOrImplicitSetter(PseudoOp);4567} else {4568return RewritePropertyOrImplicitGetter(PseudoOp);4569}4570} else if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) {4571return RewriteObjCIvarRefExpr(IvarRefExpr);4572}45734574SourceRange OrigStmtRange = S->getSourceRange();45754576// Perform a bottom up rewrite of all children.4577for (Stmt *&childStmt : S->children())4578if (childStmt) {4579Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(childStmt);4580if (newStmt) {4581childStmt = newStmt;4582}4583}45844585if (BlockExpr *BE = dyn_cast<BlockExpr>(S)) {4586SmallVector<DeclRefExpr *, 8> InnerBlockDeclRefs;4587llvm::SmallPtrSet<const DeclContext *, 8> InnerContexts;4588InnerContexts.insert(BE->getBlockDecl());4589ImportedLocalExternalDecls.clear();4590GetInnerBlockDeclRefExprs(BE->getBody(),4591InnerBlockDeclRefs, InnerContexts);4592// Rewrite the block body in place.4593Stmt *SaveCurrentBody = CurrentBody;4594CurrentBody = BE->getBody();4595PropParentMap = nullptr;4596// block literal on rhs of a property-dot-sytax assignment4597// must be replaced by its synthesize ast so getRewrittenText4598// works as expected. In this case, what actually ends up on RHS4599// is the blockTranscribed which is the helper function for the4600// block literal; as in: self.c = ^() {[ace ARR];};4601bool saveDisableReplaceStmt = DisableReplaceStmt;4602DisableReplaceStmt = false;4603RewriteFunctionBodyOrGlobalInitializer(BE->getBody());4604DisableReplaceStmt = saveDisableReplaceStmt;4605CurrentBody = SaveCurrentBody;4606PropParentMap = nullptr;4607ImportedLocalExternalDecls.clear();4608// Now we snarf the rewritten text and stash it away for later use.4609std::string Str = Rewrite.getRewrittenText(BE->getSourceRange());4610RewrittenBlockExprs[BE] = Str;46114612Stmt *blockTranscribed = SynthBlockInitExpr(BE, InnerBlockDeclRefs);46134614//blockTranscribed->dump();4615ReplaceStmt(S, blockTranscribed);4616return blockTranscribed;4617}4618// Handle specific things.4619if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))4620return RewriteAtEncode(AtEncode);46214622if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S))4623return RewriteAtSelector(AtSelector);46244625if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S))4626return RewriteObjCStringLiteral(AtString);46274628if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {4629#if 04630// Before we rewrite it, put the original message expression in a comment.4631SourceLocation startLoc = MessExpr->getBeginLoc();4632SourceLocation endLoc = MessExpr->getEndLoc();46334634const char *startBuf = SM->getCharacterData(startLoc);4635const char *endBuf = SM->getCharacterData(endLoc);46364637std::string messString;4638messString += "// ";4639messString.append(startBuf, endBuf-startBuf+1);4640messString += "\n";46414642// FIXME: Missing definition of4643// InsertText(clang::SourceLocation, char const*, unsigned int).4644// InsertText(startLoc, messString);4645// Tried this, but it didn't work either...4646// ReplaceText(startLoc, 0, messString.c_str(), messString.size());4647#endif4648return RewriteMessageExpr(MessExpr);4649}46504651if (ObjCAtTryStmt *StmtTry = dyn_cast<ObjCAtTryStmt>(S))4652return RewriteObjCTryStmt(StmtTry);46534654if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast<ObjCAtSynchronizedStmt>(S))4655return RewriteObjCSynchronizedStmt(StmtTry);46564657if (ObjCAtThrowStmt *StmtThrow = dyn_cast<ObjCAtThrowStmt>(S))4658return RewriteObjCThrowStmt(StmtThrow);46594660if (ObjCProtocolExpr *ProtocolExp = dyn_cast<ObjCProtocolExpr>(S))4661return RewriteObjCProtocolExpr(ProtocolExp);46624663if (ObjCForCollectionStmt *StmtForCollection =4664dyn_cast<ObjCForCollectionStmt>(S))4665return RewriteObjCForCollectionStmt(StmtForCollection,4666OrigStmtRange.getEnd());4667if (BreakStmt *StmtBreakStmt =4668dyn_cast<BreakStmt>(S))4669return RewriteBreakStmt(StmtBreakStmt);4670if (ContinueStmt *StmtContinueStmt =4671dyn_cast<ContinueStmt>(S))4672return RewriteContinueStmt(StmtContinueStmt);46734674// Need to check for protocol refs (id <P>, Foo <P> *) in variable decls4675// and cast exprs.4676if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {4677// FIXME: What we're doing here is modifying the type-specifier that4678// precedes the first Decl. In the future the DeclGroup should have4679// a separate type-specifier that we can rewrite.4680// NOTE: We need to avoid rewriting the DeclStmt if it is within4681// the context of an ObjCForCollectionStmt. For example:4682// NSArray *someArray;4683// for (id <FooProtocol> index in someArray) ;4684// This is because RewriteObjCForCollectionStmt() does textual rewriting4685// and it depends on the original text locations/positions.4686if (Stmts.empty() || !IsDeclStmtInForeachHeader(DS))4687RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin());46884689// Blocks rewrite rules.4690for (auto *SD : DS->decls()) {4691if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) {4692if (isTopLevelBlockPointerType(ND->getType()))4693RewriteBlockPointerDecl(ND);4694else if (ND->getType()->isFunctionPointerType())4695CheckFunctionPointerDecl(ND->getType(), ND);4696if (VarDecl *VD = dyn_cast<VarDecl>(SD)) {4697if (VD->hasAttr<BlocksAttr>()) {4698static unsigned uniqueByrefDeclCount = 0;4699assert(!BlockByRefDeclNo.count(ND) &&4700"RewriteFunctionBodyOrGlobalInitializer: Duplicate byref decl");4701BlockByRefDeclNo[ND] = uniqueByrefDeclCount++;4702RewriteByRefVar(VD);4703}4704else4705RewriteTypeOfDecl(VD);4706}4707}4708if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) {4709if (isTopLevelBlockPointerType(TD->getUnderlyingType()))4710RewriteBlockPointerDecl(TD);4711else if (TD->getUnderlyingType()->isFunctionPointerType())4712CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);4713}4714}4715}47164717if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(S))4718RewriteObjCQualifiedInterfaceTypes(CE);47194720if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||4721isa<DoStmt>(S) || isa<ForStmt>(S)) {4722assert(!Stmts.empty() && "Statement stack is empty");4723assert ((isa<SwitchStmt>(Stmts.back()) || isa<WhileStmt>(Stmts.back()) ||4724isa<DoStmt>(Stmts.back()) || isa<ForStmt>(Stmts.back()))4725&& "Statement stack mismatch");4726Stmts.pop_back();4727}4728// Handle blocks rewriting.4729if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {4730ValueDecl *VD = DRE->getDecl();4731if (VD->hasAttr<BlocksAttr>())4732return RewriteBlockDeclRefExpr(DRE);4733if (HasLocalVariableExternalStorage(VD))4734return RewriteLocalVariableExternalStorage(DRE);4735}47364737if (CallExpr *CE = dyn_cast<CallExpr>(S)) {4738if (CE->getCallee()->getType()->isBlockPointerType()) {4739Stmt *BlockCall = SynthesizeBlockCall(CE, CE->getCallee());4740ReplaceStmt(S, BlockCall);4741return BlockCall;4742}4743}4744if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(S)) {4745RewriteCastExpr(CE);4746}4747#if 04748if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) {4749CastExpr *Replacement = new (Context) CastExpr(ICE->getType(),4750ICE->getSubExpr(),4751SourceLocation());4752// Get the new text.4753std::string SStr;4754llvm::raw_string_ostream Buf(SStr);4755Replacement->printPretty(Buf);4756const std::string &Str = Buf.str();47574758printf("CAST = %s\n", &Str[0]);4759InsertText(ICE->getSubExpr()->getBeginLoc(), Str);4760delete S;4761return Replacement;4762}4763#endif4764// Return this stmt unmodified.4765return S;4766}47674768void RewriteObjC::RewriteRecordBody(RecordDecl *RD) {4769for (auto *FD : RD->fields()) {4770if (isTopLevelBlockPointerType(FD->getType()))4771RewriteBlockPointerDecl(FD);4772if (FD->getType()->isObjCQualifiedIdType() ||4773FD->getType()->isObjCQualifiedInterfaceType())4774RewriteObjCQualifiedInterfaceTypes(FD);4775}4776}47774778/// HandleDeclInMainFile - This is called for each top-level decl defined in the4779/// main file of the input.4780void RewriteObjC::HandleDeclInMainFile(Decl *D) {4781switch (D->getKind()) {4782case Decl::Function: {4783FunctionDecl *FD = cast<FunctionDecl>(D);4784if (FD->isOverloadedOperator())4785return;47864787// Since function prototypes don't have ParmDecl's, we check the function4788// prototype. This enables us to rewrite function declarations and4789// definitions using the same code.4790RewriteBlocksInFunctionProtoType(FD->getType(), FD);47914792if (!FD->isThisDeclarationADefinition())4793break;47944795// FIXME: If this should support Obj-C++, support CXXTryStmt4796if (CompoundStmt *Body = dyn_cast_or_null<CompoundStmt>(FD->getBody())) {4797CurFunctionDef = FD;4798CurFunctionDeclToDeclareForBlock = FD;4799CurrentBody = Body;4800Body =4801cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));4802FD->setBody(Body);4803CurrentBody = nullptr;4804if (PropParentMap) {4805delete PropParentMap;4806PropParentMap = nullptr;4807}4808// This synthesizes and inserts the block "impl" struct, invoke function,4809// and any copy/dispose helper functions.4810InsertBlockLiteralsWithinFunction(FD);4811CurFunctionDef = nullptr;4812CurFunctionDeclToDeclareForBlock = nullptr;4813}4814break;4815}4816case Decl::ObjCMethod: {4817ObjCMethodDecl *MD = cast<ObjCMethodDecl>(D);4818if (CompoundStmt *Body = MD->getCompoundBody()) {4819CurMethodDef = MD;4820CurrentBody = Body;4821Body =4822cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));4823MD->setBody(Body);4824CurrentBody = nullptr;4825if (PropParentMap) {4826delete PropParentMap;4827PropParentMap = nullptr;4828}4829InsertBlockLiteralsWithinMethod(MD);4830CurMethodDef = nullptr;4831}4832break;4833}4834case Decl::ObjCImplementation: {4835ObjCImplementationDecl *CI = cast<ObjCImplementationDecl>(D);4836ClassImplementation.push_back(CI);4837break;4838}4839case Decl::ObjCCategoryImpl: {4840ObjCCategoryImplDecl *CI = cast<ObjCCategoryImplDecl>(D);4841CategoryImplementation.push_back(CI);4842break;4843}4844case Decl::Var: {4845VarDecl *VD = cast<VarDecl>(D);4846RewriteObjCQualifiedInterfaceTypes(VD);4847if (isTopLevelBlockPointerType(VD->getType()))4848RewriteBlockPointerDecl(VD);4849else if (VD->getType()->isFunctionPointerType()) {4850CheckFunctionPointerDecl(VD->getType(), VD);4851if (VD->getInit()) {4852if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) {4853RewriteCastExpr(CE);4854}4855}4856} else if (VD->getType()->isRecordType()) {4857RecordDecl *RD = VD->getType()->castAs<RecordType>()->getDecl();4858if (RD->isCompleteDefinition())4859RewriteRecordBody(RD);4860}4861if (VD->getInit()) {4862GlobalVarDecl = VD;4863CurrentBody = VD->getInit();4864RewriteFunctionBodyOrGlobalInitializer(VD->getInit());4865CurrentBody = nullptr;4866if (PropParentMap) {4867delete PropParentMap;4868PropParentMap = nullptr;4869}4870SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName());4871GlobalVarDecl = nullptr;48724873// This is needed for blocks.4874if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) {4875RewriteCastExpr(CE);4876}4877}4878break;4879}4880case Decl::TypeAlias:4881case Decl::Typedef: {4882if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {4883if (isTopLevelBlockPointerType(TD->getUnderlyingType()))4884RewriteBlockPointerDecl(TD);4885else if (TD->getUnderlyingType()->isFunctionPointerType())4886CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);4887}4888break;4889}4890case Decl::CXXRecord:4891case Decl::Record: {4892RecordDecl *RD = cast<RecordDecl>(D);4893if (RD->isCompleteDefinition())4894RewriteRecordBody(RD);4895break;4896}4897default:4898break;4899}4900// Nothing yet.4901}49024903void RewriteObjC::HandleTranslationUnit(ASTContext &C) {4904if (Diags.hasErrorOccurred())4905return;49064907RewriteInclude();49084909// Here's a great place to add any extra declarations that may be needed.4910// Write out meta data for each @protocol(<expr>).4911for (ObjCProtocolDecl *ProtDecl : ProtocolExprDecls)4912RewriteObjCProtocolMetaData(ProtDecl, "", "", Preamble);49134914InsertText(SM->getLocForStartOfFile(MainFileID), Preamble, false);4915if (ClassImplementation.size() || CategoryImplementation.size())4916RewriteImplementations();49174918// Get the buffer corresponding to MainFileID. If we haven't changed it, then4919// we are done.4920if (const RewriteBuffer *RewriteBuf =4921Rewrite.getRewriteBufferFor(MainFileID)) {4922//printf("Changed:\n");4923*OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());4924} else {4925llvm::errs() << "No changes\n";4926}49274928if (ClassImplementation.size() || CategoryImplementation.size() ||4929ProtocolExprDecls.size()) {4930// Rewrite Objective-c meta data*4931std::string ResultStr;4932RewriteMetaDataIntoBuffer(ResultStr);4933// Emit metadata.4934*OutFile << ResultStr;4935}4936OutFile->flush();4937}49384939void RewriteObjCFragileABI::Initialize(ASTContext &context) {4940InitializeCommon(context);49414942// declaring objc_selector outside the parameter list removes a silly4943// scope related warning...4944if (IsHeader)4945Preamble = "#pragma once\n";4946Preamble += "struct objc_selector; struct objc_class;\n";4947Preamble += "struct __rw_objc_super { struct objc_object *object; ";4948Preamble += "struct objc_object *superClass; ";4949if (LangOpts.MicrosoftExt) {4950// Add a constructor for creating temporary objects.4951Preamble += "__rw_objc_super(struct objc_object *o, struct objc_object *s) "4952": ";4953Preamble += "object(o), superClass(s) {} ";4954}4955Preamble += "};\n";4956Preamble += "#ifndef _REWRITER_typedef_Protocol\n";4957Preamble += "typedef struct objc_object Protocol;\n";4958Preamble += "#define _REWRITER_typedef_Protocol\n";4959Preamble += "#endif\n";4960if (LangOpts.MicrosoftExt) {4961Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n";4962Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n";4963} else4964Preamble += "#define __OBJC_RW_DLLIMPORT extern\n";4965Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend";4966Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";4967Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper";4968Preamble += "(struct objc_super *, struct objc_selector *, ...);\n";4969Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSend_stret";4970Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";4971Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSendSuper_stret";4972Preamble += "(struct objc_super *, struct objc_selector *, ...);\n";4973Preamble += "__OBJC_RW_DLLIMPORT double objc_msgSend_fpret";4974Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";4975Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getClass";4976Preamble += "(const char *);\n";4977Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass";4978Preamble += "(struct objc_class *);\n";4979Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getMetaClass";4980Preamble += "(const char *);\n";4981Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw(struct objc_object *);\n";4982Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_enter(void *);\n";4983Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_exit(void *);\n";4984Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_exception_extract(void *);\n";4985Preamble += "__OBJC_RW_DLLIMPORT int objc_exception_match";4986Preamble += "(struct objc_class *, struct objc_object *);\n";4987// @synchronized hooks.4988Preamble += "__OBJC_RW_DLLIMPORT int objc_sync_enter(struct objc_object *);\n";4989Preamble += "__OBJC_RW_DLLIMPORT int objc_sync_exit(struct objc_object *);\n";4990Preamble += "__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);\n";4991Preamble += "#ifndef __FASTENUMERATIONSTATE\n";4992Preamble += "struct __objcFastEnumerationState {\n\t";4993Preamble += "unsigned long state;\n\t";4994Preamble += "void **itemsPtr;\n\t";4995Preamble += "unsigned long *mutationsPtr;\n\t";4996Preamble += "unsigned long extra[5];\n};\n";4997Preamble += "__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);\n";4998Preamble += "#define __FASTENUMERATIONSTATE\n";4999Preamble += "#endif\n";5000Preamble += "#ifndef __NSCONSTANTSTRINGIMPL\n";5001Preamble += "struct __NSConstantStringImpl {\n";5002Preamble += " int *isa;\n";5003Preamble += " int flags;\n";5004Preamble += " char *str;\n";5005Preamble += " long length;\n";5006Preamble += "};\n";5007Preamble += "#ifdef CF_EXPORT_CONSTANT_STRING\n";5008Preamble += "extern \"C\" __declspec(dllexport) int __CFConstantStringClassReference[];\n";5009Preamble += "#else\n";5010Preamble += "__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];\n";5011Preamble += "#endif\n";5012Preamble += "#define __NSCONSTANTSTRINGIMPL\n";5013Preamble += "#endif\n";5014// Blocks preamble.5015Preamble += "#ifndef BLOCK_IMPL\n";5016Preamble += "#define BLOCK_IMPL\n";5017Preamble += "struct __block_impl {\n";5018Preamble += " void *isa;\n";5019Preamble += " int Flags;\n";5020Preamble += " int Reserved;\n";5021Preamble += " void *FuncPtr;\n";5022Preamble += "};\n";5023Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n";5024Preamble += "#ifdef __OBJC_EXPORT_BLOCKS\n";5025Preamble += "extern \"C\" __declspec(dllexport) "5026"void _Block_object_assign(void *, const void *, const int);\n";5027Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_dispose(const void *, const int);\n";5028Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n";5029Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n";5030Preamble += "#else\n";5031Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n";5032Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n";5033Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n";5034Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n";5035Preamble += "#endif\n";5036Preamble += "#endif\n";5037if (LangOpts.MicrosoftExt) {5038Preamble += "#undef __OBJC_RW_DLLIMPORT\n";5039Preamble += "#undef __OBJC_RW_STATICIMPORT\n";5040Preamble += "#ifndef KEEP_ATTRIBUTES\n"; // We use this for clang tests.5041Preamble += "#define __attribute__(X)\n";5042Preamble += "#endif\n";5043Preamble += "#define __weak\n";5044}5045else {5046Preamble += "#define __block\n";5047Preamble += "#define __weak\n";5048}5049// NOTE! Windows uses LLP64 for 64bit mode. So, cast pointer to long long5050// as this avoids warning in any 64bit/32bit compilation model.5051Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n";5052}50535054/// RewriteIvarOffsetComputation - This routine synthesizes computation of5055/// ivar offset.5056void RewriteObjCFragileABI::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,5057std::string &Result) {5058if (ivar->isBitField()) {5059// FIXME: The hack below doesn't work for bitfields. For now, we simply5060// place all bitfields at offset 0.5061Result += "0";5062} else {5063Result += "__OFFSETOFIVAR__(struct ";5064Result += ivar->getContainingInterface()->getNameAsString();5065if (LangOpts.MicrosoftExt)5066Result += "_IMPL";5067Result += ", ";5068Result += ivar->getNameAsString();5069Result += ")";5070}5071}50725073/// RewriteObjCProtocolMetaData - Rewrite protocols meta-data.5074void RewriteObjCFragileABI::RewriteObjCProtocolMetaData(5075ObjCProtocolDecl *PDecl, StringRef prefix,5076StringRef ClassName, std::string &Result) {5077static bool objc_protocol_methods = false;50785079// Output struct protocol_methods holder of method selector and type.5080if (!objc_protocol_methods && PDecl->hasDefinition()) {5081/* struct protocol_methods {5082SEL _cmd;5083char *method_types;5084}5085*/5086Result += "\nstruct _protocol_methods {\n";5087Result += "\tstruct objc_selector *_cmd;\n";5088Result += "\tchar *method_types;\n";5089Result += "};\n";50905091objc_protocol_methods = true;5092}5093// Do not synthesize the protocol more than once.5094if (ObjCSynthesizedProtocols.count(PDecl->getCanonicalDecl()))5095return;50965097if (ObjCProtocolDecl *Def = PDecl->getDefinition())5098PDecl = Def;50995100if (PDecl->instmeth_begin() != PDecl->instmeth_end()) {5101unsigned NumMethods = std::distance(PDecl->instmeth_begin(),5102PDecl->instmeth_end());5103/* struct _objc_protocol_method_list {5104int protocol_method_count;5105struct protocol_methods protocols[];5106}5107*/5108Result += "\nstatic struct {\n";5109Result += "\tint protocol_method_count;\n";5110Result += "\tstruct _protocol_methods protocol_methods[";5111Result += utostr(NumMethods);5112Result += "];\n} _OBJC_PROTOCOL_INSTANCE_METHODS_";5113Result += PDecl->getNameAsString();5114Result += " __attribute__ ((used, section (\"__OBJC, __cat_inst_meth\")))= "5115"{\n\t" + utostr(NumMethods) + "\n";51165117// Output instance methods declared in this protocol.5118for (ObjCProtocolDecl::instmeth_iterator5119I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();5120I != E; ++I) {5121if (I == PDecl->instmeth_begin())5122Result += "\t ,{{(struct objc_selector *)\"";5123else5124Result += "\t ,{(struct objc_selector *)\"";5125Result += (*I)->getSelector().getAsString();5126std::string MethodTypeString = Context->getObjCEncodingForMethodDecl(*I);5127Result += "\", \"";5128Result += MethodTypeString;5129Result += "\"}\n";5130}5131Result += "\t }\n};\n";5132}51335134// Output class methods declared in this protocol.5135unsigned NumMethods = std::distance(PDecl->classmeth_begin(),5136PDecl->classmeth_end());5137if (NumMethods > 0) {5138/* struct _objc_protocol_method_list {5139int protocol_method_count;5140struct protocol_methods protocols[];5141}5142*/5143Result += "\nstatic struct {\n";5144Result += "\tint protocol_method_count;\n";5145Result += "\tstruct _protocol_methods protocol_methods[";5146Result += utostr(NumMethods);5147Result += "];\n} _OBJC_PROTOCOL_CLASS_METHODS_";5148Result += PDecl->getNameAsString();5149Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= "5150"{\n\t";5151Result += utostr(NumMethods);5152Result += "\n";51535154// Output instance methods declared in this protocol.5155for (ObjCProtocolDecl::classmeth_iterator5156I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();5157I != E; ++I) {5158if (I == PDecl->classmeth_begin())5159Result += "\t ,{{(struct objc_selector *)\"";5160else5161Result += "\t ,{(struct objc_selector *)\"";5162Result += (*I)->getSelector().getAsString();5163std::string MethodTypeString = Context->getObjCEncodingForMethodDecl(*I);5164Result += "\", \"";5165Result += MethodTypeString;5166Result += "\"}\n";5167}5168Result += "\t }\n};\n";5169}51705171// Output:5172/* struct _objc_protocol {5173// Objective-C 1.0 extensions5174struct _objc_protocol_extension *isa;5175char *protocol_name;5176struct _objc_protocol **protocol_list;5177struct _objc_protocol_method_list *instance_methods;5178struct _objc_protocol_method_list *class_methods;5179};5180*/5181static bool objc_protocol = false;5182if (!objc_protocol) {5183Result += "\nstruct _objc_protocol {\n";5184Result += "\tstruct _objc_protocol_extension *isa;\n";5185Result += "\tchar *protocol_name;\n";5186Result += "\tstruct _objc_protocol **protocol_list;\n";5187Result += "\tstruct _objc_protocol_method_list *instance_methods;\n";5188Result += "\tstruct _objc_protocol_method_list *class_methods;\n";5189Result += "};\n";51905191objc_protocol = true;5192}51935194Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_";5195Result += PDecl->getNameAsString();5196Result += " __attribute__ ((used, section (\"__OBJC, __protocol\")))= "5197"{\n\t0, \"";5198Result += PDecl->getNameAsString();5199Result += "\", 0, ";5200if (PDecl->instmeth_begin() != PDecl->instmeth_end()) {5201Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_INSTANCE_METHODS_";5202Result += PDecl->getNameAsString();5203Result += ", ";5204}5205else5206Result += "0, ";5207if (PDecl->classmeth_begin() != PDecl->classmeth_end()) {5208Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_CLASS_METHODS_";5209Result += PDecl->getNameAsString();5210Result += "\n";5211}5212else5213Result += "0\n";5214Result += "};\n";52155216// Mark this protocol as having been generated.5217if (!ObjCSynthesizedProtocols.insert(PDecl->getCanonicalDecl()).second)5218llvm_unreachable("protocol already synthesized");5219}52205221void RewriteObjCFragileABI::RewriteObjCProtocolListMetaData(5222const ObjCList<ObjCProtocolDecl> &Protocols,5223StringRef prefix, StringRef ClassName,5224std::string &Result) {5225if (Protocols.empty()) return;52265227for (unsigned i = 0; i != Protocols.size(); i++)5228RewriteObjCProtocolMetaData(Protocols[i], prefix, ClassName, Result);52295230// Output the top lovel protocol meta-data for the class.5231/* struct _objc_protocol_list {5232struct _objc_protocol_list *next;5233int protocol_count;5234struct _objc_protocol *class_protocols[];5235}5236*/5237Result += "\nstatic struct {\n";5238Result += "\tstruct _objc_protocol_list *next;\n";5239Result += "\tint protocol_count;\n";5240Result += "\tstruct _objc_protocol *class_protocols[";5241Result += utostr(Protocols.size());5242Result += "];\n} _OBJC_";5243Result += prefix;5244Result += "_PROTOCOLS_";5245Result += ClassName;5246Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= "5247"{\n\t0, ";5248Result += utostr(Protocols.size());5249Result += "\n";52505251Result += "\t,{&_OBJC_PROTOCOL_";5252Result += Protocols[0]->getNameAsString();5253Result += " \n";52545255for (unsigned i = 1; i != Protocols.size(); i++) {5256Result += "\t ,&_OBJC_PROTOCOL_";5257Result += Protocols[i]->getNameAsString();5258Result += "\n";5259}5260Result += "\t }\n};\n";5261}52625263void RewriteObjCFragileABI::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,5264std::string &Result) {5265ObjCInterfaceDecl *CDecl = IDecl->getClassInterface();52665267// Explicitly declared @interface's are already synthesized.5268if (CDecl->isImplicitInterfaceDecl()) {5269// FIXME: Implementation of a class with no @interface (legacy) does not5270// produce correct synthesis as yet.5271RewriteObjCInternalStruct(CDecl, Result);5272}52735274// Build _objc_ivar_list metadata for classes ivars if needed5275unsigned NumIvars =5276!IDecl->ivar_empty() ? IDecl->ivar_size() : CDecl->ivar_size();5277if (NumIvars > 0) {5278static bool objc_ivar = false;5279if (!objc_ivar) {5280/* struct _objc_ivar {5281char *ivar_name;5282char *ivar_type;5283int ivar_offset;5284};5285*/5286Result += "\nstruct _objc_ivar {\n";5287Result += "\tchar *ivar_name;\n";5288Result += "\tchar *ivar_type;\n";5289Result += "\tint ivar_offset;\n";5290Result += "};\n";52915292objc_ivar = true;5293}52945295/* struct {5296int ivar_count;5297struct _objc_ivar ivar_list[nIvars];5298};5299*/5300Result += "\nstatic struct {\n";5301Result += "\tint ivar_count;\n";5302Result += "\tstruct _objc_ivar ivar_list[";5303Result += utostr(NumIvars);5304Result += "];\n} _OBJC_INSTANCE_VARIABLES_";5305Result += IDecl->getNameAsString();5306Result += " __attribute__ ((used, section (\"__OBJC, __instance_vars\")))= "5307"{\n\t";5308Result += utostr(NumIvars);5309Result += "\n";53105311ObjCInterfaceDecl::ivar_iterator IVI, IVE;5312SmallVector<ObjCIvarDecl *, 8> IVars;5313if (!IDecl->ivar_empty()) {5314for (auto *IV : IDecl->ivars())5315IVars.push_back(IV);5316IVI = IDecl->ivar_begin();5317IVE = IDecl->ivar_end();5318} else {5319IVI = CDecl->ivar_begin();5320IVE = CDecl->ivar_end();5321}5322Result += "\t,{{\"";5323Result += IVI->getNameAsString();5324Result += "\", \"";5325std::string TmpString, StrEncoding;5326Context->getObjCEncodingForType(IVI->getType(), TmpString, *IVI);5327QuoteDoublequotes(TmpString, StrEncoding);5328Result += StrEncoding;5329Result += "\", ";5330RewriteIvarOffsetComputation(*IVI, Result);5331Result += "}\n";5332for (++IVI; IVI != IVE; ++IVI) {5333Result += "\t ,{\"";5334Result += IVI->getNameAsString();5335Result += "\", \"";5336std::string TmpString, StrEncoding;5337Context->getObjCEncodingForType(IVI->getType(), TmpString, *IVI);5338QuoteDoublequotes(TmpString, StrEncoding);5339Result += StrEncoding;5340Result += "\", ";5341RewriteIvarOffsetComputation(*IVI, Result);5342Result += "}\n";5343}53445345Result += "\t }\n};\n";5346}53475348// Build _objc_method_list for class's instance methods if needed5349SmallVector<ObjCMethodDecl *, 32> InstanceMethods(IDecl->instance_methods());53505351// If any of our property implementations have associated getters or5352// setters, produce metadata for them as well.5353for (const auto *Prop : IDecl->property_impls()) {5354if (Prop->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)5355continue;5356if (!Prop->getPropertyIvarDecl())5357continue;5358ObjCPropertyDecl *PD = Prop->getPropertyDecl();5359if (!PD)5360continue;5361if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl())5362if (!Getter->isDefined())5363InstanceMethods.push_back(Getter);5364if (PD->isReadOnly())5365continue;5366if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl())5367if (!Setter->isDefined())5368InstanceMethods.push_back(Setter);5369}5370RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(),5371true, "", IDecl->getName(), Result);53725373// Build _objc_method_list for class's class methods if needed5374RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),5375false, "", IDecl->getName(), Result);53765377// Protocols referenced in class declaration?5378RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(),5379"CLASS", CDecl->getName(), Result);53805381// Declaration of class/meta-class metadata5382/* struct _objc_class {5383struct _objc_class *isa; // or const char *root_class_name when metadata5384const char *super_class_name;5385char *name;5386long version;5387long info;5388long instance_size;5389struct _objc_ivar_list *ivars;5390struct _objc_method_list *methods;5391struct objc_cache *cache;5392struct objc_protocol_list *protocols;5393const char *ivar_layout;5394struct _objc_class_ext *ext;5395};5396*/5397static bool objc_class = false;5398if (!objc_class) {5399Result += "\nstruct _objc_class {\n";5400Result += "\tstruct _objc_class *isa;\n";5401Result += "\tconst char *super_class_name;\n";5402Result += "\tchar *name;\n";5403Result += "\tlong version;\n";5404Result += "\tlong info;\n";5405Result += "\tlong instance_size;\n";5406Result += "\tstruct _objc_ivar_list *ivars;\n";5407Result += "\tstruct _objc_method_list *methods;\n";5408Result += "\tstruct objc_cache *cache;\n";5409Result += "\tstruct _objc_protocol_list *protocols;\n";5410Result += "\tconst char *ivar_layout;\n";5411Result += "\tstruct _objc_class_ext *ext;\n";5412Result += "};\n";5413objc_class = true;5414}54155416// Meta-class metadata generation.5417ObjCInterfaceDecl *RootClass = nullptr;5418ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass();5419while (SuperClass) {5420RootClass = SuperClass;5421SuperClass = SuperClass->getSuperClass();5422}5423SuperClass = CDecl->getSuperClass();54245425Result += "\nstatic struct _objc_class _OBJC_METACLASS_";5426Result += CDecl->getNameAsString();5427Result += " __attribute__ ((used, section (\"__OBJC, __meta_class\")))= "5428"{\n\t(struct _objc_class *)\"";5429Result += (RootClass ? RootClass->getNameAsString() : CDecl->getNameAsString());5430Result += "\"";54315432if (SuperClass) {5433Result += ", \"";5434Result += SuperClass->getNameAsString();5435Result += "\", \"";5436Result += CDecl->getNameAsString();5437Result += "\"";5438}5439else {5440Result += ", 0, \"";5441Result += CDecl->getNameAsString();5442Result += "\"";5443}5444// Set 'ivars' field for root class to 0. ObjC1 runtime does not use it.5445// 'info' field is initialized to CLS_META(2) for metaclass5446Result += ", 0,2, sizeof(struct _objc_class), 0";5447if (IDecl->classmeth_begin() != IDecl->classmeth_end()) {5448Result += "\n\t, (struct _objc_method_list *)&_OBJC_CLASS_METHODS_";5449Result += IDecl->getNameAsString();5450Result += "\n";5451}5452else5453Result += ", 0\n";5454if (CDecl->protocol_begin() != CDecl->protocol_end()) {5455Result += "\t,0, (struct _objc_protocol_list *)&_OBJC_CLASS_PROTOCOLS_";5456Result += CDecl->getNameAsString();5457Result += ",0,0\n";5458}5459else5460Result += "\t,0,0,0,0\n";5461Result += "};\n";54625463// class metadata generation.5464Result += "\nstatic struct _objc_class _OBJC_CLASS_";5465Result += CDecl->getNameAsString();5466Result += " __attribute__ ((used, section (\"__OBJC, __class\")))= "5467"{\n\t&_OBJC_METACLASS_";5468Result += CDecl->getNameAsString();5469if (SuperClass) {5470Result += ", \"";5471Result += SuperClass->getNameAsString();5472Result += "\", \"";5473Result += CDecl->getNameAsString();5474Result += "\"";5475}5476else {5477Result += ", 0, \"";5478Result += CDecl->getNameAsString();5479Result += "\"";5480}5481// 'info' field is initialized to CLS_CLASS(1) for class5482Result += ", 0,1";5483if (!ObjCSynthesizedStructs.count(CDecl))5484Result += ",0";5485else {5486// class has size. Must synthesize its size.5487Result += ",sizeof(struct ";5488Result += CDecl->getNameAsString();5489if (LangOpts.MicrosoftExt)5490Result += "_IMPL";5491Result += ")";5492}5493if (NumIvars > 0) {5494Result += ", (struct _objc_ivar_list *)&_OBJC_INSTANCE_VARIABLES_";5495Result += CDecl->getNameAsString();5496Result += "\n\t";5497}5498else5499Result += ",0";5500if (IDecl->instmeth_begin() != IDecl->instmeth_end()) {5501Result += ", (struct _objc_method_list *)&_OBJC_INSTANCE_METHODS_";5502Result += CDecl->getNameAsString();5503Result += ", 0\n\t";5504}5505else5506Result += ",0,0";5507if (CDecl->protocol_begin() != CDecl->protocol_end()) {5508Result += ", (struct _objc_protocol_list*)&_OBJC_CLASS_PROTOCOLS_";5509Result += CDecl->getNameAsString();5510Result += ", 0,0\n";5511}5512else5513Result += ",0,0,0\n";5514Result += "};\n";5515}55165517void RewriteObjCFragileABI::RewriteMetaDataIntoBuffer(std::string &Result) {5518int ClsDefCount = ClassImplementation.size();5519int CatDefCount = CategoryImplementation.size();55205521// For each implemented class, write out all its meta data.5522for (int i = 0; i < ClsDefCount; i++)5523RewriteObjCClassMetaData(ClassImplementation[i], Result);55245525// For each implemented category, write out all its meta data.5526for (int i = 0; i < CatDefCount; i++)5527RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result);55285529// Write objc_symtab metadata5530/*5531struct _objc_symtab5532{5533long sel_ref_cnt;5534SEL *refs;5535short cls_def_cnt;5536short cat_def_cnt;5537void *defs[cls_def_cnt + cat_def_cnt];5538};5539*/55405541Result += "\nstruct _objc_symtab {\n";5542Result += "\tlong sel_ref_cnt;\n";5543Result += "\tSEL *refs;\n";5544Result += "\tshort cls_def_cnt;\n";5545Result += "\tshort cat_def_cnt;\n";5546Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n";5547Result += "};\n\n";55485549Result += "static struct _objc_symtab "5550"_OBJC_SYMBOLS __attribute__((used, section (\"__OBJC, __symbols\")))= {\n";5551Result += "\t0, 0, " + utostr(ClsDefCount)5552+ ", " + utostr(CatDefCount) + "\n";5553for (int i = 0; i < ClsDefCount; i++) {5554Result += "\t,&_OBJC_CLASS_";5555Result += ClassImplementation[i]->getNameAsString();5556Result += "\n";5557}55585559for (int i = 0; i < CatDefCount; i++) {5560Result += "\t,&_OBJC_CATEGORY_";5561Result += CategoryImplementation[i]->getClassInterface()->getNameAsString();5562Result += "_";5563Result += CategoryImplementation[i]->getNameAsString();5564Result += "\n";5565}55665567Result += "};\n\n";55685569// Write objc_module metadata55705571/*5572struct _objc_module {5573long version;5574long size;5575const char *name;5576struct _objc_symtab *symtab;5577}5578*/55795580Result += "\nstruct _objc_module {\n";5581Result += "\tlong version;\n";5582Result += "\tlong size;\n";5583Result += "\tconst char *name;\n";5584Result += "\tstruct _objc_symtab *symtab;\n";5585Result += "};\n\n";5586Result += "static struct _objc_module "5587"_OBJC_MODULES __attribute__ ((used, section (\"__OBJC, __module_info\")))= {\n";5588Result += "\t" + utostr(OBJC_ABI_VERSION) +5589", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";5590Result += "};\n\n";55915592if (LangOpts.MicrosoftExt) {5593if (ProtocolExprDecls.size()) {5594Result += "#pragma section(\".objc_protocol$B\",long,read,write)\n";5595Result += "#pragma data_seg(push, \".objc_protocol$B\")\n";5596for (ObjCProtocolDecl *ProtDecl : ProtocolExprDecls) {5597Result += "static struct _objc_protocol *_POINTER_OBJC_PROTOCOL_";5598Result += ProtDecl->getNameAsString();5599Result += " = &_OBJC_PROTOCOL_";5600Result += ProtDecl->getNameAsString();5601Result += ";\n";5602}5603Result += "#pragma data_seg(pop)\n\n";5604}5605Result += "#pragma section(\".objc_module_info$B\",long,read,write)\n";5606Result += "#pragma data_seg(push, \".objc_module_info$B\")\n";5607Result += "static struct _objc_module *_POINTER_OBJC_MODULES = ";5608Result += "&_OBJC_MODULES;\n";5609Result += "#pragma data_seg(pop)\n\n";5610}5611}56125613/// RewriteObjCCategoryImplDecl - Rewrite metadata for each category5614/// implementation.5615void RewriteObjCFragileABI::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,5616std::string &Result) {5617ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface();5618// Find category declaration for this implementation.5619ObjCCategoryDecl *CDecl5620= ClassDecl->FindCategoryDeclaration(IDecl->getIdentifier());56215622std::string FullCategoryName = ClassDecl->getNameAsString();5623FullCategoryName += '_';5624FullCategoryName += IDecl->getNameAsString();56255626// Build _objc_method_list for class's instance methods if needed5627SmallVector<ObjCMethodDecl *, 32> InstanceMethods(IDecl->instance_methods());56285629// If any of our property implementations have associated getters or5630// setters, produce metadata for them as well.5631for (const auto *Prop : IDecl->property_impls()) {5632if (Prop->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)5633continue;5634if (!Prop->getPropertyIvarDecl())5635continue;5636ObjCPropertyDecl *PD = Prop->getPropertyDecl();5637if (!PD)5638continue;5639if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl())5640InstanceMethods.push_back(Getter);5641if (PD->isReadOnly())5642continue;5643if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl())5644InstanceMethods.push_back(Setter);5645}5646RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(),5647true, "CATEGORY_", FullCategoryName, Result);56485649// Build _objc_method_list for class's class methods if needed5650RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),5651false, "CATEGORY_", FullCategoryName, Result);56525653// Protocols referenced in class declaration?5654// Null CDecl is case of a category implementation with no category interface5655if (CDecl)5656RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(), "CATEGORY",5657FullCategoryName, Result);5658/* struct _objc_category {5659char *category_name;5660char *class_name;5661struct _objc_method_list *instance_methods;5662struct _objc_method_list *class_methods;5663struct _objc_protocol_list *protocols;5664// Objective-C 1.0 extensions5665uint32_t size; // sizeof (struct _objc_category)5666struct _objc_property_list *instance_properties; // category's own5667// @property decl.5668};5669*/56705671static bool objc_category = false;5672if (!objc_category) {5673Result += "\nstruct _objc_category {\n";5674Result += "\tchar *category_name;\n";5675Result += "\tchar *class_name;\n";5676Result += "\tstruct _objc_method_list *instance_methods;\n";5677Result += "\tstruct _objc_method_list *class_methods;\n";5678Result += "\tstruct _objc_protocol_list *protocols;\n";5679Result += "\tunsigned int size;\n";5680Result += "\tstruct _objc_property_list *instance_properties;\n";5681Result += "};\n";5682objc_category = true;5683}5684Result += "\nstatic struct _objc_category _OBJC_CATEGORY_";5685Result += FullCategoryName;5686Result += " __attribute__ ((used, section (\"__OBJC, __category\")))= {\n\t\"";5687Result += IDecl->getNameAsString();5688Result += "\"\n\t, \"";5689Result += ClassDecl->getNameAsString();5690Result += "\"\n";56915692if (IDecl->instmeth_begin() != IDecl->instmeth_end()) {5693Result += "\t, (struct _objc_method_list *)"5694"&_OBJC_CATEGORY_INSTANCE_METHODS_";5695Result += FullCategoryName;5696Result += "\n";5697}5698else5699Result += "\t, 0\n";5700if (IDecl->classmeth_begin() != IDecl->classmeth_end()) {5701Result += "\t, (struct _objc_method_list *)"5702"&_OBJC_CATEGORY_CLASS_METHODS_";5703Result += FullCategoryName;5704Result += "\n";5705}5706else5707Result += "\t, 0\n";57085709if (CDecl && CDecl->protocol_begin() != CDecl->protocol_end()) {5710Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";5711Result += FullCategoryName;5712Result += "\n";5713}5714else5715Result += "\t, 0\n";5716Result += "\t, sizeof(struct _objc_category), 0\n};\n";5717}57185719// RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or5720/// class methods.5721template<typename MethodIterator>5722void RewriteObjCFragileABI::RewriteObjCMethodsMetaData(MethodIterator MethodBegin,5723MethodIterator MethodEnd,5724bool IsInstanceMethod,5725StringRef prefix,5726StringRef ClassName,5727std::string &Result) {5728if (MethodBegin == MethodEnd) return;57295730if (!objc_impl_method) {5731/* struct _objc_method {5732SEL _cmd;5733char *method_types;5734void *_imp;5735}5736*/5737Result += "\nstruct _objc_method {\n";5738Result += "\tSEL _cmd;\n";5739Result += "\tchar *method_types;\n";5740Result += "\tvoid *_imp;\n";5741Result += "};\n";57425743objc_impl_method = true;5744}57455746// Build _objc_method_list for class's methods if needed57475748/* struct {5749struct _objc_method_list *next_method;5750int method_count;5751struct _objc_method method_list[];5752}5753*/5754unsigned NumMethods = std::distance(MethodBegin, MethodEnd);5755Result += "\nstatic struct {\n";5756Result += "\tstruct _objc_method_list *next_method;\n";5757Result += "\tint method_count;\n";5758Result += "\tstruct _objc_method method_list[";5759Result += utostr(NumMethods);5760Result += "];\n} _OBJC_";5761Result += prefix;5762Result += IsInstanceMethod ? "INSTANCE" : "CLASS";5763Result += "_METHODS_";5764Result += ClassName;5765Result += " __attribute__ ((used, section (\"__OBJC, __";5766Result += IsInstanceMethod ? "inst" : "cls";5767Result += "_meth\")))= ";5768Result += "{\n\t0, " + utostr(NumMethods) + "\n";57695770Result += "\t,{{(SEL)\"";5771Result += (*MethodBegin)->getSelector().getAsString();5772std::string MethodTypeString =5773Context->getObjCEncodingForMethodDecl(*MethodBegin);5774Result += "\", \"";5775Result += MethodTypeString;5776Result += "\", (void *)";5777Result += MethodInternalNames[*MethodBegin];5778Result += "}\n";5779for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) {5780Result += "\t ,{(SEL)\"";5781Result += (*MethodBegin)->getSelector().getAsString();5782std::string MethodTypeString =5783Context->getObjCEncodingForMethodDecl(*MethodBegin);5784Result += "\", \"";5785Result += MethodTypeString;5786Result += "\", (void *)";5787Result += MethodInternalNames[*MethodBegin];5788Result += "}\n";5789}5790Result += "\t }\n};\n";5791}57925793Stmt *RewriteObjCFragileABI::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {5794SourceRange OldRange = IV->getSourceRange();5795Expr *BaseExpr = IV->getBase();57965797// Rewrite the base, but without actually doing replaces.5798{5799DisableReplaceStmtScope S(*this);5800BaseExpr = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(BaseExpr));5801IV->setBase(BaseExpr);5802}58035804ObjCIvarDecl *D = IV->getDecl();58055806Expr *Replacement = IV;5807if (CurMethodDef) {5808if (BaseExpr->getType()->isObjCObjectPointerType()) {5809const ObjCInterfaceType *iFaceDecl =5810dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());5811assert(iFaceDecl && "RewriteObjCIvarRefExpr - iFaceDecl is null");5812// lookup which class implements the instance variable.5813ObjCInterfaceDecl *clsDeclared = nullptr;5814iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),5815clsDeclared);5816assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class");58175818// Synthesize an explicit cast to gain access to the ivar.5819std::string RecName =5820std::string(clsDeclared->getIdentifier()->getName());5821RecName += "_IMPL";5822IdentifierInfo *II = &Context->Idents.get(RecName);5823RecordDecl *RD =5824RecordDecl::Create(*Context, TagTypeKind::Struct, TUDecl,5825SourceLocation(), SourceLocation(), II);5826assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");5827QualType castT = Context->getPointerType(Context->getTagDeclType(RD));5828CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT,5829CK_BitCast,5830IV->getBase());5831// Don't forget the parens to enforce the proper binding.5832ParenExpr *PE = new (Context) ParenExpr(OldRange.getBegin(),5833OldRange.getEnd(),5834castExpr);5835if (IV->isFreeIvar() &&5836declaresSameEntity(CurMethodDef->getClassInterface(),5837iFaceDecl->getDecl())) {5838MemberExpr *ME = MemberExpr::CreateImplicit(5839*Context, PE, true, D, D->getType(), VK_LValue, OK_Ordinary);5840Replacement = ME;5841} else {5842IV->setBase(PE);5843}5844}5845} else { // we are outside a method.5846assert(!IV->isFreeIvar() && "Cannot have a free standing ivar outside a method");58475848// Explicit ivar refs need to have a cast inserted.5849// FIXME: consider sharing some of this code with the code above.5850if (BaseExpr->getType()->isObjCObjectPointerType()) {5851const ObjCInterfaceType *iFaceDecl =5852dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());5853// lookup which class implements the instance variable.5854ObjCInterfaceDecl *clsDeclared = nullptr;5855iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),5856clsDeclared);5857assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class");58585859// Synthesize an explicit cast to gain access to the ivar.5860std::string RecName =5861std::string(clsDeclared->getIdentifier()->getName());5862RecName += "_IMPL";5863IdentifierInfo *II = &Context->Idents.get(RecName);5864RecordDecl *RD =5865RecordDecl::Create(*Context, TagTypeKind::Struct, TUDecl,5866SourceLocation(), SourceLocation(), II);5867assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");5868QualType castT = Context->getPointerType(Context->getTagDeclType(RD));5869CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT,5870CK_BitCast,5871IV->getBase());5872// Don't forget the parens to enforce the proper binding.5873ParenExpr *PE = new (Context) ParenExpr(5874IV->getBase()->getBeginLoc(), IV->getBase()->getEndLoc(), castExpr);5875// Cannot delete IV->getBase(), since PE points to it.5876// Replace the old base with the cast. This is important when doing5877// embedded rewrites. For example, [newInv->_container addObject:0].5878IV->setBase(PE);5879}5880}58815882ReplaceStmtWithRange(IV, Replacement, OldRange);5883return Replacement;5884}58855886#endif // CLANG_ENABLE_OBJC_REWRITER588758885889