1139f7f9bSDimitry Andric //===--- TransAPIUses.cpp - Transformations to ARC mode -------------------===//
26122f3e6SDimitry Andric //
36122f3e6SDimitry Andric //                     The LLVM Compiler Infrastructure
46122f3e6SDimitry Andric //
56122f3e6SDimitry Andric // This file is distributed under the University of Illinois Open Source
66122f3e6SDimitry Andric // License. See LICENSE.TXT for details.
76122f3e6SDimitry Andric //
86122f3e6SDimitry Andric //===----------------------------------------------------------------------===//
96122f3e6SDimitry Andric //
106122f3e6SDimitry Andric // checkAPIUses:
116122f3e6SDimitry Andric //
126122f3e6SDimitry Andric // Emits error/fix with some API uses that are obsolete or not safe in ARC mode:
136122f3e6SDimitry Andric //
146122f3e6SDimitry Andric // - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe
156122f3e6SDimitry Andric //   with __unsafe_unretained objects.
166122f3e6SDimitry Andric // - Calling -zone gets replaced with 'nil'.
176122f3e6SDimitry Andric //
186122f3e6SDimitry Andric //===----------------------------------------------------------------------===//
196122f3e6SDimitry Andric 
206122f3e6SDimitry Andric #include "Transforms.h"
216122f3e6SDimitry Andric #include "Internals.h"
227ae0e2c9SDimitry Andric #include "clang/AST/ASTContext.h"
236122f3e6SDimitry Andric #include "clang/Sema/SemaDiagnostic.h"
246122f3e6SDimitry Andric 
256122f3e6SDimitry Andric using namespace clang;
266122f3e6SDimitry Andric using namespace arcmt;
276122f3e6SDimitry Andric using namespace trans;
286122f3e6SDimitry Andric 
296122f3e6SDimitry Andric namespace {
306122f3e6SDimitry Andric 
316122f3e6SDimitry Andric class APIChecker : public RecursiveASTVisitor<APIChecker> {
326122f3e6SDimitry Andric   MigrationPass &Pass;
336122f3e6SDimitry Andric 
346122f3e6SDimitry Andric   Selector getReturnValueSel, setReturnValueSel;
356122f3e6SDimitry Andric   Selector getArgumentSel, setArgumentSel;
366122f3e6SDimitry Andric 
376122f3e6SDimitry Andric   Selector zoneSel;
386122f3e6SDimitry Andric public:
APIChecker(MigrationPass & pass)396122f3e6SDimitry Andric   APIChecker(MigrationPass &pass) : Pass(pass) {
406122f3e6SDimitry Andric     SelectorTable &sels = Pass.Ctx.Selectors;
416122f3e6SDimitry Andric     IdentifierTable &ids = Pass.Ctx.Idents;
426122f3e6SDimitry Andric     getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue"));
436122f3e6SDimitry Andric     setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue"));
446122f3e6SDimitry Andric 
456122f3e6SDimitry Andric     IdentifierInfo *selIds[2];
466122f3e6SDimitry Andric     selIds[0] = &ids.get("getArgument");
476122f3e6SDimitry Andric     selIds[1] = &ids.get("atIndex");
486122f3e6SDimitry Andric     getArgumentSel = sels.getSelector(2, selIds);
496122f3e6SDimitry Andric     selIds[0] = &ids.get("setArgument");
506122f3e6SDimitry Andric     setArgumentSel = sels.getSelector(2, selIds);
516122f3e6SDimitry Andric 
526122f3e6SDimitry Andric     zoneSel = sels.getNullarySelector(&ids.get("zone"));
536122f3e6SDimitry Andric   }
546122f3e6SDimitry Andric 
VisitObjCMessageExpr(ObjCMessageExpr * E)556122f3e6SDimitry Andric   bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
566122f3e6SDimitry Andric     // NSInvocation.
576122f3e6SDimitry Andric     if (E->isInstanceMessage() &&
586122f3e6SDimitry Andric         E->getReceiverInterface() &&
596122f3e6SDimitry Andric         E->getReceiverInterface()->getName() == "NSInvocation") {
606122f3e6SDimitry Andric       StringRef selName;
616122f3e6SDimitry Andric       if (E->getSelector() == getReturnValueSel)
626122f3e6SDimitry Andric         selName = "getReturnValue";
636122f3e6SDimitry Andric       else if (E->getSelector() == setReturnValueSel)
646122f3e6SDimitry Andric         selName = "setReturnValue";
656122f3e6SDimitry Andric       else if (E->getSelector() == getArgumentSel)
666122f3e6SDimitry Andric         selName = "getArgument";
676122f3e6SDimitry Andric       else if (E->getSelector() == setArgumentSel)
686122f3e6SDimitry Andric         selName = "setArgument";
6959d1ed5bSDimitry Andric       else
706122f3e6SDimitry Andric         return true;
716122f3e6SDimitry Andric 
726122f3e6SDimitry Andric       Expr *parm = E->getArg(0)->IgnoreParenCasts();
736122f3e6SDimitry Andric       QualType pointee = parm->getType()->getPointeeType();
746122f3e6SDimitry Andric       if (pointee.isNull())
756122f3e6SDimitry Andric         return true;
766122f3e6SDimitry Andric 
7759d1ed5bSDimitry Andric       if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone)
78*b5893f02SDimitry Andric         Pass.TA.report(parm->getBeginLoc(),
7959d1ed5bSDimitry Andric                        diag::err_arcmt_nsinvocation_ownership,
8059d1ed5bSDimitry Andric                        parm->getSourceRange())
8159d1ed5bSDimitry Andric             << selName;
8259d1ed5bSDimitry Andric 
836122f3e6SDimitry Andric       return true;
846122f3e6SDimitry Andric     }
856122f3e6SDimitry Andric 
866122f3e6SDimitry Andric     // -zone.
876122f3e6SDimitry Andric     if (E->isInstanceMessage() &&
886122f3e6SDimitry Andric         E->getInstanceReceiver() &&
896122f3e6SDimitry Andric         E->getSelector() == zoneSel &&
906122f3e6SDimitry Andric         Pass.TA.hasDiagnostic(diag::err_unavailable,
916122f3e6SDimitry Andric                               diag::err_unavailable_message,
92284c1978SDimitry Andric                               E->getSelectorLoc(0))) {
936122f3e6SDimitry Andric       // Calling -zone is meaningless in ARC, change it to nil.
946122f3e6SDimitry Andric       Transaction Trans(Pass.TA);
956122f3e6SDimitry Andric       Pass.TA.clearDiagnostic(diag::err_unavailable,
966122f3e6SDimitry Andric                               diag::err_unavailable_message,
97284c1978SDimitry Andric                               E->getSelectorLoc(0));
9833956c43SDimitry Andric       Pass.TA.replace(E->getSourceRange(), getNilString(Pass));
996122f3e6SDimitry Andric     }
1006122f3e6SDimitry Andric     return true;
1016122f3e6SDimitry Andric   }
1026122f3e6SDimitry Andric };
1036122f3e6SDimitry Andric 
1046122f3e6SDimitry Andric } // anonymous namespace
1056122f3e6SDimitry Andric 
checkAPIUses(MigrationPass & pass)1066122f3e6SDimitry Andric void trans::checkAPIUses(MigrationPass &pass) {
1076122f3e6SDimitry Andric   APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
1086122f3e6SDimitry Andric }
109