clang API Documentation

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