xref: /freebsd-src/contrib/llvm-project/clang/lib/ARCMigrate/TransAPIUses.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===--- TransAPIUses.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 // checkAPIUses:
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric // Emits error/fix with some API uses that are obsolete or not safe in ARC mode:
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric // - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe
140b57cec5SDimitry Andric //   with __unsafe_unretained objects.
150b57cec5SDimitry Andric // - Calling -zone gets replaced with 'nil'.
160b57cec5SDimitry Andric //
170b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric #include "Transforms.h"
200b57cec5SDimitry Andric #include "Internals.h"
210b57cec5SDimitry Andric #include "clang/AST/ASTContext.h"
220b57cec5SDimitry Andric #include "clang/Sema/SemaDiagnostic.h"
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric using namespace clang;
250b57cec5SDimitry Andric using namespace arcmt;
260b57cec5SDimitry Andric using namespace trans;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric namespace {
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric class APIChecker : public RecursiveASTVisitor<APIChecker> {
310b57cec5SDimitry Andric   MigrationPass &Pass;
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric   Selector getReturnValueSel, setReturnValueSel;
340b57cec5SDimitry Andric   Selector getArgumentSel, setArgumentSel;
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric   Selector zoneSel;
370b57cec5SDimitry Andric public:
380b57cec5SDimitry Andric   APIChecker(MigrationPass &pass) : Pass(pass) {
390b57cec5SDimitry Andric     SelectorTable &sels = Pass.Ctx.Selectors;
400b57cec5SDimitry Andric     IdentifierTable &ids = Pass.Ctx.Idents;
410b57cec5SDimitry Andric     getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue"));
420b57cec5SDimitry Andric     setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue"));
430b57cec5SDimitry Andric 
44*0fca6ea1SDimitry Andric     const IdentifierInfo *selIds[2];
450b57cec5SDimitry Andric     selIds[0] = &ids.get("getArgument");
460b57cec5SDimitry Andric     selIds[1] = &ids.get("atIndex");
470b57cec5SDimitry Andric     getArgumentSel = sels.getSelector(2, selIds);
480b57cec5SDimitry Andric     selIds[0] = &ids.get("setArgument");
490b57cec5SDimitry Andric     setArgumentSel = sels.getSelector(2, selIds);
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric     zoneSel = sels.getNullarySelector(&ids.get("zone"));
520b57cec5SDimitry Andric   }
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
550b57cec5SDimitry Andric     // NSInvocation.
560b57cec5SDimitry Andric     if (E->isInstanceMessage() &&
570b57cec5SDimitry Andric         E->getReceiverInterface() &&
580b57cec5SDimitry Andric         E->getReceiverInterface()->getName() == "NSInvocation") {
590b57cec5SDimitry Andric       StringRef selName;
600b57cec5SDimitry Andric       if (E->getSelector() == getReturnValueSel)
610b57cec5SDimitry Andric         selName = "getReturnValue";
620b57cec5SDimitry Andric       else if (E->getSelector() == setReturnValueSel)
630b57cec5SDimitry Andric         selName = "setReturnValue";
640b57cec5SDimitry Andric       else if (E->getSelector() == getArgumentSel)
650b57cec5SDimitry Andric         selName = "getArgument";
660b57cec5SDimitry Andric       else if (E->getSelector() == setArgumentSel)
670b57cec5SDimitry Andric         selName = "setArgument";
680b57cec5SDimitry Andric       else
690b57cec5SDimitry Andric         return true;
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric       Expr *parm = E->getArg(0)->IgnoreParenCasts();
720b57cec5SDimitry Andric       QualType pointee = parm->getType()->getPointeeType();
730b57cec5SDimitry Andric       if (pointee.isNull())
740b57cec5SDimitry Andric         return true;
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric       if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone)
770b57cec5SDimitry Andric         Pass.TA.report(parm->getBeginLoc(),
780b57cec5SDimitry Andric                        diag::err_arcmt_nsinvocation_ownership,
790b57cec5SDimitry Andric                        parm->getSourceRange())
800b57cec5SDimitry Andric             << selName;
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric       return true;
830b57cec5SDimitry Andric     }
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric     // -zone.
860b57cec5SDimitry Andric     if (E->isInstanceMessage() &&
870b57cec5SDimitry Andric         E->getInstanceReceiver() &&
880b57cec5SDimitry Andric         E->getSelector() == zoneSel &&
890b57cec5SDimitry Andric         Pass.TA.hasDiagnostic(diag::err_unavailable,
900b57cec5SDimitry Andric                               diag::err_unavailable_message,
910b57cec5SDimitry Andric                               E->getSelectorLoc(0))) {
920b57cec5SDimitry Andric       // Calling -zone is meaningless in ARC, change it to nil.
930b57cec5SDimitry Andric       Transaction Trans(Pass.TA);
940b57cec5SDimitry Andric       Pass.TA.clearDiagnostic(diag::err_unavailable,
950b57cec5SDimitry Andric                               diag::err_unavailable_message,
960b57cec5SDimitry Andric                               E->getSelectorLoc(0));
970b57cec5SDimitry Andric       Pass.TA.replace(E->getSourceRange(), getNilString(Pass));
980b57cec5SDimitry Andric     }
990b57cec5SDimitry Andric     return true;
1000b57cec5SDimitry Andric   }
1010b57cec5SDimitry Andric };
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric } // anonymous namespace
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric void trans::checkAPIUses(MigrationPass &pass) {
1060b57cec5SDimitry Andric   APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
1070b57cec5SDimitry Andric }
108