clang: lib/ARCMigrate/ARCMT.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

23#include "llvm/Support/MemoryBuffer.h"

24#include "llvm/TargetParser/Triple.h"

25#include

26using namespace clang;

27using namespace arcmt;

28

31 if (range.isInvalid())

32 return false;

33

34 bool cleared = false;

35 ListTy::iterator I = List.begin();

36 while (I != List.end()) {

38 if ((IDs.empty() ||

39 llvm::is_contained(IDs, I->getID())) &&

41 (diagLoc == range.getEnd() ||

43 cleared = true;

44 ListTy::iterator eraseS = I++;

47 ++I;

48

49 I = List.erase(eraseS, I);

50 continue;

51 }

52

53 ++I;

54 }

55

56 return cleared;

57}

58

61 if (range.isInvalid())

62 return false;

63

64 ListTy::const_iterator I = List.begin();

65 while (I != List.end()) {

67 if ((IDs.empty() ||

68 llvm::is_contained(IDs, I->getID())) &&

70 (diagLoc == range.getEnd() ||

72 return true;

73 }

74

75 ++I;

76 }

77

78 return false;

79}

80

82 for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I)

84}

85

87 for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I)

89 return true;

90

91 return false;

92}

93

94namespace {

95

100 bool HasBegunSourceFile;

101public:

105 : Diags(diags), DiagClient(client), CapturedDiags(capturedDiags),

106 HasBegunSourceFile(false) { }

107

108 void BeginSourceFile(const LangOptions &Opts,

110

111

112

113 if (!HasBegunSourceFile) {

115 HasBegunSourceFile = true;

116 }

117 }

118

119 void FinishCapture() {

120

121

122

123 if (HasBegunSourceFile) {

125 HasBegunSourceFile = false;

126 }

127 }

128

129 ~CaptureDiagnosticConsumer() override {

130 assert(!HasBegunSourceFile && "FinishCapture not called!");

131 }

132

139 return;

140 }

141

142

144 }

145};

146

147}

148

150

151

152

154

155 if (triple.isiOS())

156 return triple.getOSMajorVersion() >= 5;

157

158 if (triple.isWatchOS())

159 return true;

160

161 if (triple.getOS() == llvm::Triple::Darwin)

162 return triple.getOSMajorVersion() >= 11;

163

164 if (triple.getOS() == llvm::Triple::MacOSX) {

165 return triple.getOSVersion() >= VersionTuple(10, 7);

166 }

167

168 return false;

169}

170

174 std::unique_ptr CInvok;

178

179

187 if (!OriginalFile.empty())

188 PPOpts.Includes.insert(PPOpts.Includes.begin(), OriginalFile);

190 }

192 define += '=';

193 CInvok->getPreprocessorOpts().addMacroDef(define);

194 CInvok->getLangOpts().ObjCAutoRefCount = true;

196 CInvok->getDiagnosticOpts().ErrorLimit = 0;

197 CInvok->getDiagnosticOpts().PedanticErrors = 0;

198

199

200 std::vectorstd::string WarnOpts;

201 for (std::vectorstd::string::iterator

202 I = CInvok->getDiagnosticOpts().Warnings.begin(),

203 E = CInvok->getDiagnosticOpts().Warnings.end(); I != E; ++I) {

204 if (!StringRef(*I).starts_with("error"))

205 WarnOpts.push_back(*I);

206 }

207 WarnOpts.push_back("error=arc-unsafe-retained-assign");

208 CInvok->getDiagnosticOpts().Warnings = std::move(WarnOpts);

209

210 CInvok->getLangOpts().ObjCWeakRuntime = HasARCRuntime(origCI);

211 CInvok->getLangOpts().ObjCWeak = CInvok->getLangOpts().ObjCWeakRuntime;

212

213 return CInvok.release();

214}

215

223 false));

225

229}

230

231

232

233

234

237 std::shared_ptr PCHContainerOps,

239 StringRef plistOut) {

241 return false;

242

246

248 NoFinalizeRemoval);

249 assert(!transforms.empty());

250

251 std::unique_ptr CInvok;

