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