• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===--- 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 // - When a NSData's 'bytes' family of methods are used on a local var,
17 //   add __attribute__((objc_precise_lifetime)) to make it safer.
18 //
19 //===----------------------------------------------------------------------===//
20 
21 #include "Transforms.h"
22 #include "Internals.h"
23 
24 using namespace clang;
25 using namespace arcmt;
26 using namespace trans;
27 using llvm::StringRef;
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 bytesSel, getBytesSel, getBytesLengthSel, getBytesRangeSel;
38 
39   llvm::DenseSet<VarDecl *> ChangedNSDataVars;
40 public:
APIChecker(MigrationPass & pass)41   APIChecker(MigrationPass &pass) : Pass(pass) {
42     SelectorTable &sels = Pass.Ctx.Selectors;
43     IdentifierTable &ids = Pass.Ctx.Idents;
44     getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue"));
45     setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue"));
46 
47     IdentifierInfo *selIds[2];
48     selIds[0] = &ids.get("getArgument");
49     selIds[1] = &ids.get("atIndex");
50     getArgumentSel = sels.getSelector(2, selIds);
51     selIds[0] = &ids.get("setArgument");
52     setArgumentSel = sels.getSelector(2, selIds);
53 
54     bytesSel = sels.getNullarySelector(&ids.get("bytes"));
55     getBytesSel = sels.getUnarySelector(&ids.get("getBytes"));
56     selIds[0] = &ids.get("getBytes");
57     selIds[1] = &ids.get("length");
58     getBytesLengthSel = sels.getSelector(2, selIds);
59     selIds[1] = &ids.get("range");
60     getBytesRangeSel = sels.getSelector(2, selIds);
61   }
62 
VisitObjCMessageExpr(ObjCMessageExpr * E)63   bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
64     if (E->isInstanceMessage() &&
65         E->getReceiverInterface() &&
66         E->getReceiverInterface()->getName() == "NSInvocation") {
67       StringRef selName;
68       if (E->getSelector() == getReturnValueSel)
69         selName = "getReturnValue";
70       else if (E->getSelector() == setReturnValueSel)
71         selName = "setReturnValue";
72       else if (E->getSelector() == getArgumentSel)
73         selName = "getArgument";
74       else if (E->getSelector() == setArgumentSel)
75         selName = "setArgument";
76 
77       if (selName.empty())
78         return true;
79 
80       Expr *parm = E->getArg(0)->IgnoreParenCasts();
81       QualType pointee = parm->getType()->getPointeeType();
82       if (pointee.isNull())
83         return true;
84 
85       if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) {
86         std::string err = "NSInvocation's ";
87         err += selName;
88         err += " is not safe to be used with an object with ownership other "
89             "than __unsafe_unretained";
90         Pass.TA.reportError(err, parm->getLocStart(), parm->getSourceRange());
91       }
92       return true;
93     }
94 
95     if (E->isInstanceMessage() &&
96         E->getReceiverInterface() &&
97         E->getReceiverInterface()->getName() == "NSData" &&
98         E->getInstanceReceiver() &&
99         (E->getSelector() == bytesSel ||
100          E->getSelector() == getBytesSel ||
101          E->getSelector() == getBytesLengthSel ||
102          E->getSelector() == getBytesRangeSel)) {
103       Expr *rec = E->getInstanceReceiver();
104       rec = rec->IgnoreParenCasts();
105       if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(rec))
106         if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
107           if (VD->hasLocalStorage() && !ChangedNSDataVars.count(VD)) {
108             Transaction Trans(Pass.TA);
109             Pass.TA.insertAfterToken(VD->getLocation(),
110                                      " __attribute__((objc_precise_lifetime))");
111             ChangedNSDataVars.insert(VD);
112           }
113     }
114 
115     return true;
116   }
117 };
118 
119 } // anonymous namespace
120 
checkAPIUses(MigrationPass & pass)121 void trans::checkAPIUses(MigrationPass &pass) {
122   APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
123 }
124