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 70 if (selName.empty()) 71 return true; 72 73 Expr *parm = E->getArg(0)->IgnoreParenCasts(); 74 QualType pointee = parm->getType()->getPointeeType(); 75 if (pointee.isNull()) 76 return true; 77 78 if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) { 79 std::string err = "NSInvocation's "; 80 err += selName; 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()); 84 } 85 return true; 86 } 87 88 // -zone. 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->getInstanceReceiver()->getExprLoc())) { 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->getInstanceReceiver()->getExprLoc()); 100 Pass.TA.replace(E->getSourceRange(), getNilString(Pass.Ctx)); 101 } 102 return true; 103 } 104 }; 105 106 } // anonymous namespace 107 108 void trans::checkAPIUses(MigrationPass &pass) { 109 APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 110 } 111