clang  mainline
TransAPIUses.cpp
Go to the documentation of this file.
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));
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 }