Coverage Report

Created: 2023-09-30 09:22

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