clang API Documentation
00001 //===--- TransAPIUses.cpp - Transformations 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/AST/ASTContext.h" 00023 #include "clang/Sema/SemaDiagnostic.h" 00024 00025 using namespace clang; 00026 using namespace arcmt; 00027 using namespace trans; 00028 00029 namespace { 00030 00031 class APIChecker : public RecursiveASTVisitor<APIChecker> { 00032 MigrationPass &Pass; 00033 00034 Selector getReturnValueSel, setReturnValueSel; 00035 Selector getArgumentSel, setArgumentSel; 00036 00037 Selector zoneSel; 00038 public: 00039 APIChecker(MigrationPass &pass) : Pass(pass) { 00040 SelectorTable &sels = Pass.Ctx.Selectors; 00041 IdentifierTable &ids = Pass.Ctx.Idents; 00042 getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue")); 00043 setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue")); 00044 00045 IdentifierInfo *selIds[2]; 00046 selIds[0] = &ids.get("getArgument"); 00047 selIds[1] = &ids.get("atIndex"); 00048 getArgumentSel = sels.getSelector(2, selIds); 00049 selIds[0] = &ids.get("setArgument"); 00050 setArgumentSel = sels.getSelector(2, selIds); 00051 00052 zoneSel = sels.getNullarySelector(&ids.get("zone")); 00053 } 00054 00055 bool VisitObjCMessageExpr(ObjCMessageExpr *E) { 00056 // NSInvocation. 00057 if (E->isInstanceMessage() && 00058 E->getReceiverInterface() && 00059 E->getReceiverInterface()->getName() == "NSInvocation") { 00060 StringRef selName; 00061 if (E->getSelector() == getReturnValueSel) 00062 selName = "getReturnValue"; 00063 else if (E->getSelector() == setReturnValueSel) 00064 selName = "setReturnValue"; 00065 else if (E->getSelector() == getArgumentSel) 00066 selName = "getArgument"; 00067 else if (E->getSelector() == setArgumentSel) 00068 selName = "setArgument"; 00069 else 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 Pass.TA.report(parm->getLocStart(), 00079 diag::err_arcmt_nsinvocation_ownership, 00080 parm->getSourceRange()) 00081 << selName; 00082 00083 return true; 00084 } 00085 00086 // -zone. 00087 if (E->isInstanceMessage() && 00088 E->getInstanceReceiver() && 00089 E->getSelector() == zoneSel && 00090 Pass.TA.hasDiagnostic(diag::err_unavailable, 00091 diag::err_unavailable_message, 00092 E->getSelectorLoc(0))) { 00093 // Calling -zone is meaningless in ARC, change it to nil. 00094 Transaction Trans(Pass.TA); 00095 Pass.TA.clearDiagnostic(diag::err_unavailable, 00096 diag::err_unavailable_message, 00097 E->getSelectorLoc(0)); 00098 Pass.TA.replace(E->getSourceRange(), getNilString(Pass.Ctx)); 00099 } 00100 return true; 00101 } 00102 }; 00103 00104 } // anonymous namespace 00105 00106 void trans::checkAPIUses(MigrationPass &pass) { 00107 APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 00108 }