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 25 using namespace clang; 26 using namespace arcmt; 27 using namespace trans; 28 29 namespace { 30 31 class APIChecker : public RecursiveASTVisitor<APIChecker> { 32 MigrationPass &Pass; 33 34 Selector getReturnValueSel, setReturnValueSel; 35 Selector getArgumentSel, setArgumentSel; 36 37 Selector zoneSel; 38 public: 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)); 99 } 100 return true; 101 } 102 }; 103 104 } // anonymous namespace 105 106 void trans::checkAPIUses(MigrationPass &pass) { 107 APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 108 } 109