Coverage Report

Created: 2017-10-03 07:32

/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/clang/lib/ARCMigrate/ARCMT.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- ARCMT.cpp - Migration to ARC mode --------------------------------===//
2
//
3
//                     The LLVM Compiler Infrastructure
4
//
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
7
//
8
//===----------------------------------------------------------------------===//
9
10
#include "Internals.h"
11
#include "clang/AST/ASTConsumer.h"
12
#include "clang/Basic/DiagnosticCategories.h"
13
#include "clang/Frontend/ASTUnit.h"
14
#include "clang/Frontend/CompilerInstance.h"
15
#include "clang/Frontend/FrontendAction.h"
16
#include "clang/Frontend/TextDiagnosticPrinter.h"
17
#include "clang/Frontend/Utils.h"
18
#include "clang/Lex/Preprocessor.h"
19
#include "clang/Lex/PreprocessorOptions.h"
20
#include "clang/Rewrite/Core/Rewriter.h"
21
#include "clang/Sema/SemaDiagnostic.h"
22
#include "clang/Serialization/ASTReader.h"
23
#include "llvm/ADT/Triple.h"
24
#include "llvm/Support/MemoryBuffer.h"
25
#include <utility>
26
using namespace clang;
27
using namespace arcmt;
28
29
bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs,
30
484
                                       SourceRange range) {
31
484
  if (range.isInvalid())
32
0
    return false;
33
484
34
484
  bool cleared = false;
35
484
  ListTy::iterator I = List.begin();
36
8.89k
  while (
I != List.end()8.89k
) {
37
8.41k
    FullSourceLoc diagLoc = I->getLocation();
38
8.41k
    if ((IDs.empty() || // empty means clear all diagnostics in the range.
39
8.41k
         std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) &&
40
3.63k
        !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) &&
41
3.30k
        (diagLoc == range.getEnd() ||
42
8.41k
           
diagLoc.isBeforeInTranslationUnitThan(range.getEnd())2.74k
)) {
43
621
      cleared = true;
44
621
      ListTy::iterator eraseS = I++;
45
621
      if (eraseS->getLevel() != DiagnosticsEngine::Note)
46
970
        
while (596
I != List.end() && 970
I->getLevel() == DiagnosticsEngine::Note884
)
47
374
          ++I;
48
621
      // Clear the diagnostic and any notes following it.
49
621
      I = List.erase(eraseS, I);
50
621
      continue;
51
621
    }
52
7.79k
53
7.79k
    ++I;
54
7.79k
  }
55
484
56
484
  return cleared;
57
484
}
58
59
bool CapturedDiagList::hasDiagnostic(ArrayRef<unsigned> IDs,
60
810
                                     SourceRange range) const {
61
810
  if (range.isInvalid())
62
0
    return false;
63
810
64
810
  ListTy::const_iterator I = List.begin();
65
5.56k
  while (
I != List.end()5.56k
) {
66
5.30k
    FullSourceLoc diagLoc = I->getLocation();
67
5.30k
    if ((IDs.empty() || // empty means any diagnostic in the range.
68
5.30k
         std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) &&
69
1.33k
        !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) &&
70
876
        (diagLoc == range.getEnd() ||
71
5.30k
           
diagLoc.isBeforeInTranslationUnitThan(range.getEnd())382
)) {
72
550
      return true;
73
550
    }
74
4.75k
75
4.75k
    ++I;
76
4.75k
  }
77
810
78
260
  return false;