252 CInvok.reset(

254 CInvok->getFrontendOpts().Inputs.clear();

255 CInvok->getFrontendOpts().Inputs.push_back(Input);

256

258

259 assert(DiagClient);

263 DiagClient, false));

264

265

266 CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);

267 Diags->setClient(&errRec, false);

268

270 std::move(CInvok), PCHContainerOps, Diags));

271 if (!Unit) {

272 errRec.FinishCapture();

273 return true;

274 }

275

276

277 Diags->setClient(DiagClient, false);

278

279 ASTContext &Ctx = Unit->getASTContext();

280

281 if (Diags->hasFatalErrorOccurred()) {

282 Diags->Reset();

286 errRec.FinishCapture();

287 return true;

288 }

289

290 if (emitPremigrationARCErrors)

292 Unit->getPreprocessor());

293 if (!plistOut.empty()) {

296 I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I)

297 arcDiags.push_back(*I);

300 }

301

302

303

304

305

306

308

309

310

311 std::vector ARCMTMacroLocs;

312

313 TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());

314 MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, capturedDiags,

315 ARCMTMacroLocs);

317 if (!NoNSAllocReallocError)

320

321 for (unsigned i=0, e = transforms.size(); i != e; ++i)

322 transforms[i](pass);

323

325

327 errRec.FinishCapture();

328

330}

331

332

333

334

335

336static bool

338 std::shared_ptr PCHContainerOps,

340 bool emitPremigrationARCErrors, StringRef plistOut) {

342 return false;

343

345

346

349 DiagClient, emitPremigrationARCErrors,

350 plistOut))

351 return true;

352

356

357 MigrationProcess migration(CInvok, PCHContainerOps, DiagClient, outputDir);

359

361 NoFinalizeRemoval);

362 assert(!transforms.empty());

363

364 for (unsigned i=0, e = transforms.size(); i != e; ++i) {

366 if (err) return true;

367 }

368

372 DiagClient, false));

373

374 if (outputDir.empty()) {

375 origCI.getLangOpts().ObjCAutoRefCount = true;

377 } else {

379 }

380}

381

384 std::shared_ptr PCHContainerOps,

386 return applyTransforms(origCI, Input, PCHContainerOps, DiagClient,

387 StringRef(), false, StringRef());

388}

389

392 std::shared_ptr PCHContainerOps,

394 bool emitPremigrationARCErrors, StringRef plistOut) {

395 assert(!outputDir.empty() && "Expected output directory path");

396 return applyTransforms(origCI, Input, PCHContainerOps, DiagClient, outputDir,

397 emitPremigrationARCErrors, plistOut);

398}

399

401 remap,

402 StringRef outputDir,

404 assert(!outputDir.empty());

405

409 DiagClient, false));

410

412 bool err = remapper.initFromDisk(outputDir, *Diags,

413 true);

414 if (err)

415 return true;

416

418 [&](StringRef From, StringRef To) {

419 remap.push_back(std::make_pair(From.str(), To.str()));

420 },

421 [](StringRef, const llvm::MemoryBufferRef &) {});

422

423 return false;

424}

425

426

427

428

429

430

431namespace {

432

433class ARCMTMacroTrackerPPCallbacks : public PPCallbacks {

434 std::vector &ARCMTMacroLocs;

435

436public:

437 ARCMTMacroTrackerPPCallbacks(std::vector &ARCMTMacroLocs)

438 : ARCMTMacroLocs(ARCMTMacroLocs) { }

439

443 ARCMTMacroLocs.push_back(MacroNameTok.getLocation());

444 }

445};

446

448 std::vector &ARCMTMacroLocs;

449

450public:

451 ARCMTMacroTrackerAction(std::vector &ARCMTMacroLocs)

452 : ARCMTMacroLocs(ARCMTMacroLocs) { }

453

454 std::unique_ptr CreateASTConsumer(CompilerInstance &CI,

455 StringRef InFile) override {

457 std::make_unique(ARCMTMacroLocs));

458 return std::make_unique();

459 }

460};

461

465

466public:

469 : rewriter(rewriter), Listener(listener) {

470 if (Listener)

471 Listener->start(ctx);

472 }

