blob: aaa82d8dfb7a2a59e2e38efe7978aac439bbbb45 [file] [log] [blame]
Argyrios Kyrtzidisfd103982011-07-18 07:44:45 +00001//===--- TransAPIUses.cpp - Tranformations to ARC mode --------------------===//
2//
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 Kyrtzidis18fd0c62011-07-27 05:28:18 +000012// Emits error/fix with some API uses that are obsolete or not safe in ARC mode:
Argyrios Kyrtzidisfd103982011-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 Kyrtzidis18fd0c62011-07-27 05:28:18 +000016// - Calling -zone gets replaced with 'nil'.
Argyrios Kyrtzidisfd103982011-07-18 07:44:45 +000017//
18//===----------------------------------------------------------------------===//
19
20#include "Transforms.h"
21#include "Internals.h"
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +000022#include "clang/Sema/SemaDiagnostic.h"
Argyrios Kyrtzidisfd103982011-07-18 07:44:45 +000023
24using namespace clang;
25using namespace arcmt;
26using namespace trans;
Argyrios Kyrtzidisfd103982011-07-18 07:44:45 +000027
28namespace {
29
30class APIChecker : public RecursiveASTVisitor<APIChecker> {
31 MigrationPass &Pass;
Argyrios Kyrtzidis05fdf9b2011-07-18 07:44:50 +000032
Argyrios Kyrtzidisfd103982011-07-18 07:44:45 +000033 Selector getReturnValueSel, setReturnValueSel;
34 Selector getArgumentSel, setArgumentSel;
35
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +000036 Selector zoneSel;
Argyrios Kyrtzidisfd103982011-07-18 07:44:45 +000037public:
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);
Argyrios Kyrtzidis05fdf9b2011-07-18 07:44:50 +000050
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +000051 zoneSel = sels.getNullarySelector(&ids.get("zone"));
Argyrios Kyrtzidisfd103982011-07-18 07:44:45 +000052 }
53
54 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +000055 // NSInvocation.
Argyrios Kyrtzidisfd103982011-07-18 07:44:45 +000056 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
69 if (selName.empty())
70 return true;
71
72 Expr *parm = E->getArg(0)->IgnoreParenCasts();
73 QualType pointee = parm->getType()->getPointeeType();
74 if (pointee.isNull())
75 return true;
76
77 if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) {
78 std::string err = "NSInvocation's ";
79 err += selName;
80 err += " is not safe to be used with an object with ownership other "
81 "than __unsafe_unretained";
82 Pass.TA.reportError(err, parm->getLocStart(), parm->getSourceRange());
83 }
84 return true;
85 }
86
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +000087 // -zone.
88 if (E->isInstanceMessage() &&
89 E->getInstanceReceiver() &&
90 E->getSelector() == zoneSel &&
91 Pass.TA.hasDiagnostic(diag::err_unavailable,
92 diag::err_unavailable_message,
93 E->getInstanceReceiver()->getExprLoc())) {
94 // Calling -zone is meaningless in ARC, change it to nil.
95 Transaction Trans(Pass.TA);
96 Pass.TA.clearDiagnostic(diag::err_unavailable,
97 diag::err_unavailable_message,
98 E->getInstanceReceiver()->getExprLoc());
99 Pass.TA.replace(E->getSourceRange(), getNilString(Pass.Ctx));
100 }
Argyrios Kyrtzidisfd103982011-07-18 07:44:45 +0000101 return true;
102 }
103};
104
105} // anonymous namespace
106
107void trans::checkAPIUses(MigrationPass &pass) {
108 APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
109}