Coverage Report

Created: 2019-07-24 05:18

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