473 ~RewritesApplicator() override {

474 if (Listener)

476 }

477

478 void insert(SourceLocation loc, StringRef text) override {

479 bool err = rewriter.InsertText(loc, text, true,

480 true);

481 if (!err && Listener)

482 Listener->insert(loc, text);

483 }

484

490

491 bool err = rewriter.RemoveText(range, removeOpts);

492 if (!err && Listener)

493 Listener->remove(range);

494 }

495

499 }

500};

501

502}

503

504

506

509 std::shared_ptr PCHContainerOps,

511 : OrigCI(CI), PCHContainerOps(std::move(PCHContainerOps)),

513 if (!outputDir.empty()) {

517 DiagClient, false));

518 Remapper.initFromDisk(outputDir, *Diags, true);

519 }

520}

521

524 std::unique_ptr CInvok;

525 CInvok.reset(

527 CInvok->getDiagnosticOpts().IgnoreWarnings = true;

528

529 Remapper.applyMappings(CInvok->getPreprocessorOpts());

530

532 std::vector ARCMTMacroLocs;

533

534 assert(DiagClient);

538 DiagClient, false));

539

540

541 CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);

542 Diags->setClient(&errRec, false);

543

544 std::unique_ptr ASTAction;

545 ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs));

546

548 std::move(CInvok), PCHContainerOps, Diags, ASTAction.get()));

549 if (!Unit) {

550 errRec.FinishCapture();

551 return true;

552 }

553 Unit->setOwnsRemappedFileBuffers(false);

554

556

557

558 Diags->setClient(DiagClient, false);

559

560 ASTContext &Ctx = Unit->getASTContext();

561

562 if (Diags->hasFatalErrorOccurred()) {

563 Diags->Reset();

567 errRec.FinishCapture();

568 return true;

569 }

570

571

572

573

574

575

577

579 TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());

581 Unit->getSema(), TA, capturedDiags, ARCMTMacroLocs);

582

583 trans(pass);

584

585 {

586 RewritesApplicator applicator(rewriter, Ctx, listener);

588 }

589

591 errRec.FinishCapture();

592

594 return true;

595

598 FileID FID = I->first;

599 llvm::RewriteBuffer &buf = I->second;

602 assert(file);

603 std::string newFname = std::string(file->getName());

604 newFname += "-trans";

606 llvm::raw_svector_ostream vecOS(newText);

607 buf.write(vecOS);

608 std::unique_ptrllvm::MemoryBuffer memBuf(

609 llvm::MemoryBuffer::getMemBufferCopy(newText.str(), newFname));

611 Unit->getFileManager().FixupRelativePath(filePath);

612 Remapper.remap(filePath.str(), std::move(memBuf));

613 }

614

615 return false;

616}

static void emitPremigrationErrors(const CapturedDiagList &arcDiags, DiagnosticOptions *diagOpts, Preprocessor &PP)

static CompilerInvocation * createInvocationForMigration(CompilerInvocation &origCI, const PCHContainerReader &PCHContainerRdr)

static bool applyTransforms(CompilerInvocation &origCI, const FrontendInputFile &Input, std::shared_ptr< PCHContainerOperations > PCHContainerOps, DiagnosticConsumer *DiagClient, StringRef outputDir, bool emitPremigrationARCErrors, StringRef plistOut)

static bool HasARCRuntime(CompilerInvocation &origCI)