79
810
}
80
81
51
void CapturedDiagList::reportDiagnostics(DiagnosticsEngine &Diags) const {
82
202
  for (ListTy::const_iterator I = List.begin(), E = List.end(); 
I != E202
;
++I151
)
83
151
    Diags.Report(*I);
84
51
}
85
86
88
bool CapturedDiagList::hasErrors() const {
87
88
  for (ListTy::const_iterator I = List.begin(), E = List.end(); 
I != E88
;
++I0
)
88
43
    
if (43
I->getLevel() >= DiagnosticsEngine::Error43
)
89
43
      return true;
90
88
91
45
  return false;
92
88
}
93
94
namespace {
95
96
class CaptureDiagnosticConsumer : public DiagnosticConsumer {
97
  DiagnosticsEngine &Diags;
98
  DiagnosticConsumer &DiagClient;
99
  CapturedDiagList &CapturedDiags;
100
  bool HasBegunSourceFile;
101
public:
102
  CaptureDiagnosticConsumer(DiagnosticsEngine &diags,
103
                            DiagnosticConsumer &client,
104
                            CapturedDiagList &capturedDiags)
105
    : Diags(diags), DiagClient(client), CapturedDiags(capturedDiags),
106
122
      HasBegunSourceFile(false) { }
107
108
  void BeginSourceFile(const LangOptions &Opts,
109
122
                       const Preprocessor *PP) override {
110
122
    // Pass BeginSourceFile message onto DiagClient on first call.
111
122
    // The corresponding EndSourceFile call will be made from an
112
122
    // explicit call to FinishCapture.
113
122
    if (
!HasBegunSourceFile122
) {
114
122
      DiagClient.BeginSourceFile(Opts, PP);
115
122
      HasBegunSourceFile = true;
116
122
    }
117
122
  }
118
119
122
  void FinishCapture() {
120
122
    // Call EndSourceFile on DiagClient on completion of capture to
121
122
    // enable VerifyDiagnosticConsumer to check diagnostics *after*
122
122
    // it has received the diagnostic list.
123
122
    if (
HasBegunSourceFile122
) {
124
122
      DiagClient.EndSourceFile();
125
122
      HasBegunSourceFile = false;
126
122
    }
127
122
  }
128
129
122
  ~CaptureDiagnosticConsumer() override {
130
122
    assert(!HasBegunSourceFile && "FinishCapture not called!");
131
122
  }
132
133
  void HandleDiagnostic(DiagnosticsEngine::Level level,
134
1.26k
                        const Diagnostic &Info) override {
135
1.26k
    if (DiagnosticIDs::isARCDiagnostic(Info.getID()) ||
136
1.26k
        
level >= DiagnosticsEngine::Error590
||
level == DiagnosticsEngine::Note367
) {
137
1.18k
      if (Info.getLocation().isValid())
138
1.18k
        CapturedDiags.push_back(StoredDiagnostic(level, Info));
139
1.18k
      return;
140
1.18k
    }
141
82
142
82
    // Non-ARC warnings are ignored.
143
82
    Diags.setLastDiagnosticIgnored();
144
82
  }
145
};
146
147
} // end anonymous namespace
148
149
122
static bool HasARCRuntime(CompilerInvocation &origCI) {
150
122
  // This duplicates some functionality from Darwin::AddDeploymentTarget
151
122
  // but this function is well defined, so keep it decoupled from the driver
152
122
  // and avoid unrelated complications.
153
122
  llvm::Triple triple(origCI.getTargetOpts().Triple);
154
122
155
122
  if (triple.isiOS())
156
0
    return triple.getOSMajorVersion() >= 5;
157
122
158
122
  
if (122
triple.isWatchOS()122
)
159
0
    return true;
160
122
161
122
  
if (122
triple.getOS() == llvm::Triple::Darwin122
)
162
94
    return triple.getOSMajorVersion() >= 11;
163
28
164
28
  
if (28
triple.getOS() == llvm::Triple::MacOSX28
) {
165
28
    unsigned Major, Minor, Micro;
166
28
    triple.getOSVersion(Major, Minor, Micro);
167
28
    return Major > 10 || 
(Major == 10 && 28
Minor >= 728
);
168
28
  }
169
0
170
0
  return false;
171
0
}
172
173
static CompilerInvocation *
174
createInvocationForMigration(CompilerInvocation &origCI,
175
122
                             const PCHContainerReader &PCHContainerRdr) {
176
122
  std::unique_ptr<CompilerInvocation> CInvok;
177
122
  CInvok.reset(new CompilerInvocation(origCI));
178
122
  PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
179
122
  if (
!PPOpts.ImplicitPCHInclude.empty()122
) {
180
7
    // We can't use a PCH because it was likely built in non-ARC mode and we
181
7
    // want to parse in ARC. Include the original header.
182
7
    FileManager FileMgr(origCI.getFileSystemOpts());
183
7
    IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
184
7
    IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
185
7
        new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
186
7
                              new IgnoringDiagConsumer()));
