1 //===--- TransAPIUses.cpp - Tranformations 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/Sema/SemaDiagnostic.h" 23 24 using namespace clang; 25 using namespace arcmt; 26 using namespace trans; 27 28 namespace { 29 30 class APIChecker : public RecursiveASTVisitor<APIChecker> { 31 MigrationPass &Pass; 32 33 Selector getReturnValueSel, setReturnValueSel; 34 Selector getArgumentSel, setArgumentSel; 35 36 Selector zoneSel; 37 public: 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 69 if (selName.empty()) 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 std::string err = "NSInvocation's "; 79 err += selName; 80 err += " is not safe to be used with an object with ownership other " 81 "than __unsafe_unretained"; 82 Pass.TA.reportError(err, parm->getLocStart(), parm->getSourceRange()); 83 } 84 return true; 85 } 86 87 // -zone. 88 if (E->isInstanceMessage() && 89 E->getInstanceReceiver() && 90 E->getSelector() == zoneSel && 91 Pass.TA.hasDiagnostic(diag::err_unavailable, 92 diag::err_unavailable_message, 93 E->getInstanceReceiver()->getExprLoc())) { 94 // Calling -zone is meaningless in ARC, change it to nil. 95 Transaction Trans(Pass.TA); 96 Pass.TA.clearDiagnostic(diag::err_unavailable, 97 diag::err_unavailable_message, 98 E->getInstanceReceiver()->getExprLoc()); 99 Pass.TA.replace(E->getSourceRange(), getNilString(Pass.Ctx)); 100 } 101 return true; 102 } 103 }; 104 105 } // anonymous namespace 106 107 void trans::checkAPIUses(MigrationPass &pass) { 108 APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 109 } 110