Defines the clang::FrontendAction interface and various convenience abstract classes (clang::ASTFront...

Defines the clang::Preprocessor interface.

Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...

SourceManager & getSourceManager()

const LangOptions & getLangOpts() const

Abstract base class to use for AST consumer-based frontend actions.

StringRef getOriginalSourceFile()

Retrieve the name of the original source file name for the primary module file.

static ASTUnit * LoadFromCompilerInvocationAction(std::shared_ptr< CompilerInvocation > CI, std::shared_ptr< PCHContainerOperations > PCHContainerOps, IntrusiveRefCntPtr< DiagnosticsEngine > Diags, FrontendAction *Action=nullptr, ASTUnit *Unit=nullptr, bool Persistent=true, StringRef ResourceFilesPath=StringRef(), bool OnlyLocalDecls=false, CaptureDiagsKind CaptureDiagnostics=CaptureDiagsKind::None, unsigned PrecompilePreambleAfterNParses=0, bool CacheCodeCompletionResults=false, bool UserFilesAreVolatile=false, std::unique_ptr< ASTUnit > *ErrAST=nullptr)

Create an ASTUnit from a source file, via a CompilerInvocation object, by invoking the optionally pro...

Represents a character-granular source range.

CompilerInstance - Helper class for managing a single instance of the Clang compiler.

Preprocessor & getPreprocessor() const

Return the current preprocessor.

Helper class for holding the data necessary to invoke the compiler.

MigratorOptions & getMigratorOpts()

LangOptions & getLangOpts()

Mutable getters.

FrontendOptions & getFrontendOpts()

FileSystemOptions & getFileSystemOpts()

TargetOptions & getTargetOpts()

DiagnosticOptions & getDiagnosticOpts()

Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...

virtual void EndSourceFile()

Callback to inform the diagnostic client that processing of a source file has ended.

unsigned getNumErrors() const

virtual void BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP=nullptr)

Callback to inform the diagnostic client that processing of a source file is beginning.

Used for handling and querying diagnostic IDs.

static bool isARCDiagnostic(unsigned DiagID)

Return true if a given diagnostic falls into an ARC diagnostic category.

Options for controlling the compiler diagnostics engine.

A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine a...

const SourceLocation & getLocation() const

Concrete class used by the front-end to report problems and issues.

DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)

Issue the message to the client.

void setLastDiagnosticIgnored(bool Ignored)

Pretend that the last diagnostic issued was ignored, so any subsequent notes will be suppressed,...

Level

The level of the diagnostic, after it has been through mapping.

StringRef getName() const

The name of this FileEntry.

An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...

Implements support for file system lookup, file system caching, and directory search management.

An input file for the front end.

SmallVector< FrontendInputFile, 0 > Inputs

The input files and their types.

A SourceLocation and its associated SourceManager.

bool isBeforeInTranslationUnitThan(SourceLocation Loc) const

Determines the order of 2 source locations in the translation unit.

StringRef getName() const

Return the actual identifier string.

A diagnostic client that ignores all diagnostics.

Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...

MacroArgs - An instance of this class captures information about the formal arguments specified to a ...

A description of the current definition of a macro.

unsigned NoNSAllocReallocError

unsigned NoFinalizeRemoval

This abstract interface provides operations for unwrapping containers for serialized ASTs (precompile...

This interface provides a way to observe the actions of the preprocessor as it does its thing.

PreprocessorOptions - This class is used for passing the various options used in preprocessor initial...

std::vector< std::string > Includes

std::string ImplicitPCHInclude

The implicit PCH included at the start of the translation unit, or empty.

Engages in a tight little dance with the lexer to efficiently preprocess tokens.

void addPPCallbacks(std::unique_ptr< PPCallbacks > C)

SourceManager & getSourceManager() const

const LangOptions & getLangOpts() const

Rewriter - This is the main interface to the rewrite buffers.

std::map< FileID, llvm::RewriteBuffer >::iterator buffer_iterator

bool InsertText(SourceLocation Loc, StringRef Str, bool InsertAfter=true, bool indentNewLines=false)

InsertText - Insert the specified string at the specified location in the original buffer.

bool RemoveText(SourceLocation Start, unsigned Length, RewriteOptions opts=RewriteOptions())

RemoveText - Remove the specified text region.

buffer_iterator buffer_end()

buffer_iterator buffer_begin()

bool IncreaseIndentation(CharSourceRange range, SourceLocation parentIndent)

Increase indentation for the lines between the given source range.

Encodes a location in the source.

bool isValid() const

Return true if this is a valid SourceLocation object.

OptionalFileEntryRef getFileEntryRefForID(FileID FID) const

Returns the FileEntryRef for the provided FileID.

A trivial tuple used to represent a source range.

Represents a diagnostic in a form that can be retained until its corresponding source manager is dest...

std::string Triple

The name of the target triple to compile for.

void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) override

