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