xref: /freebsd-src/contrib/llvm-project/clang/lib/ARCMigrate/Transforms.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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