Callback to inform the diagnostic client that processing of a source file is beginning.

void EndSourceFile() override

Callback to inform the diagnostic client that processing of a source file has ended.

Token - This structure provides full information about a lexed token.

IdentifierInfo * getIdentifierInfo() const

SourceLocation getLocation() const

Return a source location identifier for the specified offset in the current file.

bool clearDiagnostic(ArrayRef< unsigned > IDs, SourceRange range)

void push_back(const StoredDiagnostic &diag)

bool hasDiagnostic(ArrayRef< unsigned > IDs, SourceRange range) const

ListTy::const_iterator iterator

void reportDiagnostics(DiagnosticsEngine &diags) const

void forEachMapping(llvm::function_ref< void(StringRef, StringRef)> CaptureFile, llvm::function_ref< void(StringRef, const llvm::MemoryBufferRef &)> CaptureBuffer) const

Iterate through all the mappings.

bool flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag)

void remap(StringRef filePath, std::unique_ptr< llvm::MemoryBuffer > memBuf)

void applyMappings(PreprocessorOptions &PPOpts) const

bool initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag, bool ignoreIfFilesChanged)

bool overwriteOriginal(DiagnosticsEngine &Diag, StringRef outputDir=StringRef())

void setNoFinalizeRemoval(bool val)

virtual void start(ASTContext &Ctx)

virtual void remove(CharSourceRange range)

virtual ~RewriteListener()

Anchor for VTable.

virtual void insert(SourceLocation loc, StringRef text)

FileRemapper & getRemapper()

MigrationProcess(CompilerInvocation &CI, std::shared_ptr< PCHContainerOperations > PCHContainerOps, DiagnosticConsumer *diagClient, StringRef outputDir=StringRef())

bool applyTransform(TransformFn trans, RewriteListener *listener=nullptr)

void applyRewrites(RewriteReceiver &receiver)

bool hasReportedErrors() const

bool getFileRemappings(std::vector< std::pair< std::string, std::string > > &remap, StringRef outputDir, DiagnosticConsumer *DiagClient)

Get the set of file remappings from the outputDir path that migrateWithTemporaryFiles produced.

static StringRef getARCMTMacroName()

std::vector< TransformFn > getAllTransformations(LangOptions::GCMode OrigGCMode, bool NoFinalizeRemoval)

void writeARCDiagsToPlist(const std::string &outPath, ArrayRef< StoredDiagnostic > diags, SourceManager &SM, const LangOptions &LangOpts)

bool migrateWithTemporaryFiles(CompilerInvocation &origCI, const FrontendInputFile &Input, std::shared_ptr< PCHContainerOperations > PCHContainerOps, DiagnosticConsumer *DiagClient, StringRef outputDir, bool emitPremigrationARCErrors, StringRef plistOut)

Applies automatic modifications and produces temporary files and metadata into the outputDir path.

void(* TransformFn)(MigrationPass &pass)

bool applyTransformations(CompilerInvocation &origCI, const FrontendInputFile &Input, std::shared_ptr< PCHContainerOperations > PCHContainerOps, DiagnosticConsumer *DiagClient)

Works similar to checkForManualIssues but instead of checking, it applies automatic modifications to ...

bool checkForManualIssues(CompilerInvocation &CI, const FrontendInputFile &Input, std::shared_ptr< PCHContainerOperations > PCHContainerOps, DiagnosticConsumer *DiagClient, bool emitPremigrationARCErrors=false, StringRef plistOut=StringRef())

Creates an AST with the provided CompilerInvocation but with these changes: -if a PCH/PTH is set,...

@ Error

Present this diagnostic as an error.

ASTEdit remove(RangeSelector S)

Removes the source selected by S.

The JSON file list parser is used to communicate input to InstallAPI.

bool IncludeInsertsAtBeginOfRange

Given a source range, true to include previous inserts at the beginning of the range as part of the r...

bool IncludeInsertsAtEndOfRange

Given a source range, true to include previous inserts at the end of the range as part of the range i...

bool RemoveLineIfEmpty

If true and removing some text leaves a blank line also remove the empty line (false by default).