xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/ARCMigrate/TransAPIUses.cpp (revision 7330f729ccf0bd976a06f95fad452fe774fc7fd1)
1*7330f729Sjoerg //===--- TransAPIUses.cpp - Transformations to ARC mode -------------------===//
2*7330f729Sjoerg //
3*7330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*7330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
5*7330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*7330f729Sjoerg //
7*7330f729Sjoerg //===----------------------------------------------------------------------===//
8*7330f729Sjoerg //
9*7330f729Sjoerg // checkAPIUses:
10*7330f729Sjoerg //
11*7330f729Sjoerg // Emits error/fix with some API uses that are obsolete or not safe in ARC mode:
12*7330f729Sjoerg //
13*7330f729Sjoerg // - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe
14*7330f729Sjoerg //   with __unsafe_unretained objects.
15*7330f729Sjoerg // - Calling -zone gets replaced with 'nil'.
16*7330f729Sjoerg //
17*7330f729Sjoerg //===----------------------------------------------------------------------===//
18*7330f729Sjoerg 
19*7330f729Sjoerg #include "Transforms.h"
20*7330f729Sjoerg #include "Internals.h"
21*7330f729Sjoerg #include "clang/AST/ASTContext.h"
22*7330f729Sjoerg #include "clang/Sema/SemaDiagnostic.h"
23*7330f729Sjoerg 
24*7330f729Sjoerg using namespace clang;
25*7330f729Sjoerg using namespace arcmt;
26*7330f729Sjoerg using namespace trans;
27*7330f729Sjoerg 
28*7330f729Sjoerg namespace {
29*7330f729Sjoerg 
30*7330f729Sjoerg class APIChecker : public RecursiveASTVisitor<APIChecker> {
31*7330f729Sjoerg   MigrationPass &Pass;
32*7330f729Sjoerg 
33*7330f729Sjoerg   Selector getReturnValueSel, setReturnValueSel;
34*7330f729Sjoerg   Selector getArgumentSel, setArgumentSel;
35*7330f729Sjoerg 
36*7330f729Sjoerg   Selector zoneSel;
37*7330f729Sjoerg public:
APIChecker(MigrationPass & pass)38*7330f729Sjoerg   APIChecker(MigrationPass &pass) : Pass(pass) {
39*7330f729Sjoerg     SelectorTable &sels = Pass.Ctx.Selectors;
40*7330f729Sjoerg     IdentifierTable &ids = Pass.Ctx.Idents;
41*7330f729Sjoerg     getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue"));
42*7330f729Sjoerg     setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue"));
43*7330f729Sjoerg 
44*7330f729Sjoerg     IdentifierInfo *selIds[2];
45*7330f729Sjoerg     selIds[0] = &ids.get("getArgument");
46*7330f729Sjoerg     selIds[1] = &ids.get("atIndex");
47*7330f729Sjoerg     getArgumentSel = sels.getSelector(2, selIds);
48*7330f729Sjoerg     selIds[0] = &ids.get("setArgument");
49*7330f729Sjoerg     setArgumentSel = sels.getSelector(2, selIds);
50*7330f729Sjoerg 
51*7330f729Sjoerg     zoneSel = sels.getNullarySelector(&ids.get("zone"));
52*7330f729Sjoerg   }
53*7330f729Sjoerg 
VisitObjCMessageExpr(ObjCMessageExpr * E)54*7330f729Sjoerg   bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
55*7330f729Sjoerg     // NSInvocation.
56*7330f729Sjoerg     if (E->isInstanceMessage() &&
57*7330f729Sjoerg         E->getReceiverInterface() &&
58*7330f729Sjoerg         E->getReceiverInterface()->getName() == "NSInvocation") {
59*7330f729Sjoerg       StringRef selName;
60*7330f729Sjoerg       if (E->getSelector() == getReturnValueSel)
61*7330f729Sjoerg         selName = "getReturnValue";
62*7330f729Sjoerg       else if (E->getSelector() == setReturnValueSel)
63*7330f729Sjoerg         selName = "setReturnValue";
64*7330f729Sjoerg       else if (E->getSelector() == getArgumentSel)
65*7330f729Sjoerg         selName = "getArgument";
66*7330f729Sjoerg       else if (E->getSelector() == setArgumentSel)
67*7330f729Sjoerg         selName = "setArgument";
68*7330f729Sjoerg       else
69*7330f729Sjoerg         return true;
70*7330f729Sjoerg 
71*7330f729Sjoerg       Expr *parm = E->getArg(0)->IgnoreParenCasts();
72*7330f729Sjoerg       QualType pointee = parm->getType()->getPointeeType();
73*7330f729Sjoerg       if (pointee.isNull())
74*7330f729Sjoerg         return true;
75*7330f729Sjoerg 
76*7330f729Sjoerg       if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone)
77*7330f729Sjoerg         Pass.TA.report(parm->getBeginLoc(),
78*7330f729Sjoerg                        diag::err_arcmt_nsinvocation_ownership,
79*7330f729Sjoerg                        parm->getSourceRange())
80*7330f729Sjoerg             << selName;
81*7330f729Sjoerg 
82*7330f729Sjoerg       return true;
83*7330f729Sjoerg     }
84*7330f729Sjoerg 
85*7330f729Sjoerg     // -zone.
86*7330f729Sjoerg     if (E->isInstanceMessage() &&
87*7330f729Sjoerg         E->getInstanceReceiver() &&
88*7330f729Sjoerg         E->getSelector() == zoneSel &&
89*7330f729Sjoerg         Pass.TA.hasDiagnostic(diag::err_unavailable,
90*7330f729Sjoerg                               diag::err_unavailable_message,
91*7330f729Sjoerg                               E->getSelectorLoc(0))) {
92*7330f729Sjoerg       // Calling -zone is meaningless in ARC, change it to nil.
93*7330f729Sjoerg       Transaction Trans(Pass.TA);
94*7330f729Sjoerg       Pass.TA.clearDiagnostic(diag::err_unavailable,
95*7330f729Sjoerg                               diag::err_unavailable_message,
96*7330f729Sjoerg                               E->getSelectorLoc(0));
97*7330f729Sjoerg       Pass.TA.replace(E->getSourceRange(), getNilString(Pass));
98*7330f729Sjoerg     }
99*7330f729Sjoerg     return true;
100*7330f729Sjoerg   }
101*7330f729Sjoerg };
102*7330f729Sjoerg 
103*7330f729Sjoerg } // anonymous namespace
104*7330f729Sjoerg 
checkAPIUses(MigrationPass & pass)105*7330f729Sjoerg void trans::checkAPIUses(MigrationPass &pass) {
106*7330f729Sjoerg   APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
107*7330f729Sjoerg }
108