1 //===--- TransAPIUses.cpp - Transformations to ARC mode -------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
12 // Emits error/fix with some API uses that are obsolete or not safe in ARC mode:
14 // - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe
15 // with __unsafe_unretained objects.
16 // - Calling -zone gets replaced with 'nil'.
18 //===----------------------------------------------------------------------===//
20 #include "Transforms.h"
21 #include "Internals.h"
22 #include "clang/AST/ASTContext.h"
23 #include "clang/Sema/SemaDiagnostic.h"
25 using namespace clang;
26 using namespace arcmt;
27 using namespace trans;
31 class APIChecker : public RecursiveASTVisitor<APIChecker> {
34 Selector getReturnValueSel, setReturnValueSel;
35 Selector getArgumentSel, setArgumentSel;
39 APIChecker(MigrationPass &pass) : Pass(pass) {
40 SelectorTable &sels = Pass.Ctx.Selectors;
41 IdentifierTable &ids = Pass.Ctx.Idents;
42 getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue"));
43 setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue"));
45 IdentifierInfo *selIds[2];
46 selIds[0] = &ids.get("getArgument");
47 selIds[1] = &ids.get("atIndex");
48 getArgumentSel = sels.getSelector(2, selIds);
49 selIds[0] = &ids.get("setArgument");
50 setArgumentSel = sels.getSelector(2, selIds);
52 zoneSel = sels.getNullarySelector(&ids.get("zone"));
55 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
57 if (E->isInstanceMessage() &&
58 E->getReceiverInterface() &&
59 E->getReceiverInterface()->getName() == "NSInvocation") {
61 if (E->getSelector() == getReturnValueSel)
62 selName = "getReturnValue";
63 else if (E->getSelector() == setReturnValueSel)
64 selName = "setReturnValue";
65 else if (E->getSelector() == getArgumentSel)
66 selName = "getArgument";
67 else if (E->getSelector() == setArgumentSel)
68 selName = "setArgument";
73 Expr *parm = E->getArg(0)->IgnoreParenCasts();
74 QualType pointee = parm->getType()->getPointeeType();
78 if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) {
79 std::string err = "NSInvocation's ";
81 err += " is not safe to be used with an object with ownership other "
82 "than __unsafe_unretained";
83 Pass.TA.reportError(err, parm->getLocStart(), parm->getSourceRange());
89 if (E->isInstanceMessage() &&
90 E->getInstanceReceiver() &&
91 E->getSelector() == zoneSel &&
92 Pass.TA.hasDiagnostic(diag::err_unavailable,
93 diag::err_unavailable_message,
94 E->getSelectorLoc(0))) {
95 // Calling -zone is meaningless in ARC, change it to nil.
96 Transaction Trans(Pass.TA);
97 Pass.TA.clearDiagnostic(diag::err_unavailable,
98 diag::err_unavailable_message,
99 E->getSelectorLoc(0));
100 Pass.TA.replace(E->getSourceRange(), getNilString(Pass.Ctx));
106 } // anonymous namespace
108 void trans::checkAPIUses(MigrationPass &pass) {
109 APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());