]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/llvm/tools/clang/lib/ARCMigrate/TransAPIUses.cpp
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / llvm / tools / clang / lib / ARCMigrate / TransAPIUses.cpp
1 //===--- TransAPIUses.cpp - Transformations 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/fix with some API uses that are obsolete or 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 // - Calling -zone gets replaced with 'nil'.
17 //
18 //===----------------------------------------------------------------------===//
19
20 #include "Transforms.h"
21 #include "Internals.h"
22 #include "clang/AST/ASTContext.h"
23 #include "clang/Sema/SemaDiagnostic.h"
24
25 using namespace clang;
26 using namespace arcmt;
27 using namespace trans;
28
29 namespace {
30
31 class APIChecker : public RecursiveASTVisitor<APIChecker> {
32   MigrationPass &Pass;
33
34   Selector getReturnValueSel, setReturnValueSel;
35   Selector getArgumentSel, setArgumentSel;
36
37   Selector zoneSel;
38 public:
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);
51
52     zoneSel = sels.getNullarySelector(&ids.get("zone"));
53   }
54
55   bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
56     // NSInvocation.
57     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";
69
70       if (selName.empty())
71         return true;
72
73       Expr *parm = E->getArg(0)->IgnoreParenCasts();
74       QualType pointee = parm->getType()->getPointeeType();
75       if (pointee.isNull())
76         return true;
77
78       if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) {
79         std::string err = "NSInvocation's ";
80         err += selName;
81         err += " is not safe to be used with an object with ownership other "
82             "than __unsafe_unretained";
83         Pass.TA.reportError(err, parm->getLocStart(), parm->getSourceRange());
84       }
85       return true;
86     }
87
88     // -zone.
89     if (E->isInstanceMessage() &&
90         E->getInstanceReceiver() &&
91         E->getSelector() == zoneSel &&
92         Pass.TA.hasDiagnostic(diag::err_unavailable,
93                               diag::err_unavailable_message,
94                               E->getSelectorLoc(0))) {
95       // Calling -zone is meaningless in ARC, change it to nil.
96       Transaction Trans(Pass.TA);
97       Pass.TA.clearDiagnostic(diag::err_unavailable,
98                               diag::err_unavailable_message,
99                               E->getSelectorLoc(0));
100       Pass.TA.replace(E->getSourceRange(), getNilString(Pass.Ctx));
101     }
102     return true;
103   }
104 };
105
106 } // anonymous namespace
107
108 void trans::checkAPIUses(MigrationPass &pass) {
109   APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
110 }