1//===--- TransAPIUses.cpp - Transformations to ARC mode -------------------===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// checkAPIUses: 10// 11// Emits error/fix with some API uses that are obsolete or not safe in ARC mode: 12// 13// - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe 14// with __unsafe_unretained objects. 15// - Calling -zone gets replaced with 'nil'. 16// 17//===----------------------------------------------------------------------===// 18 19#include "Transforms.h" 20#include "Internals.h" 21#include "clang/AST/ASTContext.h" 22#include "clang/Sema/SemaDiagnostic.h" 23 24using namespace clang; 25using namespace arcmt; 26using namespace trans; 27 28namespace { 29 30class APIChecker : public RecursiveASTVisitor<APIChecker> { 31 MigrationPass &Pass; 32 33 Selector getReturnValueSel, setReturnValueSel; 34 Selector getArgumentSel, setArgumentSel; 35 36 Selector zoneSel; 37public: 38 APIChecker(MigrationPass &pass) : Pass(pass) { 39 SelectorTable &sels = Pass.Ctx.Selectors; 40 IdentifierTable &ids = Pass.Ctx.Idents; 41 getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue")); 42 setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue")); 43 44 IdentifierInfo *selIds[2]; 45 selIds[0] = &ids.get("getArgument"); 46 selIds[1] = &ids.get("atIndex"); 47 getArgumentSel = sels.getSelector(2, selIds); 48 selIds[0] = &ids.get("setArgument"); 49 setArgumentSel = sels.getSelector(2, selIds); 50 51 zoneSel = sels.getNullarySelector(&ids.get("zone")); 52 } 53 54 bool VisitObjCMessageExpr(ObjCMessageExpr *E) { 55 // NSInvocation. 56 if (E->isInstanceMessage() && 57 E->getReceiverInterface() && 58 E->getReceiverInterface()->getName() == "NSInvocation") { 59 StringRef selName; 60 if (E->getSelector() == getReturnValueSel) 61 selName = "getReturnValue"; 62 else if (E->getSelector() == setReturnValueSel) 63 selName = "setReturnValue"; 64 else if (E->getSelector() == getArgumentSel) 65 selName = "getArgument"; 66 else if (E->getSelector() == setArgumentSel) 67 selName = "setArgument"; 68 else 69 return true; 70 71 Expr *parm = E->getArg(0)->IgnoreParenCasts(); 72 QualType pointee = parm->getType()->getPointeeType(); 73 if (pointee.isNull()) 74 return true; 75 76 if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) 77 Pass.TA.report(parm->getBeginLoc(), 78 diag::err_arcmt_nsinvocation_ownership, 79 parm->getSourceRange()) 80 << selName; 81 82 return true; 83 } 84 85 // -zone. 86 if (E->isInstanceMessage() && 87 E->getInstanceReceiver() && 88 E->getSelector() == zoneSel && 89 Pass.TA.hasDiagnostic(diag::err_unavailable, 90 diag::err_unavailable_message, 91 E->getSelectorLoc(0))) { 92 // Calling -zone is meaningless in ARC, change it to nil. 93 Transaction Trans(Pass.TA); 94 Pass.TA.clearDiagnostic(diag::err_unavailable, 95 diag::err_unavailable_message, 96 E->getSelectorLoc(0)); 97 Pass.TA.replace(E->getSourceRange(), getNilString(Pass)); 98 } 99 return true; 100 } 101}; 102 103} // anonymous namespace 104 105void trans::checkAPIUses(MigrationPass &pass) { 106 APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 107} 108