blob: 40c8a070f813f4a88a2ea64c643f625e2648950e [file] [log] [blame]
Benjamin Kramerd81108f2012-11-14 15:08:31 +00001//===--- TransAPIUses.cpp - Transformations to ARC mode -------------------===//
Argyrios Kyrtzidis73a0d322011-07-18 07:44:45 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// checkAPIUses:
11//
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000012// Emits error/fix with some API uses that are obsolete or not safe in ARC mode:
Argyrios Kyrtzidis73a0d322011-07-18 07:44:45 +000013//
14// - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe
15// with __unsafe_unretained objects.
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000016// - Calling -zone gets replaced with 'nil'.
Argyrios Kyrtzidis73a0d322011-07-18 07:44:45 +000017//
18//===----------------------------------------------------------------------===//
19
20#include "Transforms.h"
21#include "Internals.h"
Benjamin Kramer4ab984e2012-07-04 20:19:54 +000022#include "clang/AST/ASTContext.h"
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000023#include "clang/Sema/SemaDiagnostic.h"
Argyrios Kyrtzidis73a0d322011-07-18 07:44:45 +000024
25using namespace clang;
26using namespace arcmt;
27using namespace trans;
Argyrios Kyrtzidis73a0d322011-07-18 07:44:45 +000028
29namespace {
30
31class APIChecker : public RecursiveASTVisitor<APIChecker> {
32 MigrationPass &Pass;
Argyrios Kyrtzidis91c62bf2011-07-18 07:44:50 +000033
Argyrios Kyrtzidis73a0d322011-07-18 07:44:45 +000034 Selector getReturnValueSel, setReturnValueSel;
35 Selector getArgumentSel, setArgumentSel;
36
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000037 Selector zoneSel;
Argyrios Kyrtzidis73a0d322011-07-18 07:44:45 +000038public:
39 APIChecker(MigrationPass &pass) : Pass(pass) {
40 SelectorTable &sels = Pass.Ctx.Selectors;
41 IdentifierTable &ids = Pass.Ctx.Idents;
42 getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue"));
43 setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue"));
44
45 IdentifierInfo *selIds[2];
46 selIds[0] = &ids.get("getArgument");
47 selIds[1] = &ids.get("atIndex");
48 getArgumentSel = sels.getSelector(2, selIds);
49 selIds[0] = &ids.get("setArgument");
50 setArgumentSel = sels.getSelector(2, selIds);
Argyrios Kyrtzidis91c62bf2011-07-18 07:44:50 +000051
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000052 zoneSel = sels.getNullarySelector(&ids.get("zone"));
Argyrios Kyrtzidis73a0d322011-07-18 07:44:45 +000053 }
54
55 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000056 // NSInvocation.
Argyrios Kyrtzidis73a0d322011-07-18 07:44:45 +000057 if (E->isInstanceMessage() &&
58 E->getReceiverInterface() &&
59 E->getReceiverInterface()->getName() == "NSInvocation") {
60 StringRef selName;
61 if (E->getSelector() == getReturnValueSel)
62 selName = "getReturnValue";
63 else if (E->getSelector() == setReturnValueSel)
64 selName = "setReturnValue";
65 else if (E->getSelector() == getArgumentSel)
66 selName = "getArgument";
67 else if (E->getSelector() == setArgumentSel)
68 selName = "setArgument";
Alp Toker42aa2122014-01-26 05:07:32 +000069 else
Argyrios Kyrtzidis73a0d322011-07-18 07:44:45 +000070 return true;
71
72 Expr *parm = E->getArg(0)->IgnoreParenCasts();
73 QualType pointee = parm->getType()->getPointeeType();
74 if (pointee.isNull())
75 return true;
76
Alp Toker42aa2122014-01-26 05:07:32 +000077 if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone)
78 Pass.TA.report(parm->getLocStart(),
79 diag::err_arcmt_nsinvocation_ownership,
80 parm->getSourceRange())
81 << selName;
82
Argyrios Kyrtzidis73a0d322011-07-18 07:44:45 +000083 return true;
84 }
85
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000086 // -zone.
87 if (E->isInstanceMessage() &&
88 E->getInstanceReceiver() &&
89 E->getSelector() == zoneSel &&
90 Pass.TA.hasDiagnostic(diag::err_unavailable,
91 diag::err_unavailable_message,
Argyrios Kyrtzidisbcf2bdc2013-05-01 00:24:09 +000092 E->getSelectorLoc(0))) {
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000093 // Calling -zone is meaningless in ARC, change it to nil.
94 Transaction Trans(Pass.TA);
95 Pass.TA.clearDiagnostic(diag::err_unavailable,
96 diag::err_unavailable_message,
Argyrios Kyrtzidisbcf2bdc2013-05-01 00:24:09 +000097 E->getSelectorLoc(0));
Richard Smith20e883e2015-04-29 23:20:19 +000098 Pass.TA.replace(E->getSourceRange(), getNilString(Pass));
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000099 }
Argyrios Kyrtzidis73a0d322011-07-18 07:44:45 +0000100 return true;
101 }
102};
103
104} // anonymous namespace
105
106void trans::checkAPIUses(MigrationPass &pass) {
107 APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
108}