blob: 58fd3d07d0a27cb2b2632c0ad2917bc2f01dd6d4 [file] [log] [blame]
Argyrios Kyrtzidis73a0d322011-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//
12// Emits error with some API uses that are not safe in ARC mode:
13//
14// - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe
15// with __unsafe_unretained objects.
16//
17//===----------------------------------------------------------------------===//
18
19#include "Transforms.h"
20#include "Internals.h"
21
22using namespace clang;
23using namespace arcmt;
24using namespace trans;
25using llvm::StringRef;
26
27namespace {
28
29class APIChecker : public RecursiveASTVisitor<APIChecker> {
30 MigrationPass &Pass;
31 Selector getReturnValueSel, setReturnValueSel;
32 Selector getArgumentSel, setArgumentSel;
33
34public:
35 APIChecker(MigrationPass &pass) : Pass(pass) {
36 SelectorTable &sels = Pass.Ctx.Selectors;
37 IdentifierTable &ids = Pass.Ctx.Idents;
38 getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue"));
39 setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue"));
40
41 IdentifierInfo *selIds[2];
42 selIds[0] = &ids.get("getArgument");
43 selIds[1] = &ids.get("atIndex");
44 getArgumentSel = sels.getSelector(2, selIds);
45 selIds[0] = &ids.get("setArgument");
46 setArgumentSel = sels.getSelector(2, selIds);
47 }
48
49 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
50 if (E->isInstanceMessage() &&
51 E->getReceiverInterface() &&
52 E->getReceiverInterface()->getName() == "NSInvocation") {
53 StringRef selName;
54 if (E->getSelector() == getReturnValueSel)
55 selName = "getReturnValue";
56 else if (E->getSelector() == setReturnValueSel)
57 selName = "setReturnValue";
58 else if (E->getSelector() == getArgumentSel)
59 selName = "getArgument";
60 else if (E->getSelector() == setArgumentSel)
61 selName = "setArgument";
62
63 if (selName.empty())
64 return true;
65
66 Expr *parm = E->getArg(0)->IgnoreParenCasts();
67 QualType pointee = parm->getType()->getPointeeType();
68 if (pointee.isNull())
69 return true;
70
71 if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) {
72 std::string err = "NSInvocation's ";
73 err += selName;
74 err += " is not safe to be used with an object with ownership other "
75 "than __unsafe_unretained";
76 Pass.TA.reportError(err, parm->getLocStart(), parm->getSourceRange());
77 }
78 return true;
79 }
80
81 return true;
82 }
83};
84
85} // anonymous namespace
86
87void trans::checkAPIUses(MigrationPass &pass) {
88 APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
89}