Home | History | Annotate | Download | only in ARCMigrate
      1 //===--- TransAPIUses.cpp - Tranformations to ARC mode --------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // checkAPIUses:
     11 //
     12 // Emits error with some API uses that are not safe in ARC mode:
     13 //
     14 // - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe
     15 //   with __unsafe_unretained objects.
     16 // - When a NSData's 'bytes' family of methods are used on a local var,
     17 //   add __attribute__((objc_precise_lifetime)) to make it safer.
     18 //
     19 //===----------------------------------------------------------------------===//
     20 
     21 #include "Transforms.h"
     22 #include "Internals.h"
     23 
     24 using namespace clang;
     25 using namespace arcmt;
     26 using namespace trans;
     27 using llvm::StringRef;
     28 
     29 namespace {
     30 
     31 class APIChecker : public RecursiveASTVisitor<APIChecker> {
     32   MigrationPass &Pass;
     33 
     34   Selector getReturnValueSel, setReturnValueSel;
     35   Selector getArgumentSel, setArgumentSel;
     36 
     37   Selector bytesSel, getBytesSel, getBytesLengthSel, getBytesRangeSel;
     38 
     39   llvm::DenseSet<VarDecl *> ChangedNSDataVars;
     40 public:
     41   APIChecker(MigrationPass &pass) : Pass(pass) {
     42     SelectorTable &sels = Pass.Ctx.Selectors;
     43     IdentifierTable &ids = Pass.Ctx.Idents;
     44     getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue"));
     45     setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue"));
     46 
     47     IdentifierInfo *selIds[2];
     48     selIds[0] = &ids.get("getArgument");
     49     selIds[1] = &ids.get("atIndex");
     50     getArgumentSel = sels.getSelector(2, selIds);
     51     selIds[0] = &ids.get("setArgument");
     52     setArgumentSel = sels.getSelector(2, selIds);
     53 
     54     bytesSel = sels.getNullarySelector(&ids.get("bytes"));
     55     getBytesSel = sels.getUnarySelector(&ids.get("getBytes"));
     56     selIds[0] = &ids.get("getBytes");
     57     selIds[1] = &ids.get("length");
     58     getBytesLengthSel = sels.getSelector(2, selIds);
     59     selIds[1] = &ids.get("range");
     60     getBytesRangeSel = sels.getSelector(2, selIds);
     61   }
     62 
     63   bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
     64     if (E->isInstanceMessage() &&
     65         E->getReceiverInterface() &&
     66         E->getReceiverInterface()->getName() == "NSInvocation") {
     67       StringRef selName;
     68       if (E->getSelector() == getReturnValueSel)
     69         selName = "getReturnValue";
     70       else if (E->getSelector() == setReturnValueSel)
     71         selName = "setReturnValue";
     72       else if (E->getSelector() == getArgumentSel)
     73         selName = "getArgument";
     74       else if (E->getSelector() == setArgumentSel)
     75         selName = "setArgument";
     76 
     77       if (selName.empty())
     78         return true;
     79 
     80       Expr *parm = E->getArg(0)->IgnoreParenCasts();
     81       QualType pointee = parm->getType()->getPointeeType();
     82       if (pointee.isNull())
     83         return true;
     84 
     85       if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) {
     86         std::string err = "NSInvocation's ";
     87         err += selName;
     88         err += " is not safe to be used with an object with ownership other "
     89             "than __unsafe_unretained";
     90         Pass.TA.reportError(err, parm->getLocStart(), parm->getSourceRange());
     91       }
     92       return true;
     93     }
     94 
     95     if (E->isInstanceMessage() &&
     96         E->getReceiverInterface() &&
     97         E->getReceiverInterface()->getName() == "NSData" &&
     98         E->getInstanceReceiver() &&
     99         (E->getSelector() == bytesSel ||
    100          E->getSelector() == getBytesSel ||
    101          E->getSelector() == getBytesLengthSel ||
    102          E->getSelector() == getBytesRangeSel)) {
    103       Expr *rec = E->getInstanceReceiver();
    104       rec = rec->IgnoreParenCasts();
    105       if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(rec))
    106         if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
    107           if (VD->hasLocalStorage() && !ChangedNSDataVars.count(VD)) {
    108             Transaction Trans(Pass.TA);
    109             Pass.TA.insertAfterToken(VD->getLocation(),
    110                                      " __attribute__((objc_precise_lifetime))");
    111             ChangedNSDataVars.insert(VD);
    112           }
    113     }
    114 
    115     return true;
    116   }
    117 };
    118 
    119 } // anonymous namespace
    120 
    121 void trans::checkAPIUses(MigrationPass &pass) {
    122   APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
    123 }
    124