TransAPIUses.cpp revision accaf19bc1129c0273ec50dba52318e60bc29103
1accaf19bc1129c0273ec50dba52318e60bc29103Benjamin Kramer//===--- TransAPIUses.cpp - Transformations to ARC mode -------------------===// 2fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis// 3fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis// The LLVM Compiler Infrastructure 4fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis// 5fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis// This file is distributed under the University of Illinois Open Source 6fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis// License. See LICENSE.TXT for details. 7fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis// 8fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis//===----------------------------------------------------------------------===// 9fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis// 10fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis// checkAPIUses: 11fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis// 1218fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis// Emits error/fix with some API uses that are obsolete or not safe in ARC mode: 13fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis// 14fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis// - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe 15fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis// with __unsafe_unretained objects. 1618fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis// - Calling -zone gets replaced with 'nil'. 17fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis// 18fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis//===----------------------------------------------------------------------===// 19fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis 20fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis#include "Transforms.h" 21fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis#include "Internals.h" 22471c8b49982d1132f30b0b0da27fef94fd6e4f67Benjamin Kramer#include "clang/AST/ASTContext.h" 2318fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis#include "clang/Sema/SemaDiagnostic.h" 24fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis 25fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidisusing namespace clang; 26fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidisusing namespace arcmt; 27fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidisusing namespace trans; 28fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis 29fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidisnamespace { 30fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis 31fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidisclass APIChecker : public RecursiveASTVisitor<APIChecker> { 32fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis MigrationPass &Pass; 3305fdf9bc3f5089db291484e4ad9880aa432db9f4Argyrios Kyrtzidis 34fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis Selector getReturnValueSel, setReturnValueSel; 35fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis Selector getArgumentSel, setArgumentSel; 36fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis 3718fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis Selector zoneSel; 38fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidispublic: 39fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis APIChecker(MigrationPass &pass) : Pass(pass) { 40fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis SelectorTable &sels = Pass.Ctx.Selectors; 41fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis IdentifierTable &ids = Pass.Ctx.Idents; 42fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue")); 43fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue")); 44fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis 45fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis IdentifierInfo *selIds[2]; 46fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis selIds[0] = &ids.get("getArgument"); 47fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis selIds[1] = &ids.get("atIndex"); 48fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis getArgumentSel = sels.getSelector(2, selIds); 49fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis selIds[0] = &ids.get("setArgument"); 50fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis setArgumentSel = sels.getSelector(2, selIds); 5105fdf9bc3f5089db291484e4ad9880aa432db9f4Argyrios Kyrtzidis 5218fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis zoneSel = sels.getNullarySelector(&ids.get("zone")); 53fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis } 54fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis 55fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis bool VisitObjCMessageExpr(ObjCMessageExpr *E) { 5618fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis // NSInvocation. 57fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis if (E->isInstanceMessage() && 58fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis E->getReceiverInterface() && 59fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis E->getReceiverInterface()->getName() == "NSInvocation") { 60fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis StringRef selName; 61fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis if (E->getSelector() == getReturnValueSel) 62fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis selName = "getReturnValue"; 63fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis else if (E->getSelector() == setReturnValueSel) 64fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis selName = "setReturnValue"; 65fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis else if (E->getSelector() == getArgumentSel) 66fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis selName = "getArgument"; 67fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis else if (E->getSelector() == setArgumentSel) 68fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis selName = "setArgument"; 69fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis 70fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis if (selName.empty()) 71fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis return true; 72fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis 73fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis Expr *parm = E->getArg(0)->IgnoreParenCasts(); 74fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis QualType pointee = parm->getType()->getPointeeType(); 75fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis if (pointee.isNull()) 76fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis return true; 77fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis 78fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) { 79fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis std::string err = "NSInvocation's "; 80fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis err += selName; 81fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis err += " is not safe to be used with an object with ownership other " 82fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis "than __unsafe_unretained"; 83fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis Pass.TA.reportError(err, parm->getLocStart(), parm->getSourceRange()); 84fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis } 85fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis return true; 86fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis } 87fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis 8818fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis // -zone. 8918fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis if (E->isInstanceMessage() && 9018fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis E->getInstanceReceiver() && 9118fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis E->getSelector() == zoneSel && 9218fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis Pass.TA.hasDiagnostic(diag::err_unavailable, 9318fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis diag::err_unavailable_message, 9418fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis E->getInstanceReceiver()->getExprLoc())) { 9518fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis // Calling -zone is meaningless in ARC, change it to nil. 9618fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis Transaction Trans(Pass.TA); 9718fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis Pass.TA.clearDiagnostic(diag::err_unavailable, 9818fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis diag::err_unavailable_message, 9918fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis E->getInstanceReceiver()->getExprLoc()); 10018fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis Pass.TA.replace(E->getSourceRange(), getNilString(Pass.Ctx)); 10118fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis } 102fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis return true; 103fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis } 104fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis}; 105fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis 106fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis} // anonymous namespace 107fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis 108fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidisvoid trans::checkAPIUses(MigrationPass &pass) { 109fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 110fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis} 111