187
7
    std::string OriginalFile = ASTReader::getOriginalSourceFile(
188
7
        PPOpts.ImplicitPCHInclude, FileMgr, PCHContainerRdr, *Diags);
189
7
    if (!OriginalFile.empty())
190
7
      PPOpts.Includes.insert(PPOpts.Includes.begin(), OriginalFile);
191
7
    PPOpts.ImplicitPCHInclude.clear();
192
7
  }
193
122
  // FIXME: Get the original header of a PTH as well.
194
122
  CInvok->getPreprocessorOpts().ImplicitPTHInclude.clear();
195
122
  std::string define = getARCMTMacroName();
196
122
  define += '=';
197
122
  CInvok->getPreprocessorOpts().addMacroDef(define);
198
122
  CInvok->getLangOpts()->ObjCAutoRefCount = true;
199
122
  CInvok->getLangOpts()->setGC(LangOptions::NonGC);
200
122
  CInvok->getDiagnosticOpts().ErrorLimit = 0;
201
122
  CInvok->getDiagnosticOpts().PedanticErrors = 0;
202
122
203
122
  // Ignore -Werror flags when migrating.
204
122
  std::vector<std::string> WarnOpts;
205
122
  for (std::vector<std::string>::iterator
206
122
         I = CInvok->getDiagnosticOpts().Warnings.begin(),
207
125
         E = CInvok->getDiagnosticOpts().Warnings.end(); 
I != E125
;
++I3
) {
208
3
    if (!StringRef(*I).startswith("error"))
209
0
      WarnOpts.push_back(*I);
210
3
  }
211
122
  WarnOpts.push_back("error=arc-unsafe-retained-assign");
212
122
  CInvok->getDiagnosticOpts().Warnings = std::move(WarnOpts);
213
122
214
122
  CInvok->getLangOpts()->ObjCWeakRuntime = HasARCRuntime(origCI);
215
122
  CInvok->getLangOpts()->ObjCWeak = CInvok->getLangOpts()->ObjCWeakRuntime;
216
122
217
122
  return CInvok.release();
218
122
}
219
220
static void emitPremigrationErrors(const CapturedDiagList &arcDiags,
221
                                   DiagnosticOptions *diagOpts,
222
1
                                   Preprocessor &PP) {
223
1
  TextDiagnosticPrinter printer(llvm::errs(), diagOpts);
224
1
  IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
225
1
  IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
226
1
      new DiagnosticsEngine(DiagID, diagOpts, &printer,
227
1
                            /*ShouldOwnClient=*/false));
228
1
  Diags->setSourceManager(&PP.getSourceManager());
229
1
  
230
1
  printer.BeginSourceFile(PP.getLangOpts(), &PP);
231
1
  arcDiags.reportDiagnostics(*Diags);
232
1
  printer.EndSourceFile();
233
1
}
234
235
//===----------------------------------------------------------------------===//
236
// checkForManualIssues.
237
//===----------------------------------------------------------------------===//
238
239
bool arcmt::checkForManualIssues(
240
    CompilerInvocation &origCI, const FrontendInputFile &Input,
241
    std::shared_ptr<PCHContainerOperations> PCHContainerOps,
242
    DiagnosticConsumer *DiagClient, bool emitPremigrationARCErrors,
243
51
    StringRef plistOut) {
244
51
  if (!origCI.getLangOpts()->ObjC1)
245
1
    return false;
246
50
247
50
  LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC();
248
50
  bool NoNSAllocReallocError = origCI.getMigratorOpts().NoNSAllocReallocError;
249
50
  bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval;
250
50
251
50
  std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode,
252
50
                                                                     NoFinalizeRemoval);
