1//===--- TransAPIUses.cpp - Transformations to ARC mode -------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// checkAPIUses: 11// 12// Emits error/fix with some API uses that are obsolete or not safe in ARC mode: 13// 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'. 17// 18//===----------------------------------------------------------------------===// 19 20#include "Transforms.h" 21#include "Internals.h" 22#include "clang/AST/ASTContext.h" 23#include "clang/Sema/SemaDiagnostic.h" 24 25using namespace clang; 26using namespace arcmt; 27using namespace trans; 28 29namespace { 30 31class APIChecker : public RecursiveASTVisitor<APIChecker> { 32 MigrationPass &Pass; 33 34 Selector getReturnValueSel, setReturnValueSel; 35 Selector getArgumentSel, setArgumentSel; 36 37 Selector zoneSel; 38public: 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")); 44 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); 51 52 zoneSel = sels.getNullarySelector(&ids.get("zone")); 53 } 54 55 bool VisitObjCMessageExpr(ObjCMessageExpr *E) { 56 // NSInvocation. 57 if (E->isInstanceMessage() && 58 E->getReceiverInterface() && 59 E->getReceiverInterface()->getName() == "NSInvocation") { 60 StringRef selName; 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"; 69 else 70 return true; 71 72 Expr *parm = E->getArg(0)->IgnoreParenCasts(); 73 QualType pointee = parm->getType()->getPointeeType(); 74 if (pointee.isNull()) 75 return true; 76 77 if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) 78 Pass.TA.report(parm->getLocStart(), 79 diag::err_arcmt_nsinvocation_ownership, 80 parm->getSourceRange()) 81 << selName; 82 83 return true; 84 } 85 86 // -zone. 87 if (E->isInstanceMessage() && 88 E->getInstanceReceiver() && 89 E->getSelector() == zoneSel && 90 Pass.TA.hasDiagnostic(diag::err_unavailable, 91 diag::err_unavailable_message, 92 E->getSelectorLoc(0))) { 93 // Calling -zone is meaningless in ARC, change it to nil. 94 Transaction Trans(Pass.TA); 95 Pass.TA.clearDiagnostic(diag::err_unavailable, 96 diag::err_unavailable_message, 97 E->getSelectorLoc(0)); 98 Pass.TA.replace(E->getSourceRange(), getNilString(Pass.Ctx)); 99 } 100 return true; 101 } 102}; 103 104} // anonymous namespace 105 106void trans::checkAPIUses(MigrationPass &pass) { 107 APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 108} 109