1d81108f0SBenjamin Kramer //===--- TransAPIUses.cpp - Transformations to ARC mode -------------------===//
273a0d32dSArgyrios Kyrtzidis //
3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
673a0d32dSArgyrios Kyrtzidis //
773a0d32dSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
873a0d32dSArgyrios Kyrtzidis //
973a0d32dSArgyrios Kyrtzidis // checkAPIUses:
1073a0d32dSArgyrios Kyrtzidis //
1193907473SArgyrios Kyrtzidis // Emits error/fix with some API uses that are obsolete or not safe in ARC mode:
1273a0d32dSArgyrios Kyrtzidis //
1373a0d32dSArgyrios Kyrtzidis // - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe
1473a0d32dSArgyrios Kyrtzidis //   with __unsafe_unretained objects.
1593907473SArgyrios Kyrtzidis // - Calling -zone gets replaced with 'nil'.
1673a0d32dSArgyrios Kyrtzidis //
1773a0d32dSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
1873a0d32dSArgyrios Kyrtzidis 
1973a0d32dSArgyrios Kyrtzidis #include "Transforms.h"
2073a0d32dSArgyrios Kyrtzidis #include "Internals.h"
214ab984e7SBenjamin Kramer #include "clang/AST/ASTContext.h"
2293907473SArgyrios Kyrtzidis #include "clang/Sema/SemaDiagnostic.h"
2373a0d32dSArgyrios Kyrtzidis 
2473a0d32dSArgyrios Kyrtzidis using namespace clang;
2573a0d32dSArgyrios Kyrtzidis using namespace arcmt;
2673a0d32dSArgyrios Kyrtzidis using namespace trans;
2773a0d32dSArgyrios Kyrtzidis 
2873a0d32dSArgyrios Kyrtzidis namespace {
2973a0d32dSArgyrios Kyrtzidis 
3073a0d32dSArgyrios Kyrtzidis class APIChecker : public RecursiveASTVisitor<APIChecker> {
3173a0d32dSArgyrios Kyrtzidis   MigrationPass &Pass;
3291c62bfcSArgyrios Kyrtzidis 
3373a0d32dSArgyrios Kyrtzidis   Selector getReturnValueSel, setReturnValueSel;
3473a0d32dSArgyrios Kyrtzidis   Selector getArgumentSel, setArgumentSel;
3573a0d32dSArgyrios Kyrtzidis 
3693907473SArgyrios Kyrtzidis   Selector zoneSel;
3773a0d32dSArgyrios Kyrtzidis public:
APIChecker(MigrationPass & pass)3873a0d32dSArgyrios Kyrtzidis   APIChecker(MigrationPass &pass) : Pass(pass) {
3973a0d32dSArgyrios Kyrtzidis     SelectorTable &sels = Pass.Ctx.Selectors;
4073a0d32dSArgyrios Kyrtzidis     IdentifierTable &ids = Pass.Ctx.Idents;
4173a0d32dSArgyrios Kyrtzidis     getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue"));
4273a0d32dSArgyrios Kyrtzidis     setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue"));
4373a0d32dSArgyrios Kyrtzidis 
4473a0d32dSArgyrios Kyrtzidis     IdentifierInfo *selIds[2];
4573a0d32dSArgyrios Kyrtzidis     selIds[0] = &ids.get("getArgument");
4673a0d32dSArgyrios Kyrtzidis     selIds[1] = &ids.get("atIndex");
4773a0d32dSArgyrios Kyrtzidis     getArgumentSel = sels.getSelector(2, selIds);
4873a0d32dSArgyrios Kyrtzidis     selIds[0] = &ids.get("setArgument");
4973a0d32dSArgyrios Kyrtzidis     setArgumentSel = sels.getSelector(2, selIds);
5091c62bfcSArgyrios Kyrtzidis 
5193907473SArgyrios Kyrtzidis     zoneSel = sels.getNullarySelector(&ids.get("zone"));
5273a0d32dSArgyrios Kyrtzidis   }
5373a0d32dSArgyrios Kyrtzidis 
VisitObjCMessageExpr(ObjCMessageExpr * E)5473a0d32dSArgyrios Kyrtzidis   bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
5593907473SArgyrios Kyrtzidis     // NSInvocation.
5673a0d32dSArgyrios Kyrtzidis     if (E->isInstanceMessage() &&
5773a0d32dSArgyrios Kyrtzidis         E->getReceiverInterface() &&
5873a0d32dSArgyrios Kyrtzidis         E->getReceiverInterface()->getName() == "NSInvocation") {
5973a0d32dSArgyrios Kyrtzidis       StringRef selName;
6073a0d32dSArgyrios Kyrtzidis       if (E->getSelector() == getReturnValueSel)
6173a0d32dSArgyrios Kyrtzidis         selName = "getReturnValue";
6273a0d32dSArgyrios Kyrtzidis       else if (E->getSelector() == setReturnValueSel)
6373a0d32dSArgyrios Kyrtzidis         selName = "setReturnValue";
6473a0d32dSArgyrios Kyrtzidis       else if (E->getSelector() == getArgumentSel)
6573a0d32dSArgyrios Kyrtzidis         selName = "getArgument";
6673a0d32dSArgyrios Kyrtzidis       else if (E->getSelector() == setArgumentSel)
6773a0d32dSArgyrios Kyrtzidis         selName = "setArgument";
6842aa2122SAlp Toker       else
6973a0d32dSArgyrios Kyrtzidis         return true;
7073a0d32dSArgyrios Kyrtzidis 
7173a0d32dSArgyrios Kyrtzidis       Expr *parm = E->getArg(0)->IgnoreParenCasts();
7273a0d32dSArgyrios Kyrtzidis       QualType pointee = parm->getType()->getPointeeType();
7373a0d32dSArgyrios Kyrtzidis       if (pointee.isNull())
7473a0d32dSArgyrios Kyrtzidis         return true;
7573a0d32dSArgyrios Kyrtzidis 
7642aa2122SAlp Toker       if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone)
77f2ceec48SStephen Kelly         Pass.TA.report(parm->getBeginLoc(),
7842aa2122SAlp Toker                        diag::err_arcmt_nsinvocation_ownership,
7942aa2122SAlp Toker                        parm->getSourceRange())
8042aa2122SAlp Toker             << selName;
8142aa2122SAlp Toker 
8273a0d32dSArgyrios Kyrtzidis       return true;
8373a0d32dSArgyrios Kyrtzidis     }
8473a0d32dSArgyrios Kyrtzidis 
8593907473SArgyrios Kyrtzidis     // -zone.
8693907473SArgyrios Kyrtzidis     if (E->isInstanceMessage() &&
8793907473SArgyrios Kyrtzidis         E->getInstanceReceiver() &&
8893907473SArgyrios Kyrtzidis         E->getSelector() == zoneSel &&
8993907473SArgyrios Kyrtzidis         Pass.TA.hasDiagnostic(diag::err_unavailable,
9093907473SArgyrios Kyrtzidis                               diag::err_unavailable_message,
91bcf2bdc9SArgyrios Kyrtzidis                               E->getSelectorLoc(0))) {
9293907473SArgyrios Kyrtzidis       // Calling -zone is meaningless in ARC, change it to nil.
9393907473SArgyrios Kyrtzidis       Transaction Trans(Pass.TA);
9493907473SArgyrios Kyrtzidis       Pass.TA.clearDiagnostic(diag::err_unavailable,
9593907473SArgyrios Kyrtzidis                               diag::err_unavailable_message,
96bcf2bdc9SArgyrios Kyrtzidis                               E->getSelectorLoc(0));
9720e883e5SRichard Smith       Pass.TA.replace(E->getSourceRange(), getNilString(Pass));
9893907473SArgyrios Kyrtzidis     }
9973a0d32dSArgyrios Kyrtzidis     return true;
10073a0d32dSArgyrios Kyrtzidis   }
10173a0d32dSArgyrios Kyrtzidis };
10273a0d32dSArgyrios Kyrtzidis 
10373a0d32dSArgyrios Kyrtzidis } // anonymous namespace
10473a0d32dSArgyrios Kyrtzidis 
checkAPIUses(MigrationPass & pass)10573a0d32dSArgyrios Kyrtzidis void trans::checkAPIUses(MigrationPass &pass) {
10673a0d32dSArgyrios Kyrtzidis   APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
10773a0d32dSArgyrios Kyrtzidis }
108