253
50
  assert(!transforms.empty());
254
50
255
50
  std::unique_ptr<CompilerInvocation> CInvok;
256
50
  CInvok.reset(
257
50
      createInvocationForMigration(origCI, PCHContainerOps->getRawReader()));
258
50
  CInvok->getFrontendOpts().Inputs.clear();
259
50
  CInvok->getFrontendOpts().Inputs.push_back(Input);
260
50
261
50
  CapturedDiagList capturedDiags;
262
50
263
50
  assert(DiagClient);
264
50
  IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
265
50
  IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
266
50
      new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
267
50
                            DiagClient, /*ShouldOwnClient=*/false));
268
50
269
50
  // Filter of all diagnostics.
270
50
  CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
271
50
  Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
272
50
273
50
  std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
274
50
      std::move(CInvok), PCHContainerOps, Diags));
275
50
  if (
!Unit50
) {
276
0
    errRec.FinishCapture();
277
0
    return true;
278
0
  }
279
50
280
50
  // Don't filter diagnostics anymore.
281
50
  Diags->setClient(DiagClient, /*ShouldOwnClient=*/false);
282
50
283
50
  ASTContext &Ctx = Unit->getASTContext();
284
50
285
50
  if (
Diags->hasFatalErrorOccurred()50
) {
286
0
    Diags->Reset();
287
0
    DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
288
0
    capturedDiags.reportDiagnostics(*Diags);
289
0
    DiagClient->EndSourceFile();
290
0
    errRec.FinishCapture();
291
0
    return true;
292
0
  }
293
50
294
50
  
if (50
emitPremigrationARCErrors50
)
295
1
    emitPremigrationErrors(capturedDiags, &origCI.getDiagnosticOpts(),
296
1
                           Unit->getPreprocessor());
297
50
  if (
!plistOut.empty()50
) {
298
1
    SmallVector<StoredDiagnostic, 8> arcDiags;
299
1
    for (CapturedDiagList::iterator
300
2
           I = capturedDiags.begin(), E = capturedDiags.end(); 
I != E2
;
++I1
)
301
1
      arcDiags.push_back(*I);
302
1
    writeARCDiagsToPlist(plistOut, arcDiags,
303
1
                         Ctx.getSourceManager(), Ctx.getLangOpts());
304
1
  }
305
50
306
50
  // After parsing of source files ended, we want to reuse the
307
50
  // diagnostics objects to emit further diagnostics.
308
50
  // We call BeginSourceFile because DiagnosticConsumer requires that 
309
50
  // diagnostics with source range information are emitted only in between
310
50
  // BeginSourceFile() and EndSourceFile().
311
50
  DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
312
50
313
50
  // No macros will be added since we are just checking and we won't modify
314
50
  // source code.
315
50
  std::vector<SourceLocation> ARCMTMacroLocs;
316
50
317
50
  TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
318
50
  MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, capturedDiags,
319
50
                     ARCMTMacroLocs);
320
50
  pass.setNoFinalizeRemoval(NoFinalizeRemoval);
321
50
  if (!NoNSAllocReallocError)
322
48
    Diags->setSeverity(diag::warn_arcmt_nsalloc_realloc, diag::Severity::Error,
323
48
                       SourceLocation());
324
50
325
152
  for (unsigned i=0, e = transforms.size(); 
i != e152
;
++i102
)
326
102
    transforms[i](pass);
327
50
328
50
  capturedDiags.reportDiagnostics(*Diags);
329
50
330
50
  DiagClient->EndSourceFile();
331
50
  errRec.FinishCapture();
332
50
333
39
  return capturedDiags.hasErrors() || testAct.hasReportedErrors();
