TransAPIUses.cpp revision accaf19bc1129c0273ec50dba52318e60bc29103
1accaf19bc1129c0273ec50dba52318e60bc29103Benjamin Kramer//===--- TransAPIUses.cpp - Transformations to ARC mode -------------------===//
2fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis//
3fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis//                     The LLVM Compiler Infrastructure
4fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis//
5fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis// This file is distributed under the University of Illinois Open Source
6fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis// License. See LICENSE.TXT for details.
7fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis//
8fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis//===----------------------------------------------------------------------===//
9fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis//
10fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis// checkAPIUses:
11fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis//
1218fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis// Emits error/fix with some API uses that are obsolete or not safe in ARC mode:
13fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis//
14fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis// - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe
15fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis//   with __unsafe_unretained objects.
1618fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis// - Calling -zone gets replaced with 'nil'.
17fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis//
18fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis//===----------------------------------------------------------------------===//
19fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis
20fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis#include "Transforms.h"
21fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis#include "Internals.h"
22471c8b49982d1132f30b0b0da27fef94fd6e4f67Benjamin Kramer#include "clang/AST/ASTContext.h"
2318fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis#include "clang/Sema/SemaDiagnostic.h"
24fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis
25fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidisusing namespace clang;
26fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidisusing namespace arcmt;
27fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidisusing namespace trans;
28fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis
29fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidisnamespace {
30fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis
31fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidisclass APIChecker : public RecursiveASTVisitor<APIChecker> {
32fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis  MigrationPass &Pass;
3305fdf9bc3f5089db291484e4ad9880aa432db9f4Argyrios Kyrtzidis
34fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis  Selector getReturnValueSel, setReturnValueSel;
35fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis  Selector getArgumentSel, setArgumentSel;
36fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis
3718fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis  Selector zoneSel;
38fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidispublic:
39fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis  APIChecker(MigrationPass &pass) : Pass(pass) {
40fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis    SelectorTable &sels = Pass.Ctx.Selectors;
41fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis    IdentifierTable &ids = Pass.Ctx.Idents;
42fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis    getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue"));
43fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis    setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue"));
44fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis
45fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis    IdentifierInfo *selIds[2];
46fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis    selIds[0] = &ids.get("getArgument");
47fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis    selIds[1] = &ids.get("atIndex");
48fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis    getArgumentSel = sels.getSelector(2, selIds);
49fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis    selIds[0] = &ids.get("setArgument");
50fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis    setArgumentSel = sels.getSelector(2, selIds);
5105fdf9bc3f5089db291484e4ad9880aa432db9f4Argyrios Kyrtzidis
5218fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis    zoneSel = sels.getNullarySelector(&ids.get("zone"));
53fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis  }
54fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis
55fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis  bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
5618fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis    // NSInvocation.
57fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis    if (E->isInstanceMessage() &&
58fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis        E->getReceiverInterface() &&
59fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis        E->getReceiverInterface()->getName() == "NSInvocation") {
60fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis      StringRef selName;
61fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis      if (E->getSelector() == getReturnValueSel)
62fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis        selName = "getReturnValue";
63fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis      else if (E->getSelector() == setReturnValueSel)
64fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis        selName = "setReturnValue";
65fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis      else if (E->getSelector() == getArgumentSel)
66fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis        selName = "getArgument";
67fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis      else if (E->getSelector() == setArgumentSel)
68fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis        selName = "setArgument";
69fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis
70fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis      if (selName.empty())
71fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis        return true;
72fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis
73fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis      Expr *parm = E->getArg(0)->IgnoreParenCasts();
74fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis      QualType pointee = parm->getType()->getPointeeType();
75fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis      if (pointee.isNull())
76fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis        return true;
77fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis
78fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis      if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) {
79fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis        std::string err = "NSInvocation's ";
80fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis        err += selName;
81fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis        err += " is not safe to be used with an object with ownership other "
82fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis            "than __unsafe_unretained";
83fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis        Pass.TA.reportError(err, parm->getLocStart(), parm->getSourceRange());
84fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis      }
85fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis      return true;
86fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis    }
87fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis
8818fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis    // -zone.
8918fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis    if (E->isInstanceMessage() &&
9018fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis        E->getInstanceReceiver() &&
9118fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis        E->getSelector() == zoneSel &&
9218fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis        Pass.TA.hasDiagnostic(diag::err_unavailable,
9318fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis                              diag::err_unavailable_message,
9418fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis                              E->getInstanceReceiver()->getExprLoc())) {
9518fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis      // Calling -zone is meaningless in ARC, change it to nil.
9618fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis      Transaction Trans(Pass.TA);
9718fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis      Pass.TA.clearDiagnostic(diag::err_unavailable,
9818fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis                              diag::err_unavailable_message,
9918fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis                              E->getInstanceReceiver()->getExprLoc());
10018fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis      Pass.TA.replace(E->getSourceRange(), getNilString(Pass.Ctx));
10118fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis    }
102fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis    return true;
103fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis  }
104fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis};
105fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis
106fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis} // anonymous namespace
107fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis
108fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidisvoid trans::checkAPIUses(MigrationPass &pass) {
109fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis  APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
110fd10398c10ffdcbdeb1e3e299c74d70e689f503cArgyrios Kyrtzidis}
111