• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/fix with some API uses that are obsolete or 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 // - Calling -zone gets replaced with 'nil'.
17 //
18 //===----------------------------------------------------------------------===//
19 
20 #include "Transforms.h"
21 #include "Internals.h"
22 #include "clang/Sema/SemaDiagnostic.h"
23 
24 using namespace clang;
25 using namespace arcmt;
26 using namespace trans;
27 
28 namespace {
29 
30 class APIChecker : public RecursiveASTVisitor<APIChecker> {
31   MigrationPass &Pass;
32 
33   Selector getReturnValueSel, setReturnValueSel;
34   Selector getArgumentSel, setArgumentSel;
35 
36   Selector zoneSel;
37 public:
APIChecker(MigrationPass & pass)38   APIChecker(MigrationPass &pass) : Pass(pass) {
39     SelectorTable &sels = Pass.Ctx.Selectors;
40     IdentifierTable &ids = Pass.Ctx.Idents;
41     getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue"));
42     setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue"));
43 
44     IdentifierInfo *selIds[2];
45     selIds[0] = &ids.get("getArgument");
46     selIds[1] = &ids.get("atIndex");
47     getArgumentSel = sels.getSelector(2, selIds);
48     selIds[0] = &ids.get("setArgument");
49     setArgumentSel = sels.getSelector(2, selIds);
50 
51     zoneSel = sels.getNullarySelector(&ids.get("zone"));
52   }
53 
VisitObjCMessageExpr(ObjCMessageExpr * E)54   bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
55     // NSInvocation.
56     if (E->isInstanceMessage() &&
57         E->getReceiverInterface() &&
58         E->getReceiverInterface()->getName() == "NSInvocation") {
59       StringRef selName;
60       if (E->getSelector() == getReturnValueSel)
61         selName = "getReturnValue";
62       else if (E->getSelector() == setReturnValueSel)
63         selName = "setReturnValue";
64       else if (E->getSelector() == getArgumentSel)
65         selName = "getArgument";
66       else if (E->getSelector() == setArgumentSel)
67         selName = "setArgument";
68 
69       if (selName.empty())
70         return true;
71 
72       Expr *parm = E->getArg(0)->IgnoreParenCasts();
73       QualType pointee = parm->getType()->getPointeeType();
74       if (pointee.isNull())
75         return true;
76 
77       if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) {
78         std::string err = "NSInvocation's ";
79         err += selName;
80         err += " is not safe to be used with an object with ownership other "
81             "than __unsafe_unretained";
82         Pass.TA.reportError(err, parm->getLocStart(), parm->getSourceRange());
83       }
84       return true;
85     }
86 
87     // -zone.
88     if (E->isInstanceMessage() &&
89         E->getInstanceReceiver() &&
90         E->getSelector() == zoneSel &&
91         Pass.TA.hasDiagnostic(diag::err_unavailable,
92                               diag::err_unavailable_message,
93                               E->getInstanceReceiver()->getExprLoc())) {
94       // Calling -zone is meaningless in ARC, change it to nil.
95       Transaction Trans(Pass.TA);
96       Pass.TA.clearDiagnostic(diag::err_unavailable,
97                               diag::err_unavailable_message,
98                               E->getInstanceReceiver()->getExprLoc());
99       Pass.TA.replace(E->getSourceRange(), getNilString(Pass.Ctx));
100     }
101     return true;
102   }
103 };
104 
105 } // anonymous namespace
106 
checkAPIUses(MigrationPass & pass)107 void trans::checkAPIUses(MigrationPass &pass) {
108   APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
109 }
110