1 //===--- TransAPIUses.cpp - Transformations to ARC mode -------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
11 // Emits error/fix with some API uses that are obsolete or not safe in ARC mode:
13 // - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe
14 // with __unsafe_unretained objects.
15 // - Calling -zone gets replaced with 'nil'.
17 //===----------------------------------------------------------------------===//
19 #include "Transforms.h"
20 #include "Internals.h"
21 #include "clang/AST/ASTContext.h"
22 #include "clang/Sema/SemaDiagnostic.h"
24 using namespace clang
;
25 using namespace arcmt
;
26 using namespace trans
;
30 class APIChecker
: public RecursiveASTVisitor
<APIChecker
> {
33 Selector getReturnValueSel
, setReturnValueSel
;
34 Selector getArgumentSel
, setArgumentSel
;
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"));
44 const 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
);
51 zoneSel
= sels
.getNullarySelector(&ids
.get("zone"));
54 bool VisitObjCMessageExpr(ObjCMessageExpr
*E
) {
56 if (E
->isInstanceMessage() &&
57 E
->getReceiverInterface() &&
58 E
->getReceiverInterface()->getName() == "NSInvocation") {
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";
71 Expr
*parm
= E
->getArg(0)->IgnoreParenCasts();
72 QualType pointee
= parm
->getType()->getPointeeType();
76 if (pointee
.getObjCLifetime() > Qualifiers::OCL_ExplicitNone
)
77 Pass
.TA
.report(parm
->getBeginLoc(),
78 diag::err_arcmt_nsinvocation_ownership
,
79 parm
->getSourceRange())
86 if (E
->isInstanceMessage() &&
87 E
->getInstanceReceiver() &&
88 E
->getSelector() == zoneSel
&&
89 Pass
.TA
.hasDiagnostic(diag::err_unavailable
,
90 diag::err_unavailable_message
,
91 E
->getSelectorLoc(0))) {
92 // Calling -zone is meaningless in ARC, change it to nil.
93 Transaction
Trans(Pass
.TA
);
94 Pass
.TA
.clearDiagnostic(diag::err_unavailable
,
95 diag::err_unavailable_message
,
96 E
->getSelectorLoc(0));
97 Pass
.TA
.replace(E
->getSourceRange(), getNilString(Pass
));
103 } // anonymous namespace
105 void trans::checkAPIUses(MigrationPass
&pass
) {
106 APIChecker(pass
).TraverseDecl(pass
.Ctx
.getTranslationUnitDecl());