334
51
}
335
336
//===----------------------------------------------------------------------===//
337
// applyTransformations.
338
//===----------------------------------------------------------------------===//
339
340
static bool
341
applyTransforms(CompilerInvocation &origCI, const FrontendInputFile &Input,
342
                std::shared_ptr<PCHContainerOperations> PCHContainerOps,
343
                DiagnosticConsumer *DiagClient, StringRef outputDir,
344
10
                bool emitPremigrationARCErrors, StringRef plistOut) {
345
10
  if (!origCI.getLangOpts()->ObjC1)
346
0
    return false;
347
10
348
10
  LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC();
349
10
350
10
  // Make sure checking is successful first.
351
10
  CompilerInvocation CInvokForCheck(origCI);
352
10
  if (arcmt::checkForManualIssues(CInvokForCheck, Input, PCHContainerOps,
353
10
                                  DiagClient, emitPremigrationARCErrors,
354
10
                                  plistOut))
355
0
    return true;
356
10
357
10
  CompilerInvocation CInvok(origCI);
358
10
  CInvok.getFrontendOpts().Inputs.clear();
359
10
  CInvok.getFrontendOpts().Inputs.push_back(Input);
360
10
361
10
  MigrationProcess migration(CInvok, PCHContainerOps, DiagClient, outputDir);
362
10
  bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval;
363
10
364
10
  std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode,
365
10
                                                                     NoFinalizeRemoval);
366
10
  assert(!transforms.empty());
367
10
368
30
  for (unsigned i=0, e = transforms.size(); 
i != e30
;
++i20
) {
369
20
    bool err = migration.applyTransform(transforms[i]);
370
20
    if (
err20
)
return true0
;
371
20
  }
372
10
373
10
  IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
374
10
  IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
375
10
      new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
376
10
                            DiagClient, /*ShouldOwnClient=*/false));
377
10
378
10
  if (
outputDir.empty()10
) {
379
2
    origCI.getLangOpts()->ObjCAutoRefCount = true;
380
2
    return migration.getRemapper().overwriteOriginal(*Diags);
381
0
  } else {
382
8
    return migration.getRemapper().flushToDisk(outputDir, *Diags);
383
8
  }
384
0
}
385
386
bool arcmt::applyTransformations(
387
    CompilerInvocation &origCI, const FrontendInputFile &Input,
388
    std::shared_ptr<PCHContainerOperations> PCHContainerOps,
389
2
    DiagnosticConsumer *DiagClient) {
390
2
  return applyTransforms(origCI, Input, PCHContainerOps, DiagClient,
391
2
                         StringRef(), false, StringRef());
392
2
}
393
394
bool arcmt::migrateWithTemporaryFiles(
395
    CompilerInvocation &origCI, const FrontendInputFile &Input,
396
    std::shared_ptr<PCHContainerOperations> PCHContainerOps,
397
    DiagnosticConsumer *DiagClient, StringRef outputDir,
398
8
    bool emitPremigrationARCErrors, StringRef plistOut) {
399
8
  assert(!outputDir.empty() && "Expected output directory path");
400
8
  return applyTransforms(origCI, Input, PCHContainerOps, DiagClient, outputDir,
401
8
                         emitPremigrationARCErrors, plistOut);
402
8
}
403
404
bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > &
405
                                  remap,
406
                              StringRef outputDir,
407
24
                              DiagnosticConsumer *DiagClient) {
408
24
  assert(!outputDir.empty());
409
24
410
24
  IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
411
24
  IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
412
24
      new DiagnosticsEngine(DiagID, new DiagnosticOptions,
413
24
                            DiagClient, /*ShouldOwnClient=*/false));
414
24
415
24
  FileRemapper remapper;
416
24
  bool err = remapper.initFromDisk(outputDir, *Diags,
417
24
                                   /*ignoreIfFilesChanged=*/true);
418
24
  if (err)
419
0
    return true;
420
24
421
24
  PreprocessorOptions PPOpts;
422
24
  remapper.applyMappings(PPOpts);
423
24
  remap = PPOpts.RemappedFiles;
424
24
425
24
  return false;
