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