clang API Documentation
00001 //===--- TransAPIUses.cpp - Tranformations to ARC mode --------------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // checkAPIUses: 00011 // 00012 // Emits error/fix with some API uses that are obsolete or not safe in ARC mode: 00013 // 00014 // - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe 00015 // with __unsafe_unretained objects. 00016 // - Calling -zone gets replaced with 'nil'. 00017 // 00018 //===----------------------------------------------------------------------===// 00019 00020 #include "Transforms.h" 00021 #include "Internals.h" 00022 #include "clang/Sema/SemaDiagnostic.h" 00023 00024 using namespace clang; 00025 using namespace arcmt; 00026 using namespace trans; 00027 00028 namespace { 00029 00030 class APIChecker : public RecursiveASTVisitor<APIChecker> { 00031 MigrationPass &Pass; 00032 00033 Selector getReturnValueSel, setReturnValueSel; 00034 Selector getArgumentSel, setArgumentSel; 00035 00036 Selector zoneSel; 00037 public: 00038 APIChecker(MigrationPass &pass) : Pass(pass) { 00039 SelectorTable &sels = Pass.Ctx.Selectors; 00040 IdentifierTable &ids = Pass.Ctx.Idents; 00041 getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue")); 00042 setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue")); 00043 00044 IdentifierInfo *selIds[2]; 00045 selIds[0] = &ids.get("getArgument"); 00046 selIds[1] = &ids.get("atIndex"); 00047 getArgumentSel = sels.getSelector(2, selIds); 00048 selIds[0] = &ids.get("setArgument"); 00049 setArgumentSel = sels.getSelector(2, selIds); 00050 00051 zoneSel = sels.getNullarySelector(&ids.get("zone")); 00052 } 00053 00054 bool VisitObjCMessageExpr(ObjCMessageExpr *E) { 00055 // NSInvocation. 00056 if (E->isInstanceMessage() && 00057 E->getReceiverInterface() && 00058 E->getReceiverInterface()->getName() == "NSInvocation") { 00059 StringRef selName; 00060 if (E->getSelector() == getReturnValueSel) 00061 selName = "getReturnValue"; 00062 else if (E->getSelector() == setReturnValueSel) 00063 selName = "setReturnValue"; 00064 else if (E->getSelector() == getArgumentSel) 00065 selName = "getArgument"; 00066 else if (E->getSelector() == setArgumentSel) 00067 selName = "setArgument"; 00068 00069 if (selName.empty()) 00070 return true; 00071 00072 Expr *parm = E->getArg(0)->IgnoreParenCasts(); 00073 QualType pointee = parm->getType()->getPointeeType(); 00074 if (pointee.isNull()) 00075 return true; 00076 00077 if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) { 00078 std::string err = "NSInvocation's "; 00079 err += selName; 00080 err += " is not safe to be used with an object with ownership other " 00081 "than __unsafe_unretained"; 00082 Pass.TA.reportError(err, parm->getLocStart(), parm->getSourceRange()); 00083 } 00084 return true; 00085 } 00086 00087 // -zone. 00088 if (E->isInstanceMessage() && 00089 E->getInstanceReceiver() && 00090 E->getSelector() == zoneSel && 00091 Pass.TA.hasDiagnostic(diag::err_unavailable, 00092 diag::err_unavailable_message, 00093 E->getInstanceReceiver()->getExprLoc())) { 00094 // Calling -zone is meaningless in ARC, change it to nil. 00095 Transaction Trans(Pass.TA); 00096 Pass.TA.clearDiagnostic(diag::err_unavailable, 00097 diag::err_unavailable_message, 00098 E->getInstanceReceiver()->getExprLoc()); 00099 Pass.TA.replace(E->getSourceRange(), getNilString(Pass.Ctx)); 00100 } 00101 return true; 00102 } 00103 }; 00104 00105 } // anonymous namespace 00106 00107 void trans::checkAPIUses(MigrationPass &pass) { 00108 APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 00109 }