426
24
}
427
428
429
//===----------------------------------------------------------------------===//
430
// CollectTransformActions.
431
//===----------------------------------------------------------------------===//
432
433
namespace {
434
435
class ARCMTMacroTrackerPPCallbacks : public PPCallbacks {
436
  std::vector<SourceLocation> &ARCMTMacroLocs;
437
438
public:
439
  ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs)
440
72
    : ARCMTMacroLocs(ARCMTMacroLocs) { }
441
442
  void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
443
964
                    SourceRange Range, const MacroArgs *Args) override {
444
964
    if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName())
445
92
      ARCMTMacroLocs.push_back(MacroNameTok.getLocation());
446
964
  }
447
};
448
449
class ARCMTMacroTrackerAction : public ASTFrontendAction {
450
  std::vector<SourceLocation> &ARCMTMacroLocs;
451
452
public:
453
  ARCMTMacroTrackerAction(std::vector<SourceLocation> &ARCMTMacroLocs)
454
72
    : ARCMTMacroLocs(ARCMTMacroLocs) { }
455
456
  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
457
72
                                                 StringRef InFile) override {
458
72
    CI.getPreprocessor().addPPCallbacks(
459
72
               llvm::make_unique<ARCMTMacroTrackerPPCallbacks>(ARCMTMacroLocs));
460
72
    return llvm::make_unique<ASTConsumer>();
461
72
  }
462
};
463
464
class RewritesApplicator : public TransformActions::RewriteReceiver {
465
  Rewriter &rewriter;
466
  MigrationProcess::RewriteListener *Listener;
467
468
public:
469
  RewritesApplicator(Rewriter &rewriter, ASTContext &ctx,
470
                     MigrationProcess::RewriteListener *listener)
471
72
    : rewriter(rewriter), Listener(listener) {
472
72
    if (Listener)
473
0
      Listener->start(ctx);
474
72
  }
475
72
  ~RewritesApplicator() override {
476
72
    if (Listener)
477
0
      Listener->finish();
478
72
  }
479
480
313
  void insert(SourceLocation loc, StringRef text) override {
481
313
    bool err = rewriter.InsertText(loc, text, /*InsertAfter=*/true,
482
313
                                   /*indentNewLines=*/true);
483
313
    if (
!err && 313
Listener313
)
484
0
      Listener->insert(loc, text);
485
313
  }
486
487
402
  void remove(CharSourceRange range) override {
488
402
    Rewriter::RewriteOptions removeOpts;
489
402
    removeOpts.IncludeInsertsAtBeginOfRange = false;
490
402
    removeOpts.IncludeInsertsAtEndOfRange = false;
491
402
    removeOpts.RemoveLineIfEmpty = true;
492
402
493
402
    bool err = rewriter.RemoveText(range, removeOpts);
494
402
    if (
!err && 402
Listener402
)
495
0
      Listener->remove(range);
496
402
  }
497
498
  void increaseIndentation(CharSourceRange range,
499
16
                            SourceLocation parentIndent) override {
500
16
    rewriter.IncreaseIndentation(range, parentIndent);
501
16
  }
502
};
503
504
} // end anonymous namespace.
505
506
/// \brief Anchor for VTable.
507
0
MigrationProcess::RewriteListener::~RewriteListener() { }
508
509
MigrationProcess::MigrationProcess(
510
    const CompilerInvocation &CI,
511
    std::shared_ptr<PCHContainerOperations> PCHContainerOps,
512
    DiagnosticConsumer *diagClient, StringRef outputDir)
513
    : OrigCI(CI), PCHContainerOps(std::move(PCHContainerOps)),
514
35
      DiagClient(diagClient), HadARCErrors(false) {
515
35
  if (
!outputDir.empty()35
) {
516
8
    IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
517
8
    IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
518
8
      new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(),
519
8
                            DiagClient, /*ShouldOwnClient=*/false));
520
8
    Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true);
521
8
  }
