10b57cec5SDimitry Andric //===--- Transforms.cpp - Transformations to ARC mode ---------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "Transforms.h" 100b57cec5SDimitry Andric #include "Internals.h" 115ffd83dbSDimitry Andric #include "clang/ARCMigrate/ARCMT.h" 120b57cec5SDimitry Andric #include "clang/AST/ASTContext.h" 130b57cec5SDimitry Andric #include "clang/AST/RecursiveASTVisitor.h" 140b57cec5SDimitry Andric #include "clang/Analysis/DomainSpecific/CocoaConventions.h" 150b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h" 160b57cec5SDimitry Andric #include "clang/Basic/TargetInfo.h" 170b57cec5SDimitry Andric #include "clang/Lex/Lexer.h" 180b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h" 190b57cec5SDimitry Andric #include "clang/Sema/Sema.h" 20*0fca6ea1SDimitry Andric #include "clang/Sema/SemaObjC.h" 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric using namespace clang; 230b57cec5SDimitry Andric using namespace arcmt; 240b57cec5SDimitry Andric using namespace trans; 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric ASTTraverser::~ASTTraverser() { } 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric bool MigrationPass::CFBridgingFunctionsDefined() { 2981ad6265SDimitry Andric if (!EnableCFBridgeFns) 30*0fca6ea1SDimitry Andric EnableCFBridgeFns = SemaRef.ObjC().isKnownName("CFBridgingRetain") && 31*0fca6ea1SDimitry Andric SemaRef.ObjC().isKnownName("CFBridgingRelease"); 320b57cec5SDimitry Andric return *EnableCFBridgeFns; 330b57cec5SDimitry Andric } 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 360b57cec5SDimitry Andric // Helpers. 370b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric bool trans::canApplyWeak(ASTContext &Ctx, QualType type, 400b57cec5SDimitry Andric bool AllowOnUnknownClass) { 410b57cec5SDimitry Andric if (!Ctx.getLangOpts().ObjCWeakRuntime) 420b57cec5SDimitry Andric return false; 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric QualType T = type; 450b57cec5SDimitry Andric if (T.isNull()) 460b57cec5SDimitry Andric return false; 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric // iOS is always safe to use 'weak'. 490b57cec5SDimitry Andric if (Ctx.getTargetInfo().getTriple().isiOS() || 500b57cec5SDimitry Andric Ctx.getTargetInfo().getTriple().isWatchOS()) 510b57cec5SDimitry Andric AllowOnUnknownClass = true; 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric while (const PointerType *ptr = T->getAs<PointerType>()) 540b57cec5SDimitry Andric T = ptr->getPointeeType(); 550b57cec5SDimitry Andric if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) { 560b57cec5SDimitry Andric ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl(); 570b57cec5SDimitry Andric if (!AllowOnUnknownClass && (!Class || Class->getName() == "NSObject")) 580b57cec5SDimitry Andric return false; // id/NSObject is not safe for weak. 590b57cec5SDimitry Andric if (!AllowOnUnknownClass && !Class->hasDefinition()) 600b57cec5SDimitry Andric return false; // forward classes are not verifiable, therefore not safe. 610b57cec5SDimitry Andric if (Class && Class->isArcWeakrefUnavailable()) 620b57cec5SDimitry Andric return false; 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric return true; 660b57cec5SDimitry Andric } 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric bool trans::isPlusOneAssign(const BinaryOperator *E) { 690b57cec5SDimitry Andric if (E->getOpcode() != BO_Assign) 700b57cec5SDimitry Andric return false; 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric return isPlusOne(E->getRHS()); 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric bool trans::isPlusOne(const Expr *E) { 760b57cec5SDimitry Andric if (!E) 770b57cec5SDimitry Andric return false; 780b57cec5SDimitry Andric if (const FullExpr *FE = dyn_cast<FullExpr>(E)) 790b57cec5SDimitry Andric E = FE->getSubExpr(); 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric if (const ObjCMessageExpr * 820b57cec5SDimitry Andric ME = dyn_cast<ObjCMessageExpr>(E->IgnoreParenCasts())) 830b57cec5SDimitry Andric if (ME->getMethodFamily() == OMF_retain) 840b57cec5SDimitry Andric return true; 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric if (const CallExpr * 870b57cec5SDimitry Andric callE = dyn_cast<CallExpr>(E->IgnoreParenCasts())) { 880b57cec5SDimitry Andric if (const FunctionDecl *FD = callE->getDirectCallee()) { 890b57cec5SDimitry Andric if (FD->hasAttr<CFReturnsRetainedAttr>()) 900b57cec5SDimitry Andric return true; 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric if (FD->isGlobal() && 930b57cec5SDimitry Andric FD->getIdentifier() && 940b57cec5SDimitry Andric FD->getParent()->isTranslationUnit() && 950b57cec5SDimitry Andric FD->isExternallyVisible() && 960b57cec5SDimitry Andric ento::cocoa::isRefType(callE->getType(), "CF", 970b57cec5SDimitry Andric FD->getIdentifier()->getName())) { 980b57cec5SDimitry Andric StringRef fname = FD->getIdentifier()->getName(); 995f757f3fSDimitry Andric if (fname.ends_with("Retain") || fname.contains("Create") || 100349cc55cSDimitry Andric fname.contains("Copy")) 1010b57cec5SDimitry Andric return true; 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric const ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E); 1070b57cec5SDimitry Andric while (implCE && implCE->getCastKind() == CK_BitCast) 1080b57cec5SDimitry Andric implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr()); 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric return implCE && implCE->getCastKind() == CK_ARCConsumeObject; 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric /// 'Loc' is the end of a statement range. This returns the location 1140b57cec5SDimitry Andric /// immediately after the semicolon following the statement. 1150b57cec5SDimitry Andric /// If no semicolon is found or the location is inside a macro, the returned 1160b57cec5SDimitry Andric /// source location will be invalid. 1170b57cec5SDimitry Andric SourceLocation trans::findLocationAfterSemi(SourceLocation loc, 1180b57cec5SDimitry Andric ASTContext &Ctx, bool IsDecl) { 1190b57cec5SDimitry Andric SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx, IsDecl); 1200b57cec5SDimitry Andric if (SemiLoc.isInvalid()) 1210b57cec5SDimitry Andric return SourceLocation(); 1220b57cec5SDimitry Andric return SemiLoc.getLocWithOffset(1); 1230b57cec5SDimitry Andric } 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric /// \arg Loc is the end of a statement range. This returns the location 1260b57cec5SDimitry Andric /// of the semicolon following the statement. 1270b57cec5SDimitry Andric /// If no semicolon is found or the location is inside a macro, the returned 1280b57cec5SDimitry Andric /// source location will be invalid. 1290b57cec5SDimitry Andric SourceLocation trans::findSemiAfterLocation(SourceLocation loc, 1300b57cec5SDimitry Andric ASTContext &Ctx, 1310b57cec5SDimitry Andric bool IsDecl) { 1320b57cec5SDimitry Andric SourceManager &SM = Ctx.getSourceManager(); 1330b57cec5SDimitry Andric if (loc.isMacroID()) { 1340b57cec5SDimitry Andric if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOpts(), &loc)) 1350b57cec5SDimitry Andric return SourceLocation(); 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOpts()); 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric // Break down the source location. 1400b57cec5SDimitry Andric std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc); 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric // Try to load the file buffer. 1430b57cec5SDimitry Andric bool invalidTemp = false; 1440b57cec5SDimitry Andric StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 1450b57cec5SDimitry Andric if (invalidTemp) 1460b57cec5SDimitry Andric return SourceLocation(); 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric const char *tokenBegin = file.data() + locInfo.second; 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric // Lex from the start of the given location. 1510b57cec5SDimitry Andric Lexer lexer(SM.getLocForStartOfFile(locInfo.first), 1520b57cec5SDimitry Andric Ctx.getLangOpts(), 1530b57cec5SDimitry Andric file.begin(), tokenBegin, file.end()); 1540b57cec5SDimitry Andric Token tok; 1550b57cec5SDimitry Andric lexer.LexFromRawLexer(tok); 1560b57cec5SDimitry Andric if (tok.isNot(tok::semi)) { 1570b57cec5SDimitry Andric if (!IsDecl) 1580b57cec5SDimitry Andric return SourceLocation(); 1590b57cec5SDimitry Andric // Declaration may be followed with other tokens; such as an __attribute, 1600b57cec5SDimitry Andric // before ending with a semicolon. 1610b57cec5SDimitry Andric return findSemiAfterLocation(tok.getLocation(), Ctx, /*IsDecl*/true); 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric return tok.getLocation(); 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) { 1680b57cec5SDimitry Andric if (!E || !E->HasSideEffects(Ctx)) 1690b57cec5SDimitry Andric return false; 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric E = E->IgnoreParenCasts(); 1720b57cec5SDimitry Andric ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E); 1730b57cec5SDimitry Andric if (!ME) 1740b57cec5SDimitry Andric return true; 1750b57cec5SDimitry Andric switch (ME->getMethodFamily()) { 1760b57cec5SDimitry Andric case OMF_autorelease: 1770b57cec5SDimitry Andric case OMF_dealloc: 1780b57cec5SDimitry Andric case OMF_release: 1790b57cec5SDimitry Andric case OMF_retain: 1800b57cec5SDimitry Andric switch (ME->getReceiverKind()) { 1810b57cec5SDimitry Andric case ObjCMessageExpr::SuperInstance: 1820b57cec5SDimitry Andric return false; 1830b57cec5SDimitry Andric case ObjCMessageExpr::Instance: 1840b57cec5SDimitry Andric return hasSideEffects(ME->getInstanceReceiver(), Ctx); 1850b57cec5SDimitry Andric default: 1860b57cec5SDimitry Andric break; 1870b57cec5SDimitry Andric } 1880b57cec5SDimitry Andric break; 1890b57cec5SDimitry Andric default: 1900b57cec5SDimitry Andric break; 1910b57cec5SDimitry Andric } 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric return true; 1940b57cec5SDimitry Andric } 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric bool trans::isGlobalVar(Expr *E) { 1970b57cec5SDimitry Andric E = E->IgnoreParenCasts(); 1980b57cec5SDimitry Andric if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) 1990b57cec5SDimitry Andric return DRE->getDecl()->getDeclContext()->isFileContext() && 2000b57cec5SDimitry Andric DRE->getDecl()->isExternallyVisible(); 2010b57cec5SDimitry Andric if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E)) 2020b57cec5SDimitry Andric return isGlobalVar(condOp->getTrueExpr()) && 2030b57cec5SDimitry Andric isGlobalVar(condOp->getFalseExpr()); 2040b57cec5SDimitry Andric 2050b57cec5SDimitry Andric return false; 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric StringRef trans::getNilString(MigrationPass &Pass) { 2090b57cec5SDimitry Andric return Pass.SemaRef.PP.isMacroDefined("nil") ? "nil" : "0"; 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric namespace { 2130b57cec5SDimitry Andric 2140b57cec5SDimitry Andric class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> { 2150b57cec5SDimitry Andric ExprSet &Refs; 2160b57cec5SDimitry Andric public: 2170b57cec5SDimitry Andric ReferenceClear(ExprSet &refs) : Refs(refs) { } 2180b57cec5SDimitry Andric bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; } 2190b57cec5SDimitry Andric }; 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> { 2220b57cec5SDimitry Andric ValueDecl *Dcl; 2230b57cec5SDimitry Andric ExprSet &Refs; 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric public: 2260b57cec5SDimitry Andric ReferenceCollector(ValueDecl *D, ExprSet &refs) 2270b57cec5SDimitry Andric : Dcl(D), Refs(refs) { } 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric bool VisitDeclRefExpr(DeclRefExpr *E) { 2300b57cec5SDimitry Andric if (E->getDecl() == Dcl) 2310b57cec5SDimitry Andric Refs.insert(E); 2320b57cec5SDimitry Andric return true; 2330b57cec5SDimitry Andric } 2340b57cec5SDimitry Andric }; 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> { 2370b57cec5SDimitry Andric ExprSet &Removables; 2380b57cec5SDimitry Andric 2390b57cec5SDimitry Andric public: 2400b57cec5SDimitry Andric RemovablesCollector(ExprSet &removables) 2410b57cec5SDimitry Andric : Removables(removables) { } 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric bool shouldWalkTypesOfTypeLocs() const { return false; } 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric bool TraverseStmtExpr(StmtExpr *E) { 2460b57cec5SDimitry Andric CompoundStmt *S = E->getSubStmt(); 2470b57cec5SDimitry Andric for (CompoundStmt::body_iterator 2480b57cec5SDimitry Andric I = S->body_begin(), E = S->body_end(); I != E; ++I) { 2490b57cec5SDimitry Andric if (I != E - 1) 2500b57cec5SDimitry Andric mark(*I); 2510b57cec5SDimitry Andric TraverseStmt(*I); 2520b57cec5SDimitry Andric } 2530b57cec5SDimitry Andric return true; 2540b57cec5SDimitry Andric } 2550b57cec5SDimitry Andric 2560b57cec5SDimitry Andric bool VisitCompoundStmt(CompoundStmt *S) { 2570b57cec5SDimitry Andric for (auto *I : S->body()) 2580b57cec5SDimitry Andric mark(I); 2590b57cec5SDimitry Andric return true; 2600b57cec5SDimitry Andric } 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric bool VisitIfStmt(IfStmt *S) { 2630b57cec5SDimitry Andric mark(S->getThen()); 2640b57cec5SDimitry Andric mark(S->getElse()); 2650b57cec5SDimitry Andric return true; 2660b57cec5SDimitry Andric } 2670b57cec5SDimitry Andric 2680b57cec5SDimitry Andric bool VisitWhileStmt(WhileStmt *S) { 2690b57cec5SDimitry Andric mark(S->getBody()); 2700b57cec5SDimitry Andric return true; 2710b57cec5SDimitry Andric } 2720b57cec5SDimitry Andric 2730b57cec5SDimitry Andric bool VisitDoStmt(DoStmt *S) { 2740b57cec5SDimitry Andric mark(S->getBody()); 2750b57cec5SDimitry Andric return true; 2760b57cec5SDimitry Andric } 2770b57cec5SDimitry Andric 2780b57cec5SDimitry Andric bool VisitForStmt(ForStmt *S) { 2790b57cec5SDimitry Andric mark(S->getInit()); 2800b57cec5SDimitry Andric mark(S->getInc()); 2810b57cec5SDimitry Andric mark(S->getBody()); 2820b57cec5SDimitry Andric return true; 2830b57cec5SDimitry Andric } 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric private: 2860b57cec5SDimitry Andric void mark(Stmt *S) { 2870b57cec5SDimitry Andric if (!S) return; 2880b57cec5SDimitry Andric 2890b57cec5SDimitry Andric while (auto *Label = dyn_cast<LabelStmt>(S)) 2900b57cec5SDimitry Andric S = Label->getSubStmt(); 2910b57cec5SDimitry Andric if (auto *E = dyn_cast<Expr>(S)) 2920b57cec5SDimitry Andric S = E->IgnoreImplicit(); 2930b57cec5SDimitry Andric if (auto *E = dyn_cast<Expr>(S)) 2940b57cec5SDimitry Andric Removables.insert(E); 2950b57cec5SDimitry Andric } 2960b57cec5SDimitry Andric }; 2970b57cec5SDimitry Andric 2980b57cec5SDimitry Andric } // end anonymous namespace 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric void trans::clearRefsIn(Stmt *S, ExprSet &refs) { 3010b57cec5SDimitry Andric ReferenceClear(refs).TraverseStmt(S); 3020b57cec5SDimitry Andric } 3030b57cec5SDimitry Andric 3040b57cec5SDimitry Andric void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) { 3050b57cec5SDimitry Andric ReferenceCollector(D, refs).TraverseStmt(S); 3060b57cec5SDimitry Andric } 3070b57cec5SDimitry Andric 3080b57cec5SDimitry Andric void trans::collectRemovables(Stmt *S, ExprSet &exprs) { 3090b57cec5SDimitry Andric RemovablesCollector(exprs).TraverseStmt(S); 3100b57cec5SDimitry Andric } 3110b57cec5SDimitry Andric 3120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 3130b57cec5SDimitry Andric // MigrationContext 3140b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 3150b57cec5SDimitry Andric 3160b57cec5SDimitry Andric namespace { 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric class ASTTransform : public RecursiveASTVisitor<ASTTransform> { 3190b57cec5SDimitry Andric MigrationContext &MigrateCtx; 3200b57cec5SDimitry Andric typedef RecursiveASTVisitor<ASTTransform> base; 3210b57cec5SDimitry Andric 3220b57cec5SDimitry Andric public: 3230b57cec5SDimitry Andric ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { } 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric bool shouldWalkTypesOfTypeLocs() const { return false; } 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) { 3280b57cec5SDimitry Andric ObjCImplementationContext ImplCtx(MigrateCtx, D); 3290b57cec5SDimitry Andric for (MigrationContext::traverser_iterator 3300b57cec5SDimitry Andric I = MigrateCtx.traversers_begin(), 3310b57cec5SDimitry Andric E = MigrateCtx.traversers_end(); I != E; ++I) 3320b57cec5SDimitry Andric (*I)->traverseObjCImplementation(ImplCtx); 3330b57cec5SDimitry Andric 3340b57cec5SDimitry Andric return base::TraverseObjCImplementationDecl(D); 3350b57cec5SDimitry Andric } 3360b57cec5SDimitry Andric 3370b57cec5SDimitry Andric bool TraverseStmt(Stmt *rootS) { 3380b57cec5SDimitry Andric if (!rootS) 3390b57cec5SDimitry Andric return true; 3400b57cec5SDimitry Andric 3410b57cec5SDimitry Andric BodyContext BodyCtx(MigrateCtx, rootS); 3420b57cec5SDimitry Andric for (MigrationContext::traverser_iterator 3430b57cec5SDimitry Andric I = MigrateCtx.traversers_begin(), 3440b57cec5SDimitry Andric E = MigrateCtx.traversers_end(); I != E; ++I) 3450b57cec5SDimitry Andric (*I)->traverseBody(BodyCtx); 3460b57cec5SDimitry Andric 3470b57cec5SDimitry Andric return true; 3480b57cec5SDimitry Andric } 3490b57cec5SDimitry Andric }; 3500b57cec5SDimitry Andric 3510b57cec5SDimitry Andric } 3520b57cec5SDimitry Andric 3530b57cec5SDimitry Andric MigrationContext::~MigrationContext() { 3540b57cec5SDimitry Andric for (traverser_iterator 3550b57cec5SDimitry Andric I = traversers_begin(), E = traversers_end(); I != E; ++I) 3560b57cec5SDimitry Andric delete *I; 3570b57cec5SDimitry Andric } 3580b57cec5SDimitry Andric 3590b57cec5SDimitry Andric bool MigrationContext::isGCOwnedNonObjC(QualType T) { 3600b57cec5SDimitry Andric while (!T.isNull()) { 3610b57cec5SDimitry Andric if (const AttributedType *AttrT = T->getAs<AttributedType>()) { 3620b57cec5SDimitry Andric if (AttrT->getAttrKind() == attr::ObjCOwnership) 3630b57cec5SDimitry Andric return !AttrT->getModifiedType()->isObjCRetainableType(); 3640b57cec5SDimitry Andric } 3650b57cec5SDimitry Andric 3660b57cec5SDimitry Andric if (T->isArrayType()) 3670b57cec5SDimitry Andric T = Pass.Ctx.getBaseElementType(T); 3680b57cec5SDimitry Andric else if (const PointerType *PT = T->getAs<PointerType>()) 3690b57cec5SDimitry Andric T = PT->getPointeeType(); 3700b57cec5SDimitry Andric else if (const ReferenceType *RT = T->getAs<ReferenceType>()) 3710b57cec5SDimitry Andric T = RT->getPointeeType(); 3720b57cec5SDimitry Andric else 3730b57cec5SDimitry Andric break; 3740b57cec5SDimitry Andric } 3750b57cec5SDimitry Andric 3760b57cec5SDimitry Andric return false; 3770b57cec5SDimitry Andric } 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr, 3800b57cec5SDimitry Andric StringRef toAttr, 3810b57cec5SDimitry Andric SourceLocation atLoc) { 3820b57cec5SDimitry Andric if (atLoc.isMacroID()) 3830b57cec5SDimitry Andric return false; 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric SourceManager &SM = Pass.Ctx.getSourceManager(); 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric // Break down the source location. 3880b57cec5SDimitry Andric std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc); 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric // Try to load the file buffer. 3910b57cec5SDimitry Andric bool invalidTemp = false; 3920b57cec5SDimitry Andric StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 3930b57cec5SDimitry Andric if (invalidTemp) 3940b57cec5SDimitry Andric return false; 3950b57cec5SDimitry Andric 3960b57cec5SDimitry Andric const char *tokenBegin = file.data() + locInfo.second; 3970b57cec5SDimitry Andric 3980b57cec5SDimitry Andric // Lex from the start of the given location. 3990b57cec5SDimitry Andric Lexer lexer(SM.getLocForStartOfFile(locInfo.first), 4000b57cec5SDimitry Andric Pass.Ctx.getLangOpts(), 4010b57cec5SDimitry Andric file.begin(), tokenBegin, file.end()); 4020b57cec5SDimitry Andric Token tok; 4030b57cec5SDimitry Andric lexer.LexFromRawLexer(tok); 4040b57cec5SDimitry Andric if (tok.isNot(tok::at)) return false; 4050b57cec5SDimitry Andric lexer.LexFromRawLexer(tok); 4060b57cec5SDimitry Andric if (tok.isNot(tok::raw_identifier)) return false; 4070b57cec5SDimitry Andric if (tok.getRawIdentifier() != "property") 4080b57cec5SDimitry Andric return false; 4090b57cec5SDimitry Andric lexer.LexFromRawLexer(tok); 4100b57cec5SDimitry Andric if (tok.isNot(tok::l_paren)) return false; 4110b57cec5SDimitry Andric 4120b57cec5SDimitry Andric Token BeforeTok = tok; 4130b57cec5SDimitry Andric Token AfterTok; 4140b57cec5SDimitry Andric AfterTok.startToken(); 4150b57cec5SDimitry Andric SourceLocation AttrLoc; 4160b57cec5SDimitry Andric 4170b57cec5SDimitry Andric lexer.LexFromRawLexer(tok); 4180b57cec5SDimitry Andric if (tok.is(tok::r_paren)) 4190b57cec5SDimitry Andric return false; 4200b57cec5SDimitry Andric 42104eeddc0SDimitry Andric while (true) { 4220b57cec5SDimitry Andric if (tok.isNot(tok::raw_identifier)) return false; 4230b57cec5SDimitry Andric if (tok.getRawIdentifier() == fromAttr) { 4240b57cec5SDimitry Andric if (!toAttr.empty()) { 4250b57cec5SDimitry Andric Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr); 4260b57cec5SDimitry Andric return true; 4270b57cec5SDimitry Andric } 4280b57cec5SDimitry Andric // We want to remove the attribute. 4290b57cec5SDimitry Andric AttrLoc = tok.getLocation(); 4300b57cec5SDimitry Andric } 4310b57cec5SDimitry Andric 4320b57cec5SDimitry Andric do { 4330b57cec5SDimitry Andric lexer.LexFromRawLexer(tok); 4340b57cec5SDimitry Andric if (AttrLoc.isValid() && AfterTok.is(tok::unknown)) 4350b57cec5SDimitry Andric AfterTok = tok; 4360b57cec5SDimitry Andric } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren)); 4370b57cec5SDimitry Andric if (tok.is(tok::r_paren)) 4380b57cec5SDimitry Andric break; 4390b57cec5SDimitry Andric if (AttrLoc.isInvalid()) 4400b57cec5SDimitry Andric BeforeTok = tok; 4410b57cec5SDimitry Andric lexer.LexFromRawLexer(tok); 4420b57cec5SDimitry Andric } 4430b57cec5SDimitry Andric 4440b57cec5SDimitry Andric if (toAttr.empty() && AttrLoc.isValid() && AfterTok.isNot(tok::unknown)) { 4450b57cec5SDimitry Andric // We want to remove the attribute. 4460b57cec5SDimitry Andric if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::r_paren)) { 4470b57cec5SDimitry Andric Pass.TA.remove(SourceRange(BeforeTok.getLocation(), 4480b57cec5SDimitry Andric AfterTok.getLocation())); 4490b57cec5SDimitry Andric } else if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::comma)) { 4500b57cec5SDimitry Andric Pass.TA.remove(SourceRange(AttrLoc, AfterTok.getLocation())); 4510b57cec5SDimitry Andric } else { 4520b57cec5SDimitry Andric Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AttrLoc)); 4530b57cec5SDimitry Andric } 4540b57cec5SDimitry Andric 4550b57cec5SDimitry Andric return true; 4560b57cec5SDimitry Andric } 4570b57cec5SDimitry Andric 4580b57cec5SDimitry Andric return false; 4590b57cec5SDimitry Andric } 4600b57cec5SDimitry Andric 4610b57cec5SDimitry Andric bool MigrationContext::addPropertyAttribute(StringRef attr, 4620b57cec5SDimitry Andric SourceLocation atLoc) { 4630b57cec5SDimitry Andric if (atLoc.isMacroID()) 4640b57cec5SDimitry Andric return false; 4650b57cec5SDimitry Andric 4660b57cec5SDimitry Andric SourceManager &SM = Pass.Ctx.getSourceManager(); 4670b57cec5SDimitry Andric 4680b57cec5SDimitry Andric // Break down the source location. 4690b57cec5SDimitry Andric std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc); 4700b57cec5SDimitry Andric 4710b57cec5SDimitry Andric // Try to load the file buffer. 4720b57cec5SDimitry Andric bool invalidTemp = false; 4730b57cec5SDimitry Andric StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 4740b57cec5SDimitry Andric if (invalidTemp) 4750b57cec5SDimitry Andric return false; 4760b57cec5SDimitry Andric 4770b57cec5SDimitry Andric const char *tokenBegin = file.data() + locInfo.second; 4780b57cec5SDimitry Andric 4790b57cec5SDimitry Andric // Lex from the start of the given location. 4800b57cec5SDimitry Andric Lexer lexer(SM.getLocForStartOfFile(locInfo.first), 4810b57cec5SDimitry Andric Pass.Ctx.getLangOpts(), 4820b57cec5SDimitry Andric file.begin(), tokenBegin, file.end()); 4830b57cec5SDimitry Andric Token tok; 4840b57cec5SDimitry Andric lexer.LexFromRawLexer(tok); 4850b57cec5SDimitry Andric if (tok.isNot(tok::at)) return false; 4860b57cec5SDimitry Andric lexer.LexFromRawLexer(tok); 4870b57cec5SDimitry Andric if (tok.isNot(tok::raw_identifier)) return false; 4880b57cec5SDimitry Andric if (tok.getRawIdentifier() != "property") 4890b57cec5SDimitry Andric return false; 4900b57cec5SDimitry Andric lexer.LexFromRawLexer(tok); 4910b57cec5SDimitry Andric 4920b57cec5SDimitry Andric if (tok.isNot(tok::l_paren)) { 4930b57cec5SDimitry Andric Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") "); 4940b57cec5SDimitry Andric return true; 4950b57cec5SDimitry Andric } 4960b57cec5SDimitry Andric 4970b57cec5SDimitry Andric lexer.LexFromRawLexer(tok); 4980b57cec5SDimitry Andric if (tok.is(tok::r_paren)) { 4990b57cec5SDimitry Andric Pass.TA.insert(tok.getLocation(), attr); 5000b57cec5SDimitry Andric return true; 5010b57cec5SDimitry Andric } 5020b57cec5SDimitry Andric 5030b57cec5SDimitry Andric if (tok.isNot(tok::raw_identifier)) return false; 5040b57cec5SDimitry Andric 5050b57cec5SDimitry Andric Pass.TA.insert(tok.getLocation(), std::string(attr) + ", "); 5060b57cec5SDimitry Andric return true; 5070b57cec5SDimitry Andric } 5080b57cec5SDimitry Andric 5090b57cec5SDimitry Andric void MigrationContext::traverse(TranslationUnitDecl *TU) { 5100b57cec5SDimitry Andric for (traverser_iterator 5110b57cec5SDimitry Andric I = traversers_begin(), E = traversers_end(); I != E; ++I) 5120b57cec5SDimitry Andric (*I)->traverseTU(*this); 5130b57cec5SDimitry Andric 5140b57cec5SDimitry Andric ASTTransform(*this).TraverseDecl(TU); 5150b57cec5SDimitry Andric } 5160b57cec5SDimitry Andric 5170b57cec5SDimitry Andric static void GCRewriteFinalize(MigrationPass &pass) { 5180b57cec5SDimitry Andric ASTContext &Ctx = pass.Ctx; 5190b57cec5SDimitry Andric TransformActions &TA = pass.TA; 5200b57cec5SDimitry Andric DeclContext *DC = Ctx.getTranslationUnitDecl(); 5210b57cec5SDimitry Andric Selector FinalizeSel = 5220b57cec5SDimitry Andric Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize")); 5230b57cec5SDimitry Andric 5240b57cec5SDimitry Andric typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl> 5250b57cec5SDimitry Andric impl_iterator; 5260b57cec5SDimitry Andric for (impl_iterator I = impl_iterator(DC->decls_begin()), 5270b57cec5SDimitry Andric E = impl_iterator(DC->decls_end()); I != E; ++I) { 5280b57cec5SDimitry Andric for (const auto *MD : I->instance_methods()) { 5290b57cec5SDimitry Andric if (!MD->hasBody()) 5300b57cec5SDimitry Andric continue; 5310b57cec5SDimitry Andric 5320b57cec5SDimitry Andric if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) { 5330b57cec5SDimitry Andric const ObjCMethodDecl *FinalizeM = MD; 5340b57cec5SDimitry Andric Transaction Trans(TA); 5350b57cec5SDimitry Andric TA.insert(FinalizeM->getSourceRange().getBegin(), 5360b57cec5SDimitry Andric "#if !__has_feature(objc_arc)\n"); 5370b57cec5SDimitry Andric CharSourceRange::getTokenRange(FinalizeM->getSourceRange()); 5380b57cec5SDimitry Andric const SourceManager &SM = pass.Ctx.getSourceManager(); 5390b57cec5SDimitry Andric const LangOptions &LangOpts = pass.Ctx.getLangOpts(); 5400b57cec5SDimitry Andric bool Invalid; 5410b57cec5SDimitry Andric std::string str = "\n#endif\n"; 5420b57cec5SDimitry Andric str += Lexer::getSourceText( 5430b57cec5SDimitry Andric CharSourceRange::getTokenRange(FinalizeM->getSourceRange()), 5440b57cec5SDimitry Andric SM, LangOpts, &Invalid); 5450b57cec5SDimitry Andric TA.insertAfterToken(FinalizeM->getSourceRange().getEnd(), str); 5460b57cec5SDimitry Andric 5470b57cec5SDimitry Andric break; 5480b57cec5SDimitry Andric } 5490b57cec5SDimitry Andric } 5500b57cec5SDimitry Andric } 5510b57cec5SDimitry Andric } 5520b57cec5SDimitry Andric 5530b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 5540b57cec5SDimitry Andric // getAllTransformations. 5550b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 5560b57cec5SDimitry Andric 5570b57cec5SDimitry Andric static void traverseAST(MigrationPass &pass) { 5580b57cec5SDimitry Andric MigrationContext MigrateCtx(pass); 5590b57cec5SDimitry Andric 5600b57cec5SDimitry Andric if (pass.isGCMigration()) { 5610b57cec5SDimitry Andric MigrateCtx.addTraverser(new GCCollectableCallsTraverser); 5620b57cec5SDimitry Andric MigrateCtx.addTraverser(new GCAttrsTraverser()); 5630b57cec5SDimitry Andric } 5640b57cec5SDimitry Andric MigrateCtx.addTraverser(new PropertyRewriteTraverser()); 5650b57cec5SDimitry Andric MigrateCtx.addTraverser(new BlockObjCVariableTraverser()); 5660b57cec5SDimitry Andric MigrateCtx.addTraverser(new ProtectedScopeTraverser()); 5670b57cec5SDimitry Andric 5680b57cec5SDimitry Andric MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl()); 5690b57cec5SDimitry Andric } 5700b57cec5SDimitry Andric 5710b57cec5SDimitry Andric static void independentTransforms(MigrationPass &pass) { 5720b57cec5SDimitry Andric rewriteAutoreleasePool(pass); 5730b57cec5SDimitry Andric removeRetainReleaseDeallocFinalize(pass); 5740b57cec5SDimitry Andric rewriteUnusedInitDelegate(pass); 5750b57cec5SDimitry Andric removeZeroOutPropsInDeallocFinalize(pass); 5760b57cec5SDimitry Andric makeAssignARCSafe(pass); 5770b57cec5SDimitry Andric rewriteUnbridgedCasts(pass); 5780b57cec5SDimitry Andric checkAPIUses(pass); 5790b57cec5SDimitry Andric traverseAST(pass); 5800b57cec5SDimitry Andric } 5810b57cec5SDimitry Andric 5820b57cec5SDimitry Andric std::vector<TransformFn> arcmt::getAllTransformations( 5830b57cec5SDimitry Andric LangOptions::GCMode OrigGCMode, 5840b57cec5SDimitry Andric bool NoFinalizeRemoval) { 5850b57cec5SDimitry Andric std::vector<TransformFn> transforms; 5860b57cec5SDimitry Andric 5870b57cec5SDimitry Andric if (OrigGCMode == LangOptions::GCOnly && NoFinalizeRemoval) 5880b57cec5SDimitry Andric transforms.push_back(GCRewriteFinalize); 5890b57cec5SDimitry Andric transforms.push_back(independentTransforms); 5900b57cec5SDimitry Andric // This depends on previous transformations removing various expressions. 5910b57cec5SDimitry Andric transforms.push_back(removeEmptyStatementsAndDeallocFinalize); 5920b57cec5SDimitry Andric 5930b57cec5SDimitry Andric return transforms; 5940b57cec5SDimitry Andric } 595