Coverage Report

Created: 2019-07-24 05:18

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