522
35
}
523
524
bool MigrationProcess::applyTransform(TransformFn trans,
525
72
                                      RewriteListener *listener) {
526
72
  std::unique_ptr<CompilerInvocation> CInvok;
527
72
  CInvok.reset(
528
72
      createInvocationForMigration(OrigCI, PCHContainerOps->getRawReader()));
529
72
  CInvok->getDiagnosticOpts().IgnoreWarnings = true;
530
72
531
72
  Remapper.applyMappings(CInvok->getPreprocessorOpts());
532
72
533
72
  CapturedDiagList capturedDiags;
534
72
  std::vector<SourceLocation> ARCMTMacroLocs;
535
72
536
72
  assert(DiagClient);
537
72
  IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
538
72
  IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
539
72
      new DiagnosticsEngine(DiagID, new DiagnosticOptions,
540
72
                            DiagClient, /*ShouldOwnClient=*/false));
541
72
542
72
  // Filter of all diagnostics.
543
72
  CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
544
72
  Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
545
72
546
72
  std::unique_ptr<ARCMTMacroTrackerAction> ASTAction;
547
72
  ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs));
548
72
549
72
  std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
550
72
      std::move(CInvok), PCHContainerOps, Diags, ASTAction.get()));
551
72
  if (
!Unit72
) {
552
0
    errRec.FinishCapture();
553
0
    return true;
554
0
  }
555
72
  Unit->setOwnsRemappedFileBuffers(false); // FileRemapper manages that.
556
72
557
38
  HadARCErrors = HadARCErrors || capturedDiags.hasErrors();
558
72
559
72
  // Don't filter diagnostics anymore.
560
72
  Diags->setClient(DiagClient, /*ShouldOwnClient=*/false);
561
72
562
72
  ASTContext &Ctx = Unit->getASTContext();
563
72
564
72
  if (
Diags->hasFatalErrorOccurred()72
) {
565
0
    Diags->Reset();
566
0
    DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
567
0
    capturedDiags.reportDiagnostics(*Diags);
568
0
    DiagClient->EndSourceFile();
569
0
    errRec.FinishCapture();
570
0
    return true;
571
0
  }
572
72
573
72
  // After parsing of source files ended, we want to reuse the
574
72
  // diagnostics objects to emit further diagnostics.
575
72
  // We call BeginSourceFile because DiagnosticConsumer requires that 
576
72
  // diagnostics with source range information are emitted only in between
577
72
  // BeginSourceFile() and EndSourceFile().
578
72
  DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
579
72
580
72
  Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
581
72
  TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
582
72
  MigrationPass pass(Ctx, OrigCI.getLangOpts()->getGC(),
583
72
                     Unit->getSema(), TA, capturedDiags, ARCMTMacroLocs);
584
72
585
72
  trans(pass);
586
72
587
72
  {
588
72
    RewritesApplicator applicator(rewriter, Ctx, listener);
589
72
    TA.applyRewrites(applicator);
590
72
  }
591
72
592
72
  DiagClient->EndSourceFile();
593
72
  errRec.FinishCapture();
594
72
595
72
  if (DiagClient->getNumErrors())
596
0
    return true;
597
72
598
72
  for (Rewriter::buffer_iterator
599
149
        I = rewriter.buffer_begin(), E = rewriter.buffer_end(); 
I != E149
;
++I77
) {
600
77
    FileID FID = I->first;
601
77
    RewriteBuffer &buf = I->second;
602
77
    const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
603
77
    assert(file);
604
77
    std::string newFname = file->getName();
605
77
    newFname += "-trans";
606
77
    SmallString<512> newText;
607
77
    llvm::raw_svector_ostream vecOS(newText);
608
77
    buf.write(vecOS);
609
77
    std::unique_ptr<llvm::MemoryBuffer> memBuf(
610
77
        llvm::MemoryBuffer::getMemBufferCopy(
611
77
            StringRef(newText.data(), newText.size()), newFname));
612
77
    SmallString<64> filePath(file->getName());
613
77
    Unit->getFileManager().FixupRelativePath(filePath);
614
77
    Remapper.remap(filePath.str(), std::move(memBuf));
615
77
  }
616
72
617
72
  return false;
618
72
}