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