1f4a2713aSLionel Sambuc //===--- Transforms.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 #include "Transforms.h"
11f4a2713aSLionel Sambuc #include "Internals.h"
12f4a2713aSLionel Sambuc #include "clang/AST/ASTContext.h"
13f4a2713aSLionel Sambuc #include "clang/AST/RecursiveASTVisitor.h"
14f4a2713aSLionel Sambuc #include "clang/AST/StmtVisitor.h"
15f4a2713aSLionel Sambuc #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
16f4a2713aSLionel Sambuc #include "clang/Basic/SourceManager.h"
17f4a2713aSLionel Sambuc #include "clang/Basic/TargetInfo.h"
18f4a2713aSLionel Sambuc #include "clang/Lex/Lexer.h"
19f4a2713aSLionel Sambuc #include "clang/Sema/Sema.h"
20f4a2713aSLionel Sambuc #include "clang/Sema/SemaDiagnostic.h"
21f4a2713aSLionel Sambuc #include "llvm/ADT/DenseSet.h"
22f4a2713aSLionel Sambuc #include "llvm/ADT/StringSwitch.h"
23f4a2713aSLionel Sambuc #include <map>
24f4a2713aSLionel Sambuc
25f4a2713aSLionel Sambuc using namespace clang;
26f4a2713aSLionel Sambuc using namespace arcmt;
27f4a2713aSLionel Sambuc using namespace trans;
28f4a2713aSLionel Sambuc
~ASTTraverser()29f4a2713aSLionel Sambuc ASTTraverser::~ASTTraverser() { }
30f4a2713aSLionel Sambuc
CFBridgingFunctionsDefined()31f4a2713aSLionel Sambuc bool MigrationPass::CFBridgingFunctionsDefined() {
32f4a2713aSLionel Sambuc if (!EnableCFBridgeFns.hasValue())
33f4a2713aSLionel Sambuc EnableCFBridgeFns = SemaRef.isKnownName("CFBridgingRetain") &&
34f4a2713aSLionel Sambuc SemaRef.isKnownName("CFBridgingRelease");
35f4a2713aSLionel Sambuc return *EnableCFBridgeFns;
36f4a2713aSLionel Sambuc }
37f4a2713aSLionel Sambuc
38f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
39f4a2713aSLionel Sambuc // Helpers.
40f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
41f4a2713aSLionel Sambuc
canApplyWeak(ASTContext & Ctx,QualType type,bool AllowOnUnknownClass)42f4a2713aSLionel Sambuc bool trans::canApplyWeak(ASTContext &Ctx, QualType type,
43f4a2713aSLionel Sambuc bool AllowOnUnknownClass) {
44f4a2713aSLionel Sambuc if (!Ctx.getLangOpts().ObjCARCWeak)
45f4a2713aSLionel Sambuc return false;
46f4a2713aSLionel Sambuc
47f4a2713aSLionel Sambuc QualType T = type;
48f4a2713aSLionel Sambuc if (T.isNull())
49f4a2713aSLionel Sambuc return false;
50f4a2713aSLionel Sambuc
51f4a2713aSLionel Sambuc // iOS is always safe to use 'weak'.
52f4a2713aSLionel Sambuc if (Ctx.getTargetInfo().getTriple().isiOS())
53f4a2713aSLionel Sambuc AllowOnUnknownClass = true;
54f4a2713aSLionel Sambuc
55f4a2713aSLionel Sambuc while (const PointerType *ptr = T->getAs<PointerType>())
56f4a2713aSLionel Sambuc T = ptr->getPointeeType();
57f4a2713aSLionel Sambuc if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) {
58f4a2713aSLionel Sambuc ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl();
59f4a2713aSLionel Sambuc if (!AllowOnUnknownClass && (!Class || Class->getName() == "NSObject"))
60f4a2713aSLionel Sambuc return false; // id/NSObject is not safe for weak.
61f4a2713aSLionel Sambuc if (!AllowOnUnknownClass && !Class->hasDefinition())
62f4a2713aSLionel Sambuc return false; // forward classes are not verifiable, therefore not safe.
63f4a2713aSLionel Sambuc if (Class && Class->isArcWeakrefUnavailable())
64f4a2713aSLionel Sambuc return false;
65f4a2713aSLionel Sambuc }
66f4a2713aSLionel Sambuc
67f4a2713aSLionel Sambuc return true;
68f4a2713aSLionel Sambuc }
69f4a2713aSLionel Sambuc
isPlusOneAssign(const BinaryOperator * E)70f4a2713aSLionel Sambuc bool trans::isPlusOneAssign(const BinaryOperator *E) {
71f4a2713aSLionel Sambuc if (E->getOpcode() != BO_Assign)
72f4a2713aSLionel Sambuc return false;
73f4a2713aSLionel Sambuc
74f4a2713aSLionel Sambuc return isPlusOne(E->getRHS());
75f4a2713aSLionel Sambuc }
76f4a2713aSLionel Sambuc
isPlusOne(const Expr * E)77f4a2713aSLionel Sambuc bool trans::isPlusOne(const Expr *E) {
78f4a2713aSLionel Sambuc if (!E)
79f4a2713aSLionel Sambuc return false;
80f4a2713aSLionel Sambuc if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E))
81f4a2713aSLionel Sambuc E = EWC->getSubExpr();
82f4a2713aSLionel Sambuc
83f4a2713aSLionel Sambuc if (const ObjCMessageExpr *
84f4a2713aSLionel Sambuc ME = dyn_cast<ObjCMessageExpr>(E->IgnoreParenCasts()))
85f4a2713aSLionel Sambuc if (ME->getMethodFamily() == OMF_retain)
86f4a2713aSLionel Sambuc return true;
87f4a2713aSLionel Sambuc
88f4a2713aSLionel Sambuc if (const CallExpr *
89f4a2713aSLionel Sambuc callE = dyn_cast<CallExpr>(E->IgnoreParenCasts())) {
90f4a2713aSLionel Sambuc if (const FunctionDecl *FD = callE->getDirectCallee()) {
91*0a6a1f1dSLionel Sambuc if (FD->hasAttr<CFReturnsRetainedAttr>())
92f4a2713aSLionel Sambuc return true;
93f4a2713aSLionel Sambuc
94f4a2713aSLionel Sambuc if (FD->isGlobal() &&
95f4a2713aSLionel Sambuc FD->getIdentifier() &&
96f4a2713aSLionel Sambuc FD->getParent()->isTranslationUnit() &&
97f4a2713aSLionel Sambuc FD->isExternallyVisible() &&
98f4a2713aSLionel Sambuc ento::cocoa::isRefType(callE->getType(), "CF",
99f4a2713aSLionel Sambuc FD->getIdentifier()->getName())) {
100f4a2713aSLionel Sambuc StringRef fname = FD->getIdentifier()->getName();
101f4a2713aSLionel Sambuc if (fname.endswith("Retain") ||
102f4a2713aSLionel Sambuc fname.find("Create") != StringRef::npos ||
103f4a2713aSLionel Sambuc fname.find("Copy") != StringRef::npos) {
104f4a2713aSLionel Sambuc return true;
105f4a2713aSLionel Sambuc }
106f4a2713aSLionel Sambuc }
107f4a2713aSLionel Sambuc }
108f4a2713aSLionel Sambuc }
109f4a2713aSLionel Sambuc
110f4a2713aSLionel Sambuc const ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E);
111f4a2713aSLionel Sambuc while (implCE && implCE->getCastKind() == CK_BitCast)
112f4a2713aSLionel Sambuc implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr());
113f4a2713aSLionel Sambuc
114f4a2713aSLionel Sambuc if (implCE && implCE->getCastKind() == CK_ARCConsumeObject)
115f4a2713aSLionel Sambuc return true;
116f4a2713aSLionel Sambuc
117f4a2713aSLionel Sambuc return false;
118f4a2713aSLionel Sambuc }
119f4a2713aSLionel Sambuc
120f4a2713aSLionel Sambuc /// \brief 'Loc' is the end of a statement range. This returns the location
121f4a2713aSLionel Sambuc /// immediately after the semicolon following the statement.
122f4a2713aSLionel Sambuc /// If no semicolon is found or the location is inside a macro, the returned
123f4a2713aSLionel Sambuc /// source location will be invalid.
findLocationAfterSemi(SourceLocation loc,ASTContext & Ctx,bool IsDecl)124f4a2713aSLionel Sambuc SourceLocation trans::findLocationAfterSemi(SourceLocation loc,
125f4a2713aSLionel Sambuc ASTContext &Ctx, bool IsDecl) {
126f4a2713aSLionel Sambuc SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx, IsDecl);
127f4a2713aSLionel Sambuc if (SemiLoc.isInvalid())
128f4a2713aSLionel Sambuc return SourceLocation();
129f4a2713aSLionel Sambuc return SemiLoc.getLocWithOffset(1);
130f4a2713aSLionel Sambuc }
131f4a2713aSLionel Sambuc
132f4a2713aSLionel Sambuc /// \brief \arg Loc is the end of a statement range. This returns the location
133f4a2713aSLionel Sambuc /// of the semicolon following the statement.
134f4a2713aSLionel Sambuc /// If no semicolon is found or the location is inside a macro, the returned
135f4a2713aSLionel Sambuc /// source location will be invalid.
findSemiAfterLocation(SourceLocation loc,ASTContext & Ctx,bool IsDecl)136f4a2713aSLionel Sambuc SourceLocation trans::findSemiAfterLocation(SourceLocation loc,
137f4a2713aSLionel Sambuc ASTContext &Ctx,
138f4a2713aSLionel Sambuc bool IsDecl) {
139f4a2713aSLionel Sambuc SourceManager &SM = Ctx.getSourceManager();
140f4a2713aSLionel Sambuc if (loc.isMacroID()) {
141f4a2713aSLionel Sambuc if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOpts(), &loc))
142f4a2713aSLionel Sambuc return SourceLocation();
143f4a2713aSLionel Sambuc }
144f4a2713aSLionel Sambuc loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOpts());
145f4a2713aSLionel Sambuc
146f4a2713aSLionel Sambuc // Break down the source location.
147f4a2713aSLionel Sambuc std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
148f4a2713aSLionel Sambuc
149f4a2713aSLionel Sambuc // Try to load the file buffer.
150f4a2713aSLionel Sambuc bool invalidTemp = false;
151f4a2713aSLionel Sambuc StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
152f4a2713aSLionel Sambuc if (invalidTemp)
153f4a2713aSLionel Sambuc return SourceLocation();
154f4a2713aSLionel Sambuc
155f4a2713aSLionel Sambuc const char *tokenBegin = file.data() + locInfo.second;
156f4a2713aSLionel Sambuc
157f4a2713aSLionel Sambuc // Lex from the start of the given location.
158f4a2713aSLionel Sambuc Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
159f4a2713aSLionel Sambuc Ctx.getLangOpts(),
160f4a2713aSLionel Sambuc file.begin(), tokenBegin, file.end());
161f4a2713aSLionel Sambuc Token tok;
162f4a2713aSLionel Sambuc lexer.LexFromRawLexer(tok);
163f4a2713aSLionel Sambuc if (tok.isNot(tok::semi)) {
164f4a2713aSLionel Sambuc if (!IsDecl)
165f4a2713aSLionel Sambuc return SourceLocation();
166f4a2713aSLionel Sambuc // Declaration may be followed with other tokens; such as an __attribute,
167f4a2713aSLionel Sambuc // before ending with a semicolon.
168f4a2713aSLionel Sambuc return findSemiAfterLocation(tok.getLocation(), Ctx, /*IsDecl*/true);
169f4a2713aSLionel Sambuc }
170f4a2713aSLionel Sambuc
171f4a2713aSLionel Sambuc return tok.getLocation();
172f4a2713aSLionel Sambuc }
173f4a2713aSLionel Sambuc
hasSideEffects(Expr * E,ASTContext & Ctx)174f4a2713aSLionel Sambuc bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) {
175f4a2713aSLionel Sambuc if (!E || !E->HasSideEffects(Ctx))
176f4a2713aSLionel Sambuc return false;
177f4a2713aSLionel Sambuc
178f4a2713aSLionel Sambuc E = E->IgnoreParenCasts();
179f4a2713aSLionel Sambuc ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
180f4a2713aSLionel Sambuc if (!ME)
181f4a2713aSLionel Sambuc return true;
182f4a2713aSLionel Sambuc switch (ME->getMethodFamily()) {
183f4a2713aSLionel Sambuc case OMF_autorelease:
184f4a2713aSLionel Sambuc case OMF_dealloc:
185f4a2713aSLionel Sambuc case OMF_release:
186f4a2713aSLionel Sambuc case OMF_retain:
187f4a2713aSLionel Sambuc switch (ME->getReceiverKind()) {
188f4a2713aSLionel Sambuc case ObjCMessageExpr::SuperInstance:
189f4a2713aSLionel Sambuc return false;
190f4a2713aSLionel Sambuc case ObjCMessageExpr::Instance:
191f4a2713aSLionel Sambuc return hasSideEffects(ME->getInstanceReceiver(), Ctx);
192f4a2713aSLionel Sambuc default:
193f4a2713aSLionel Sambuc break;
194f4a2713aSLionel Sambuc }
195f4a2713aSLionel Sambuc break;
196f4a2713aSLionel Sambuc default:
197f4a2713aSLionel Sambuc break;
198f4a2713aSLionel Sambuc }
199f4a2713aSLionel Sambuc
200f4a2713aSLionel Sambuc return true;
201f4a2713aSLionel Sambuc }
202f4a2713aSLionel Sambuc
isGlobalVar(Expr * E)203f4a2713aSLionel Sambuc bool trans::isGlobalVar(Expr *E) {
204f4a2713aSLionel Sambuc E = E->IgnoreParenCasts();
205f4a2713aSLionel Sambuc if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
206f4a2713aSLionel Sambuc return DRE->getDecl()->getDeclContext()->isFileContext() &&
207f4a2713aSLionel Sambuc DRE->getDecl()->isExternallyVisible();
208f4a2713aSLionel Sambuc if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
209f4a2713aSLionel Sambuc return isGlobalVar(condOp->getTrueExpr()) &&
210f4a2713aSLionel Sambuc isGlobalVar(condOp->getFalseExpr());
211f4a2713aSLionel Sambuc
212f4a2713aSLionel Sambuc return false;
213f4a2713aSLionel Sambuc }
214f4a2713aSLionel Sambuc
getNilString(ASTContext & Ctx)215f4a2713aSLionel Sambuc StringRef trans::getNilString(ASTContext &Ctx) {
216f4a2713aSLionel Sambuc if (Ctx.Idents.get("nil").hasMacroDefinition())
217f4a2713aSLionel Sambuc return "nil";
218f4a2713aSLionel Sambuc else
219f4a2713aSLionel Sambuc return "0";
220f4a2713aSLionel Sambuc }
221f4a2713aSLionel Sambuc
222f4a2713aSLionel Sambuc namespace {
223f4a2713aSLionel Sambuc
224f4a2713aSLionel Sambuc class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> {
225f4a2713aSLionel Sambuc ExprSet &Refs;
226f4a2713aSLionel Sambuc public:
ReferenceClear(ExprSet & refs)227f4a2713aSLionel Sambuc ReferenceClear(ExprSet &refs) : Refs(refs) { }
VisitDeclRefExpr(DeclRefExpr * E)228f4a2713aSLionel Sambuc bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; }
229f4a2713aSLionel Sambuc };
230f4a2713aSLionel Sambuc
231f4a2713aSLionel Sambuc class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> {
232f4a2713aSLionel Sambuc ValueDecl *Dcl;
233f4a2713aSLionel Sambuc ExprSet &Refs;
234f4a2713aSLionel Sambuc
235f4a2713aSLionel Sambuc public:
ReferenceCollector(ValueDecl * D,ExprSet & refs)236f4a2713aSLionel Sambuc ReferenceCollector(ValueDecl *D, ExprSet &refs)
237f4a2713aSLionel Sambuc : Dcl(D), Refs(refs) { }
238f4a2713aSLionel Sambuc
VisitDeclRefExpr(DeclRefExpr * E)239f4a2713aSLionel Sambuc bool VisitDeclRefExpr(DeclRefExpr *E) {
240f4a2713aSLionel Sambuc if (E->getDecl() == Dcl)
241f4a2713aSLionel Sambuc Refs.insert(E);
242f4a2713aSLionel Sambuc return true;
243f4a2713aSLionel Sambuc }
244f4a2713aSLionel Sambuc };
245f4a2713aSLionel Sambuc
246f4a2713aSLionel Sambuc class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> {
247f4a2713aSLionel Sambuc ExprSet &Removables;
248f4a2713aSLionel Sambuc
249f4a2713aSLionel Sambuc public:
RemovablesCollector(ExprSet & removables)250f4a2713aSLionel Sambuc RemovablesCollector(ExprSet &removables)
251f4a2713aSLionel Sambuc : Removables(removables) { }
252f4a2713aSLionel Sambuc
shouldWalkTypesOfTypeLocs() const253f4a2713aSLionel Sambuc bool shouldWalkTypesOfTypeLocs() const { return false; }
254f4a2713aSLionel Sambuc
TraverseStmtExpr(StmtExpr * E)255f4a2713aSLionel Sambuc bool TraverseStmtExpr(StmtExpr *E) {
256f4a2713aSLionel Sambuc CompoundStmt *S = E->getSubStmt();
257f4a2713aSLionel Sambuc for (CompoundStmt::body_iterator
258f4a2713aSLionel Sambuc I = S->body_begin(), E = S->body_end(); I != E; ++I) {
259f4a2713aSLionel Sambuc if (I != E - 1)
260f4a2713aSLionel Sambuc mark(*I);
261f4a2713aSLionel Sambuc TraverseStmt(*I);
262f4a2713aSLionel Sambuc }
263f4a2713aSLionel Sambuc return true;
264f4a2713aSLionel Sambuc }
265f4a2713aSLionel Sambuc
VisitCompoundStmt(CompoundStmt * S)266f4a2713aSLionel Sambuc bool VisitCompoundStmt(CompoundStmt *S) {
267*0a6a1f1dSLionel Sambuc for (auto *I : S->body())
268*0a6a1f1dSLionel Sambuc mark(I);
269f4a2713aSLionel Sambuc return true;
270f4a2713aSLionel Sambuc }
271f4a2713aSLionel Sambuc
VisitIfStmt(IfStmt * S)272f4a2713aSLionel Sambuc bool VisitIfStmt(IfStmt *S) {
273f4a2713aSLionel Sambuc mark(S->getThen());
274f4a2713aSLionel Sambuc mark(S->getElse());
275f4a2713aSLionel Sambuc return true;
276f4a2713aSLionel Sambuc }
277f4a2713aSLionel Sambuc
VisitWhileStmt(WhileStmt * S)278f4a2713aSLionel Sambuc bool VisitWhileStmt(WhileStmt *S) {
279f4a2713aSLionel Sambuc mark(S->getBody());
280f4a2713aSLionel Sambuc return true;
281f4a2713aSLionel Sambuc }
282f4a2713aSLionel Sambuc
VisitDoStmt(DoStmt * S)283f4a2713aSLionel Sambuc bool VisitDoStmt(DoStmt *S) {
284f4a2713aSLionel Sambuc mark(S->getBody());
285f4a2713aSLionel Sambuc return true;
286f4a2713aSLionel Sambuc }
287f4a2713aSLionel Sambuc
VisitForStmt(ForStmt * S)288f4a2713aSLionel Sambuc bool VisitForStmt(ForStmt *S) {
289f4a2713aSLionel Sambuc mark(S->getInit());
290f4a2713aSLionel Sambuc mark(S->getInc());
291f4a2713aSLionel Sambuc mark(S->getBody());
292f4a2713aSLionel Sambuc return true;
293f4a2713aSLionel Sambuc }
294f4a2713aSLionel Sambuc
295f4a2713aSLionel Sambuc private:
mark(Stmt * S)296f4a2713aSLionel Sambuc void mark(Stmt *S) {
297f4a2713aSLionel Sambuc if (!S) return;
298f4a2713aSLionel Sambuc
299f4a2713aSLionel Sambuc while (LabelStmt *Label = dyn_cast<LabelStmt>(S))
300f4a2713aSLionel Sambuc S = Label->getSubStmt();
301f4a2713aSLionel Sambuc S = S->IgnoreImplicit();
302f4a2713aSLionel Sambuc if (Expr *E = dyn_cast<Expr>(S))
303f4a2713aSLionel Sambuc Removables.insert(E);
304f4a2713aSLionel Sambuc }
305f4a2713aSLionel Sambuc };
306f4a2713aSLionel Sambuc
307f4a2713aSLionel Sambuc } // end anonymous namespace
308f4a2713aSLionel Sambuc
clearRefsIn(Stmt * S,ExprSet & refs)309f4a2713aSLionel Sambuc void trans::clearRefsIn(Stmt *S, ExprSet &refs) {
310f4a2713aSLionel Sambuc ReferenceClear(refs).TraverseStmt(S);
311f4a2713aSLionel Sambuc }
312f4a2713aSLionel Sambuc
collectRefs(ValueDecl * D,Stmt * S,ExprSet & refs)313f4a2713aSLionel Sambuc void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) {
314f4a2713aSLionel Sambuc ReferenceCollector(D, refs).TraverseStmt(S);
315f4a2713aSLionel Sambuc }
316f4a2713aSLionel Sambuc
collectRemovables(Stmt * S,ExprSet & exprs)317f4a2713aSLionel Sambuc void trans::collectRemovables(Stmt *S, ExprSet &exprs) {
318f4a2713aSLionel Sambuc RemovablesCollector(exprs).TraverseStmt(S);
319f4a2713aSLionel Sambuc }
320f4a2713aSLionel Sambuc
321f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
322f4a2713aSLionel Sambuc // MigrationContext
323f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
324f4a2713aSLionel Sambuc
325f4a2713aSLionel Sambuc namespace {
326f4a2713aSLionel Sambuc
327f4a2713aSLionel Sambuc class ASTTransform : public RecursiveASTVisitor<ASTTransform> {
328f4a2713aSLionel Sambuc MigrationContext &MigrateCtx;
329f4a2713aSLionel Sambuc typedef RecursiveASTVisitor<ASTTransform> base;
330f4a2713aSLionel Sambuc
331f4a2713aSLionel Sambuc public:
ASTTransform(MigrationContext & MigrateCtx)332f4a2713aSLionel Sambuc ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { }
333f4a2713aSLionel Sambuc
shouldWalkTypesOfTypeLocs() const334f4a2713aSLionel Sambuc bool shouldWalkTypesOfTypeLocs() const { return false; }
335f4a2713aSLionel Sambuc
TraverseObjCImplementationDecl(ObjCImplementationDecl * D)336f4a2713aSLionel Sambuc bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
337f4a2713aSLionel Sambuc ObjCImplementationContext ImplCtx(MigrateCtx, D);
338f4a2713aSLionel Sambuc for (MigrationContext::traverser_iterator
339f4a2713aSLionel Sambuc I = MigrateCtx.traversers_begin(),
340f4a2713aSLionel Sambuc E = MigrateCtx.traversers_end(); I != E; ++I)
341f4a2713aSLionel Sambuc (*I)->traverseObjCImplementation(ImplCtx);
342f4a2713aSLionel Sambuc
343f4a2713aSLionel Sambuc return base::TraverseObjCImplementationDecl(D);
344f4a2713aSLionel Sambuc }
345f4a2713aSLionel Sambuc
TraverseStmt(Stmt * rootS)346f4a2713aSLionel Sambuc bool TraverseStmt(Stmt *rootS) {
347f4a2713aSLionel Sambuc if (!rootS)
348f4a2713aSLionel Sambuc return true;
349f4a2713aSLionel Sambuc
350f4a2713aSLionel Sambuc BodyContext BodyCtx(MigrateCtx, rootS);
351f4a2713aSLionel Sambuc for (MigrationContext::traverser_iterator
352f4a2713aSLionel Sambuc I = MigrateCtx.traversers_begin(),
353f4a2713aSLionel Sambuc E = MigrateCtx.traversers_end(); I != E; ++I)
354f4a2713aSLionel Sambuc (*I)->traverseBody(BodyCtx);
355f4a2713aSLionel Sambuc
356f4a2713aSLionel Sambuc return true;
357f4a2713aSLionel Sambuc }
358f4a2713aSLionel Sambuc };
359f4a2713aSLionel Sambuc
360f4a2713aSLionel Sambuc }
361f4a2713aSLionel Sambuc
~MigrationContext()362f4a2713aSLionel Sambuc MigrationContext::~MigrationContext() {
363f4a2713aSLionel Sambuc for (traverser_iterator
364f4a2713aSLionel Sambuc I = traversers_begin(), E = traversers_end(); I != E; ++I)
365f4a2713aSLionel Sambuc delete *I;
366f4a2713aSLionel Sambuc }
367f4a2713aSLionel Sambuc
isGCOwnedNonObjC(QualType T)368f4a2713aSLionel Sambuc bool MigrationContext::isGCOwnedNonObjC(QualType T) {
369f4a2713aSLionel Sambuc while (!T.isNull()) {
370f4a2713aSLionel Sambuc if (const AttributedType *AttrT = T->getAs<AttributedType>()) {
371f4a2713aSLionel Sambuc if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership)
372f4a2713aSLionel Sambuc return !AttrT->getModifiedType()->isObjCRetainableType();
373f4a2713aSLionel Sambuc }
374f4a2713aSLionel Sambuc
375f4a2713aSLionel Sambuc if (T->isArrayType())
376f4a2713aSLionel Sambuc T = Pass.Ctx.getBaseElementType(T);
377f4a2713aSLionel Sambuc else if (const PointerType *PT = T->getAs<PointerType>())
378f4a2713aSLionel Sambuc T = PT->getPointeeType();
379f4a2713aSLionel Sambuc else if (const ReferenceType *RT = T->getAs<ReferenceType>())
380f4a2713aSLionel Sambuc T = RT->getPointeeType();
381f4a2713aSLionel Sambuc else
382f4a2713aSLionel Sambuc break;
383f4a2713aSLionel Sambuc }
384f4a2713aSLionel Sambuc
385f4a2713aSLionel Sambuc return false;
386f4a2713aSLionel Sambuc }
387f4a2713aSLionel Sambuc
rewritePropertyAttribute(StringRef fromAttr,StringRef toAttr,SourceLocation atLoc)388f4a2713aSLionel Sambuc bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr,
389f4a2713aSLionel Sambuc StringRef toAttr,
390f4a2713aSLionel Sambuc SourceLocation atLoc) {
391f4a2713aSLionel Sambuc if (atLoc.isMacroID())
392f4a2713aSLionel Sambuc return false;
393f4a2713aSLionel Sambuc
394f4a2713aSLionel Sambuc SourceManager &SM = Pass.Ctx.getSourceManager();
395f4a2713aSLionel Sambuc
396f4a2713aSLionel Sambuc // Break down the source location.
397f4a2713aSLionel Sambuc std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
398f4a2713aSLionel Sambuc
399f4a2713aSLionel Sambuc // Try to load the file buffer.
400f4a2713aSLionel Sambuc bool invalidTemp = false;
401f4a2713aSLionel Sambuc StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
402f4a2713aSLionel Sambuc if (invalidTemp)
403f4a2713aSLionel Sambuc return false;
404f4a2713aSLionel Sambuc
405f4a2713aSLionel Sambuc const char *tokenBegin = file.data() + locInfo.second;
406f4a2713aSLionel Sambuc
407f4a2713aSLionel Sambuc // Lex from the start of the given location.
408f4a2713aSLionel Sambuc Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
409f4a2713aSLionel Sambuc Pass.Ctx.getLangOpts(),
410f4a2713aSLionel Sambuc file.begin(), tokenBegin, file.end());
411f4a2713aSLionel Sambuc Token tok;
412f4a2713aSLionel Sambuc lexer.LexFromRawLexer(tok);
413f4a2713aSLionel Sambuc if (tok.isNot(tok::at)) return false;
414f4a2713aSLionel Sambuc lexer.LexFromRawLexer(tok);
415f4a2713aSLionel Sambuc if (tok.isNot(tok::raw_identifier)) return false;
416*0a6a1f1dSLionel Sambuc if (tok.getRawIdentifier() != "property")
417f4a2713aSLionel Sambuc return false;
418f4a2713aSLionel Sambuc lexer.LexFromRawLexer(tok);
419f4a2713aSLionel Sambuc if (tok.isNot(tok::l_paren)) return false;
420f4a2713aSLionel Sambuc
421f4a2713aSLionel Sambuc Token BeforeTok = tok;
422f4a2713aSLionel Sambuc Token AfterTok;
423f4a2713aSLionel Sambuc AfterTok.startToken();
424f4a2713aSLionel Sambuc SourceLocation AttrLoc;
425f4a2713aSLionel Sambuc
426f4a2713aSLionel Sambuc lexer.LexFromRawLexer(tok);
427f4a2713aSLionel Sambuc if (tok.is(tok::r_paren))
428f4a2713aSLionel Sambuc return false;
429f4a2713aSLionel Sambuc
430f4a2713aSLionel Sambuc while (1) {
431f4a2713aSLionel Sambuc if (tok.isNot(tok::raw_identifier)) return false;
432*0a6a1f1dSLionel Sambuc if (tok.getRawIdentifier() == fromAttr) {
433f4a2713aSLionel Sambuc if (!toAttr.empty()) {
434f4a2713aSLionel Sambuc Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr);
435f4a2713aSLionel Sambuc return true;
436f4a2713aSLionel Sambuc }
437f4a2713aSLionel Sambuc // We want to remove the attribute.
438f4a2713aSLionel Sambuc AttrLoc = tok.getLocation();
439f4a2713aSLionel Sambuc }
440f4a2713aSLionel Sambuc
441f4a2713aSLionel Sambuc do {
442f4a2713aSLionel Sambuc lexer.LexFromRawLexer(tok);
443f4a2713aSLionel Sambuc if (AttrLoc.isValid() && AfterTok.is(tok::unknown))
444f4a2713aSLionel Sambuc AfterTok = tok;
445f4a2713aSLionel Sambuc } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren));
446f4a2713aSLionel Sambuc if (tok.is(tok::r_paren))
447f4a2713aSLionel Sambuc break;
448f4a2713aSLionel Sambuc if (AttrLoc.isInvalid())
449f4a2713aSLionel Sambuc BeforeTok = tok;
450f4a2713aSLionel Sambuc lexer.LexFromRawLexer(tok);
451f4a2713aSLionel Sambuc }
452f4a2713aSLionel Sambuc
453f4a2713aSLionel Sambuc if (toAttr.empty() && AttrLoc.isValid() && AfterTok.isNot(tok::unknown)) {
454f4a2713aSLionel Sambuc // We want to remove the attribute.
455f4a2713aSLionel Sambuc if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::r_paren)) {
456f4a2713aSLionel Sambuc Pass.TA.remove(SourceRange(BeforeTok.getLocation(),
457f4a2713aSLionel Sambuc AfterTok.getLocation()));
458f4a2713aSLionel Sambuc } else if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::comma)) {
459f4a2713aSLionel Sambuc Pass.TA.remove(SourceRange(AttrLoc, AfterTok.getLocation()));
460f4a2713aSLionel Sambuc } else {
461f4a2713aSLionel Sambuc Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AttrLoc));
462f4a2713aSLionel Sambuc }
463f4a2713aSLionel Sambuc
464f4a2713aSLionel Sambuc return true;
465f4a2713aSLionel Sambuc }
466f4a2713aSLionel Sambuc
467f4a2713aSLionel Sambuc return false;
468f4a2713aSLionel Sambuc }
469f4a2713aSLionel Sambuc
addPropertyAttribute(StringRef attr,SourceLocation atLoc)470f4a2713aSLionel Sambuc bool MigrationContext::addPropertyAttribute(StringRef attr,
471f4a2713aSLionel Sambuc SourceLocation atLoc) {
472f4a2713aSLionel Sambuc if (atLoc.isMacroID())
473f4a2713aSLionel Sambuc return false;
474f4a2713aSLionel Sambuc
475f4a2713aSLionel Sambuc SourceManager &SM = Pass.Ctx.getSourceManager();
476f4a2713aSLionel Sambuc
477f4a2713aSLionel Sambuc // Break down the source location.
478f4a2713aSLionel Sambuc std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
479f4a2713aSLionel Sambuc
480f4a2713aSLionel Sambuc // Try to load the file buffer.
481f4a2713aSLionel Sambuc bool invalidTemp = false;
482f4a2713aSLionel Sambuc StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
483f4a2713aSLionel Sambuc if (invalidTemp)
484f4a2713aSLionel Sambuc return false;
485f4a2713aSLionel Sambuc
486f4a2713aSLionel Sambuc const char *tokenBegin = file.data() + locInfo.second;
487f4a2713aSLionel Sambuc
488f4a2713aSLionel Sambuc // Lex from the start of the given location.
489f4a2713aSLionel Sambuc Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
490f4a2713aSLionel Sambuc Pass.Ctx.getLangOpts(),
491f4a2713aSLionel Sambuc file.begin(), tokenBegin, file.end());
492f4a2713aSLionel Sambuc Token tok;
493f4a2713aSLionel Sambuc lexer.LexFromRawLexer(tok);
494f4a2713aSLionel Sambuc if (tok.isNot(tok::at)) return false;
495f4a2713aSLionel Sambuc lexer.LexFromRawLexer(tok);
496f4a2713aSLionel Sambuc if (tok.isNot(tok::raw_identifier)) return false;
497*0a6a1f1dSLionel Sambuc if (tok.getRawIdentifier() != "property")
498f4a2713aSLionel Sambuc return false;
499f4a2713aSLionel Sambuc lexer.LexFromRawLexer(tok);
500f4a2713aSLionel Sambuc
501f4a2713aSLionel Sambuc if (tok.isNot(tok::l_paren)) {
502f4a2713aSLionel Sambuc Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") ");
503f4a2713aSLionel Sambuc return true;
504f4a2713aSLionel Sambuc }
505f4a2713aSLionel Sambuc
506f4a2713aSLionel Sambuc lexer.LexFromRawLexer(tok);
507f4a2713aSLionel Sambuc if (tok.is(tok::r_paren)) {
508f4a2713aSLionel Sambuc Pass.TA.insert(tok.getLocation(), attr);
509f4a2713aSLionel Sambuc return true;
510f4a2713aSLionel Sambuc }
511f4a2713aSLionel Sambuc
512f4a2713aSLionel Sambuc if (tok.isNot(tok::raw_identifier)) return false;
513f4a2713aSLionel Sambuc
514f4a2713aSLionel Sambuc Pass.TA.insert(tok.getLocation(), std::string(attr) + ", ");
515f4a2713aSLionel Sambuc return true;
516f4a2713aSLionel Sambuc }
517f4a2713aSLionel Sambuc
traverse(TranslationUnitDecl * TU)518f4a2713aSLionel Sambuc void MigrationContext::traverse(TranslationUnitDecl *TU) {
519f4a2713aSLionel Sambuc for (traverser_iterator
520f4a2713aSLionel Sambuc I = traversers_begin(), E = traversers_end(); I != E; ++I)
521f4a2713aSLionel Sambuc (*I)->traverseTU(*this);
522f4a2713aSLionel Sambuc
523f4a2713aSLionel Sambuc ASTTransform(*this).TraverseDecl(TU);
524f4a2713aSLionel Sambuc }
525f4a2713aSLionel Sambuc
GCRewriteFinalize(MigrationPass & pass)526f4a2713aSLionel Sambuc static void GCRewriteFinalize(MigrationPass &pass) {
527f4a2713aSLionel Sambuc ASTContext &Ctx = pass.Ctx;
528f4a2713aSLionel Sambuc TransformActions &TA = pass.TA;
529f4a2713aSLionel Sambuc DeclContext *DC = Ctx.getTranslationUnitDecl();
530f4a2713aSLionel Sambuc Selector FinalizeSel =
531f4a2713aSLionel Sambuc Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize"));
532f4a2713aSLionel Sambuc
533f4a2713aSLionel Sambuc typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
534f4a2713aSLionel Sambuc impl_iterator;
535f4a2713aSLionel Sambuc for (impl_iterator I = impl_iterator(DC->decls_begin()),
536f4a2713aSLionel Sambuc E = impl_iterator(DC->decls_end()); I != E; ++I) {
537*0a6a1f1dSLionel Sambuc for (const auto *MD : I->instance_methods()) {
538f4a2713aSLionel Sambuc if (!MD->hasBody())
539f4a2713aSLionel Sambuc continue;
540f4a2713aSLionel Sambuc
541f4a2713aSLionel Sambuc if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) {
542*0a6a1f1dSLionel Sambuc const ObjCMethodDecl *FinalizeM = MD;
543f4a2713aSLionel Sambuc Transaction Trans(TA);
544f4a2713aSLionel Sambuc TA.insert(FinalizeM->getSourceRange().getBegin(),
545f4a2713aSLionel Sambuc "#if !__has_feature(objc_arc)\n");
546f4a2713aSLionel Sambuc CharSourceRange::getTokenRange(FinalizeM->getSourceRange());
547f4a2713aSLionel Sambuc const SourceManager &SM = pass.Ctx.getSourceManager();
548f4a2713aSLionel Sambuc const LangOptions &LangOpts = pass.Ctx.getLangOpts();
549f4a2713aSLionel Sambuc bool Invalid;
550f4a2713aSLionel Sambuc std::string str = "\n#endif\n";
551f4a2713aSLionel Sambuc str += Lexer::getSourceText(
552f4a2713aSLionel Sambuc CharSourceRange::getTokenRange(FinalizeM->getSourceRange()),
553f4a2713aSLionel Sambuc SM, LangOpts, &Invalid);
554f4a2713aSLionel Sambuc TA.insertAfterToken(FinalizeM->getSourceRange().getEnd(), str);
555f4a2713aSLionel Sambuc
556f4a2713aSLionel Sambuc break;
557f4a2713aSLionel Sambuc }
558f4a2713aSLionel Sambuc }
559f4a2713aSLionel Sambuc }
560f4a2713aSLionel Sambuc }
561f4a2713aSLionel Sambuc
562f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
563f4a2713aSLionel Sambuc // getAllTransformations.
564f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
565f4a2713aSLionel Sambuc
traverseAST(MigrationPass & pass)566f4a2713aSLionel Sambuc static void traverseAST(MigrationPass &pass) {
567f4a2713aSLionel Sambuc MigrationContext MigrateCtx(pass);
568f4a2713aSLionel Sambuc
569f4a2713aSLionel Sambuc if (pass.isGCMigration()) {
570f4a2713aSLionel Sambuc MigrateCtx.addTraverser(new GCCollectableCallsTraverser);
571f4a2713aSLionel Sambuc MigrateCtx.addTraverser(new GCAttrsTraverser());
572f4a2713aSLionel Sambuc }
573f4a2713aSLionel Sambuc MigrateCtx.addTraverser(new PropertyRewriteTraverser());
574f4a2713aSLionel Sambuc MigrateCtx.addTraverser(new BlockObjCVariableTraverser());
575f4a2713aSLionel Sambuc MigrateCtx.addTraverser(new ProtectedScopeTraverser());
576f4a2713aSLionel Sambuc
577f4a2713aSLionel Sambuc MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl());
578f4a2713aSLionel Sambuc }
579f4a2713aSLionel Sambuc
independentTransforms(MigrationPass & pass)580f4a2713aSLionel Sambuc static void independentTransforms(MigrationPass &pass) {
581f4a2713aSLionel Sambuc rewriteAutoreleasePool(pass);
582f4a2713aSLionel Sambuc removeRetainReleaseDeallocFinalize(pass);
583f4a2713aSLionel Sambuc rewriteUnusedInitDelegate(pass);
584f4a2713aSLionel Sambuc removeZeroOutPropsInDeallocFinalize(pass);
585f4a2713aSLionel Sambuc makeAssignARCSafe(pass);
586f4a2713aSLionel Sambuc rewriteUnbridgedCasts(pass);
587f4a2713aSLionel Sambuc checkAPIUses(pass);
588f4a2713aSLionel Sambuc traverseAST(pass);
589f4a2713aSLionel Sambuc }
590f4a2713aSLionel Sambuc
getAllTransformations(LangOptions::GCMode OrigGCMode,bool NoFinalizeRemoval)591f4a2713aSLionel Sambuc std::vector<TransformFn> arcmt::getAllTransformations(
592f4a2713aSLionel Sambuc LangOptions::GCMode OrigGCMode,
593f4a2713aSLionel Sambuc bool NoFinalizeRemoval) {
594f4a2713aSLionel Sambuc std::vector<TransformFn> transforms;
595f4a2713aSLionel Sambuc
596f4a2713aSLionel Sambuc if (OrigGCMode == LangOptions::GCOnly && NoFinalizeRemoval)
597f4a2713aSLionel Sambuc transforms.push_back(GCRewriteFinalize);
598f4a2713aSLionel Sambuc transforms.push_back(independentTransforms);
599f4a2713aSLionel Sambuc // This depends on previous transformations removing various expressions.
600f4a2713aSLionel Sambuc transforms.push_back(removeEmptyStatementsAndDeallocFinalize);
601f4a2713aSLionel Sambuc
602f4a2713aSLionel Sambuc return transforms;
603f4a2713aSLionel Sambuc }
604