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
~ASTTraverser()260b57cec5SDimitry Andric ASTTraverser::~ASTTraverser() { }
270b57cec5SDimitry Andric
CFBridgingFunctionsDefined()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
canApplyWeak(ASTContext & Ctx,QualType type,bool AllowOnUnknownClass)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
isPlusOneAssign(const BinaryOperator * E)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
isPlusOne(const Expr * E)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.
findLocationAfterSemi(SourceLocation loc,ASTContext & Ctx,bool IsDecl)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.
findSemiAfterLocation(SourceLocation loc,ASTContext & Ctx,bool IsDecl)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
hasSideEffects(Expr * E,ASTContext & Ctx)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
isGlobalVar(Expr * E)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
getNilString(MigrationPass & Pass)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:
ReferenceClear(ExprSet & refs)2170b57cec5SDimitry Andric ReferenceClear(ExprSet &refs) : Refs(refs) { }
VisitDeclRefExpr(DeclRefExpr * E)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:
ReferenceCollector(ValueDecl * D,ExprSet & refs)2260b57cec5SDimitry Andric ReferenceCollector(ValueDecl *D, ExprSet &refs)
2270b57cec5SDimitry Andric : Dcl(D), Refs(refs) { }
2280b57cec5SDimitry Andric
VisitDeclRefExpr(DeclRefExpr * E)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:
RemovablesCollector(ExprSet & removables)2400b57cec5SDimitry Andric RemovablesCollector(ExprSet &removables)
2410b57cec5SDimitry Andric : Removables(removables) { }
2420b57cec5SDimitry Andric
shouldWalkTypesOfTypeLocs() const2430b57cec5SDimitry Andric bool shouldWalkTypesOfTypeLocs() const { return false; }
2440b57cec5SDimitry Andric
TraverseStmtExpr(StmtExpr * E)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
VisitCompoundStmt(CompoundStmt * S)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
VisitIfStmt(IfStmt * S)2620b57cec5SDimitry Andric bool VisitIfStmt(IfStmt *S) {
2630b57cec5SDimitry Andric mark(S->getThen());
2640b57cec5SDimitry Andric mark(S->getElse());
2650b57cec5SDimitry Andric return true;
2660b57cec5SDimitry Andric }
2670b57cec5SDimitry Andric
VisitWhileStmt(WhileStmt * S)2680b57cec5SDimitry Andric bool VisitWhileStmt(WhileStmt *S) {
2690b57cec5SDimitry Andric mark(S->getBody());
2700b57cec5SDimitry Andric return true;
2710b57cec5SDimitry Andric }
2720b57cec5SDimitry Andric
VisitDoStmt(DoStmt * S)2730b57cec5SDimitry Andric bool VisitDoStmt(DoStmt *S) {
2740b57cec5SDimitry Andric mark(S->getBody());
2750b57cec5SDimitry Andric return true;
2760b57cec5SDimitry Andric }
2770b57cec5SDimitry Andric
VisitForStmt(ForStmt * S)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:
mark(Stmt * S)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
clearRefsIn(Stmt * S,ExprSet & refs)3000b57cec5SDimitry Andric void trans::clearRefsIn(Stmt *S, ExprSet &refs) {
3010b57cec5SDimitry Andric ReferenceClear(refs).TraverseStmt(S);
3020b57cec5SDimitry Andric }
3030b57cec5SDimitry Andric
collectRefs(ValueDecl * D,Stmt * S,ExprSet & refs)3040b57cec5SDimitry Andric void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) {
3050b57cec5SDimitry Andric ReferenceCollector(D, refs).TraverseStmt(S);
3060b57cec5SDimitry Andric }
3070b57cec5SDimitry Andric
collectRemovables(Stmt * S,ExprSet & exprs)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:
ASTTransform(MigrationContext & MigrateCtx)3230b57cec5SDimitry Andric ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { }
3240b57cec5SDimitry Andric
shouldWalkTypesOfTypeLocs() const3250b57cec5SDimitry Andric bool shouldWalkTypesOfTypeLocs() const { return false; }
3260b57cec5SDimitry Andric
TraverseObjCImplementationDecl(ObjCImplementationDecl * D)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
TraverseStmt(Stmt * rootS)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
~MigrationContext()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
isGCOwnedNonObjC(QualType T)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
rewritePropertyAttribute(StringRef fromAttr,StringRef toAttr,SourceLocation atLoc)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
addPropertyAttribute(StringRef attr,SourceLocation atLoc)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
traverse(TranslationUnitDecl * TU)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
GCRewriteFinalize(MigrationPass & pass)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
traverseAST(MigrationPass & pass)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
independentTransforms(MigrationPass & pass)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
getAllTransformations(LangOptions::GCMode OrigGCMode,bool NoFinalizeRemoval)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