Coverage Report

Created: 2020-10-24 06:27

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