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 with some API uses that are 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 // - When a NSData's 'bytes' family of methods are used on a local var, 17 // add __attribute__((objc_precise_lifetime)) to make it safer. 18 // 19 //===----------------------------------------------------------------------===// 20 21 #include "Transforms.h" 22 #include "Internals.h" 23 24 using namespace clang; 25 using namespace arcmt; 26 using namespace trans; 27 using llvm::StringRef; 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 bytesSel, getBytesSel, getBytesLengthSel, getBytesRangeSel; 38 39 llvm::DenseSet<VarDecl *> ChangedNSDataVars; 40 public: 41 APIChecker(MigrationPass &pass) : Pass(pass) { 42 SelectorTable &sels = Pass.Ctx.Selectors; 43 IdentifierTable &ids = Pass.Ctx.Idents; 44 getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue")); 45 setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue")); 46 47 IdentifierInfo *selIds[2]; 48 selIds[0] = &ids.get("getArgument"); 49 selIds[1] = &ids.get("atIndex"); 50 getArgumentSel = sels.getSelector(2, selIds); 51 selIds[0] = &ids.get("setArgument"); 52 setArgumentSel = sels.getSelector(2, selIds); 53 54 bytesSel = sels.getNullarySelector(&ids.get("bytes")); 55 getBytesSel = sels.getUnarySelector(&ids.get("getBytes")); 56 selIds[0] = &ids.get("getBytes"); 57 selIds[1] = &ids.get("length"); 58 getBytesLengthSel = sels.getSelector(2, selIds); 59 selIds[1] = &ids.get("range"); 60 getBytesRangeSel = sels.getSelector(2, selIds); 61 } 62 63 bool VisitObjCMessageExpr(ObjCMessageExpr *E) { 64 if (E->isInstanceMessage() && 65 E->getReceiverInterface() && 66 E->getReceiverInterface()->getName() == "NSInvocation") { 67 StringRef selName; 68 if (E->getSelector() == getReturnValueSel) 69 selName = "getReturnValue"; 70 else if (E->getSelector() == setReturnValueSel) 71 selName = "setReturnValue"; 72 else if (E->getSelector() == getArgumentSel) 73 selName = "getArgument"; 74 else if (E->getSelector() == setArgumentSel) 75 selName = "setArgument"; 76 77 if (selName.empty()) 78 return true; 79 80 Expr *parm = E->getArg(0)->IgnoreParenCasts(); 81 QualType pointee = parm->getType()->getPointeeType(); 82 if (pointee.isNull()) 83 return true; 84 85 if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) { 86 std::string err = "NSInvocation's "; 87 err += selName; 88 err += " is not safe to be used with an object with ownership other " 89 "than __unsafe_unretained"; 90 Pass.TA.reportError(err, parm->getLocStart(), parm->getSourceRange()); 91 } 92 return true; 93 } 94 95 if (E->isInstanceMessage() && 96 E->getReceiverInterface() && 97 E->getReceiverInterface()->getName() == "NSData" && 98 E->getInstanceReceiver() && 99 (E->getSelector() == bytesSel || 100 E->getSelector() == getBytesSel || 101 E->getSelector() == getBytesLengthSel || 102 E->getSelector() == getBytesRangeSel)) { 103 Expr *rec = E->getInstanceReceiver(); 104 rec = rec->IgnoreParenCasts(); 105 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(rec)) 106 if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) 107 if (VD->hasLocalStorage() && !ChangedNSDataVars.count(VD)) { 108 Transaction Trans(Pass.TA); 109 Pass.TA.insertAfterToken(VD->getLocation(), 110 " __attribute__((objc_precise_lifetime))"); 111 ChangedNSDataVars.insert(VD); 112 } 113 } 114 115 return true; 116 } 117 }; 118 119 } // anonymous namespace 120 121 void trans::checkAPIUses(MigrationPass &pass) { 122 APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 123 } 124