xref: /freebsd/contrib/llvm-project/clang/lib/ARCMigrate/TransAPIUses.cpp (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
1 //===--- TransAPIUses.cpp - Transformations to ARC mode -------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // checkAPIUses:
10 //
11 // Emits error/fix with some API uses that are obsolete or not safe in ARC mode:
12 //
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'.
16 //
17 //===----------------------------------------------------------------------===//
18 
19 #include "Transforms.h"
20 #include "Internals.h"
21 #include "clang/AST/ASTContext.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:
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 
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       else
69         return true;
70 
71       Expr *parm = E->getArg(0)->IgnoreParenCasts();
72       QualType pointee = parm->getType()->getPointeeType();
73       if (pointee.isNull())
74         return true;
75 
76       if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone)
77         Pass.TA.report(parm->getBeginLoc(),
78                        diag::err_arcmt_nsinvocation_ownership,
79                        parm->getSourceRange())
80             << selName;
81 
82       return true;
83     }
84 
85     // -zone.
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));
98     }
99     return true;
100   }
101 };
102 
103 } // anonymous namespace
104 
105 void trans::checkAPIUses(MigrationPass &pass) {
106   APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
107 }
108