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

1

2

3

4

5

6

7

8

14#include "llvm/ADT/DenseSet.h"

15#include

16using namespace clang;

17using namespace arcmt;

18

19namespace {

20

21

22

23

24

25

26

27

28class TransformActionsImpl {

32

33 bool IsInTransaction;

34

36 Act_Insert, Act_InsertAfterToken,

37 Act_Remove, Act_RemoveStmt,

38 Act_Replace, Act_ReplaceText,

39 Act_IncreaseIndentation,

40 Act_ClearDiagnostic

41 };

42

43 struct ActionData {

47 StringRef Text1, Text2;

50 };

51

52 std::vector CachedActions;

53

54 enum RangeComparison {

55 Range_Before,

56 Range_After,

57 Range_Contains,

58 Range_Contained,

59 Range_ExtendsBegin,

60 Range_ExtendsEnd

61 };

62

63

64 struct CharRange {

66

69 assert(beginLoc.isValid() && endLoc.isValid());

70 if (range.isTokenRange()) {

72 End = FullSourceLoc(getLocForEndOfToken(endLoc, srcMgr, PP), srcMgr);

73 } else {

76 }

78 }

79

80 RangeComparison compareWith(const CharRange &RHS) const {

81 if (End.isBeforeInTranslationUnitThan(RHS.Begin))

82 return Range_Before;

83 if (RHS.End.isBeforeInTranslationUnitThan(Begin))

84 return Range_After;

85 if (Begin.isBeforeInTranslationUnitThan(RHS.Begin) &&

86 !RHS.End.isBeforeInTranslationUnitThan(End))

87 return Range_Contained;

88 if (Begin.isBeforeInTranslationUnitThan(RHS.Begin) &&

89 RHS.End.isBeforeInTranslationUnitThan(End))

90 return Range_Contains;

91 if (Begin.isBeforeInTranslationUnitThan(RHS.Begin))

92 return Range_ExtendsBegin;

93 else

94 return Range_ExtendsEnd;

95 }

96

101 SrcMgr, PP));

102 }

103 };

104

106 typedef std::map<FullSourceLoc, TextsVec, FullSourceLoc::BeforeThanCompare>

107 InsertsMap;

108 InsertsMap Inserts;

109

110

111 std::list Removals;

112

113 llvm::DenseSet<Stmt *> StmtRemovals;

114

115 std::vector<std::pair<CharRange, SourceLocation> > IndentationRanges;

116

117

118 llvm::StringMap UniqueText;

119

120public:

123 : CapturedDiags(capturedDiags), Ctx(ctx), PP(PP), IsInTransaction(false) { }

124

125 ASTContext &getASTContext() { return Ctx; }

126

127 void startTransaction();

128 bool commitTransaction();

129 void abortTransaction();

130

131 bool isInTransaction() const { return IsInTransaction; }

132

134 void insertAfterToken(SourceLocation loc, StringRef text);

136 void removeStmt(Stmt *S);

137 void replace(SourceRange range, StringRef text);

139 void replaceStmt(Stmt *S, StringRef text);

141 StringRef replacementText);

142 void increaseIndentation(SourceRange range,

144

146

148

149private:

154 bool canReplaceText(SourceLocation loc, StringRef text);

155

156 void commitInsert(SourceLocation loc, StringRef text);

157 void commitInsertAfterToken(SourceLocation loc, StringRef text);

159 void commitRemoveStmt(Stmt *S);

161 void commitReplaceText(SourceLocation loc, StringRef text,

162 StringRef replacementText);

165

167 void addInsertion(SourceLocation loc, StringRef text);

168

169

170

171

172 StringRef getUniqueText(StringRef text);

173

174

175

176

179};

180

181}

182

183void TransformActionsImpl::startTransaction() {

184 assert(!IsInTransaction &&

185 "Cannot start a transaction in the middle of another one");

186 IsInTransaction = true;

187}

188

189bool TransformActionsImpl::commitTransaction() {

190 assert(IsInTransaction && "No transaction started");

191

192 if (CachedActions.empty()) {

193 IsInTransaction = false;

194 return false;

195 }

196

197

198 bool AllActionsPossible = true;

199 for (unsigned i = 0, e = CachedActions.size(); i != e; ++i) {

200 ActionData &act = CachedActions[i];

201 switch (act.Kind) {

202 case Act_Insert:

203 if (!canInsert(act.Loc))

204 AllActionsPossible = false;

205 break;

206 case Act_InsertAfterToken:

207 if (!canInsertAfterToken(act.Loc))

208 AllActionsPossible = false;

209 break;

210 case Act_Remove:

211 if (!canRemoveRange(act.R1))

212 AllActionsPossible = false;

213 break;

214 case Act_RemoveStmt:

215 assert(act.S);

216 if (!canRemoveRange(act.S->getSourceRange()))

217 AllActionsPossible = false;

218 break;

219 case Act_Replace:

220 if (!canReplaceRange(act.R1, act.R2))

221 AllActionsPossible = false;

222 break;

223 case Act_ReplaceText:

224 if (!canReplaceText(act.Loc, act.Text1))

225 AllActionsPossible = false;

226 break;

227 case Act_IncreaseIndentation:

228

229 break;

230 case Act_ClearDiagnostic:

231

232 break;

233 }

234 if (!AllActionsPossible)

235 break;

236 }

237

238 if (!AllActionsPossible) {

239 abortTransaction();

240 return true;

241 }

242

243 for (unsigned i = 0, e = CachedActions.size(); i != e; ++i) {

244 ActionData &act = CachedActions[i];

245 switch (act.Kind) {

246 case Act_Insert:

247 commitInsert(act.Loc, act.Text1);

248 break;

249 case Act_InsertAfterToken:

250 commitInsertAfterToken(act.Loc, act.Text1);

251 break;

252 case Act_Remove:

253 commitRemove(act.R1);

254 break;

255 case Act_RemoveStmt:

256 commitRemoveStmt(act.S);

257 break;

258 case Act_Replace:

259 commitReplace(act.R1, act.R2);

260 break;

261 case Act_ReplaceText:

262 commitReplaceText(act.Loc, act.Text1, act.Text2);

263 break;

264 case Act_IncreaseIndentation:

265 commitIncreaseIndentation(act.R1, act.Loc);

266 break;

267 case Act_ClearDiagnostic:

268 commitClearDiagnostic(act.DiagIDs, act.R1);

269 break;

270 }

271 }

272

273 CachedActions.clear();

274 IsInTransaction = false;

275 return false;

276}

277

278void TransformActionsImpl::abortTransaction() {

279 assert(IsInTransaction && "No transaction started");

280 CachedActions.clear();

281 IsInTransaction = false;

282}

283

284void TransformActionsImpl::insert(SourceLocation loc, StringRef text) {

285 assert(IsInTransaction && "Actions only allowed during a transaction");

286 text = getUniqueText(text);

287 ActionData data;

288 data.Kind = Act_Insert;

289 data.Loc = loc;

290 data.Text1 = text;

291 CachedActions.push_back(data);

292}

293

294void TransformActionsImpl::insertAfterToken(SourceLocation loc, StringRef text) {

295 assert(IsInTransaction && "Actions only allowed during a transaction");

296 text = getUniqueText(text);

297 ActionData data;

298 data.Kind = Act_InsertAfterToken;

299 data.Loc = loc;

300 data.Text1 = text;

301 CachedActions.push_back(data);

302}

303

304void TransformActionsImpl::remove(SourceRange range) {

305 assert(IsInTransaction && "Actions only allowed during a transaction");

306 ActionData data;

307 data.Kind = Act_Remove;

309 CachedActions.push_back(data);

310}

311

312void TransformActionsImpl::removeStmt(Stmt *S) {

313 assert(IsInTransaction && "Actions only allowed during a transaction");

314 ActionData data;

315 data.Kind = Act_RemoveStmt;

316 if (auto *E = dyn_cast(S))

318 data.S = S;

319 CachedActions.push_back(data);

320}

321

322void TransformActionsImpl::replace(SourceRange range, StringRef text) {

323 assert(IsInTransaction && "Actions only allowed during a transaction");

324 text = getUniqueText(text);

326 insert(range.getBegin(), text);

327}

328

329void TransformActionsImpl::replace(SourceRange range,

331 assert(IsInTransaction && "Actions only allowed during a transaction");

332 ActionData data;

333 data.Kind = Act_Replace;

335 data.R2 = replacementRange;

336 CachedActions.push_back(data);

337}

338

339void TransformActionsImpl::replaceText(SourceLocation loc, StringRef text,

340 StringRef replacementText) {

341 text = getUniqueText(text);

342 replacementText = getUniqueText(replacementText);

343 ActionData data;

344 data.Kind = Act_ReplaceText;

345 data.Loc = loc;

346 data.Text1 = text;

347 data.Text2 = replacementText;

348 CachedActions.push_back(data);

349}

350

351void TransformActionsImpl::replaceStmt(Stmt *S, StringRef text) {

352 assert(IsInTransaction && "Actions only allowed during a transaction");

353 text = getUniqueText(text);

354 insert(S->getBeginLoc(), text);

355 removeStmt(S);

356}

357

358void TransformActionsImpl::increaseIndentation(SourceRange range,

360 if (range.isInvalid()) return;

361 assert(IsInTransaction && "Actions only allowed during a transaction");

362 ActionData data;

363 data.Kind = Act_IncreaseIndentation;

365 data.Loc = parentIndent;

366 CachedActions.push_back(data);

367}

368

371 assert(IsInTransaction && "Actions only allowed during a transaction");

373 return false;

374

375 ActionData data;

376 data.Kind = Act_ClearDiagnostic;

378 data.DiagIDs.append(IDs.begin(), IDs.end());

379 CachedActions.push_back(data);

380 return true;

381}

382

383bool TransformActionsImpl::canInsert(SourceLocation loc) {

385 return false;

386

388 if (SM.isInSystemHeader(SM.getExpansionLoc(loc)))

389 return false;

390

392 return true;

394}

395

396bool TransformActionsImpl::canInsertAfterToken(SourceLocation loc) {

398 return false;

399

401 if (SM.isInSystemHeader(SM.getExpansionLoc(loc)))

402 return false;

403

405 return true;

407}

408

409bool TransformActionsImpl::canRemoveRange(SourceRange range) {

410 return canInsert(range.getBegin()) && canInsertAfterToken(range.getEnd());

411}

412

413bool TransformActionsImpl::canReplaceRange(SourceRange range,

415 return canRemoveRange(range) && canRemoveRange(replacementRange);

416}

417

418bool TransformActionsImpl::canReplaceText(SourceLocation loc, StringRef text) {

419 if (!canInsert(loc))

420 return false;

421

423 loc = SM.getExpansionLoc(loc);

424

425

426 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);

427

428

429 bool invalidTemp = false;

430 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);

431 if (invalidTemp)

432 return false;

433

434 return file.substr(locInfo.second).starts_with(text);

435}

436

437void TransformActionsImpl::commitInsert(SourceLocation loc, StringRef text) {

438 addInsertion(loc, text);

439}

440

441void TransformActionsImpl::commitInsertAfterToken(SourceLocation loc,

442 StringRef text) {

443 addInsertion(getLocForEndOfToken(loc, Ctx.getSourceManager(), PP), text);

444}

445

446void TransformActionsImpl::commitRemove(SourceRange range) {

448}

449

450void TransformActionsImpl::commitRemoveStmt(Stmt *S) {

451 assert(S);

452 if (StmtRemovals.count(S))

453 return;

454

455 if (Expr *E = dyn_cast(S)) {

458 } else

459 commitRemove(S->getSourceRange());

460

461 StmtRemovals.insert(S);

462}

463

464void TransformActionsImpl::commitReplace(SourceRange range,

466 RangeComparison comp = CharRange::compare(replacementRange, range,

468 assert(comp == Range_Contained);

469 if (comp != Range_Contained)

470 return;

471 if (range.getBegin() != replacementRange.getBegin())

473 replacementRange.getBegin()));

474 if (replacementRange.getEnd() != range.getEnd())

476 getLocForEndOfToken(replacementRange.getEnd(),

478 range.getEnd()));

479}

480void TransformActionsImpl::commitReplaceText(SourceLocation loc,

481 StringRef text,

482 StringRef replacementText) {

484 loc = SM.getExpansionLoc(loc);

485

487

489 commitInsert(loc, replacementText);

490}

491

492void TransformActionsImpl::commitIncreaseIndentation(SourceRange range,

495 IndentationRanges.push_back(

497 SM, PP),

498 SM.getExpansionLoc(parentIndent)));

499}

500

501void TransformActionsImpl::commitClearDiagnostic(ArrayRef IDs,

504}

505

506void TransformActionsImpl::addInsertion(SourceLocation loc, StringRef text) {

508 loc = SM.getExpansionLoc(loc);

509 for (const CharRange &I : llvm::reverse(Removals)) {

510 if (SM.isBeforeInTranslationUnit(loc, I.End))

511 break;

512 if (I.Begin.isBeforeInTranslationUnitThan(loc))

513 return;

514 }

515

517}

518

519void TransformActionsImpl::addRemoval(CharSourceRange range) {

521 if (newRange.Begin == newRange.End)

522 return;

523

524 Inserts.erase(Inserts.upper_bound(newRange.Begin),

525 Inserts.lower_bound(newRange.End));

526

527 std::list::iterator I = Removals.end();

528 while (I != Removals.begin()) {

529 std::list::iterator RI = I;

530 --RI;

531 RangeComparison comp = newRange.compareWith(*RI);

532 switch (comp) {

533 case Range_Before:

534 --I;

535 break;

536 case Range_After:

537 Removals.insert(I, newRange);

538 return;

539 case Range_Contained:

540 return;

541 case Range_Contains:

542 RI->End = newRange.End;

543 [[fallthrough]];

544 case Range_ExtendsBegin:

545 newRange.End = RI->End;

546 Removals.erase(RI);

547 break;

548 case Range_ExtendsEnd:

549 RI->End = newRange.End;

550 return;

551 }

552 }

553

554 Removals.insert(Removals.begin(), newRange);

555}

556

557void TransformActionsImpl::applyRewrites(

559 for (InsertsMap::iterator I = Inserts.begin(), E = Inserts.end(); I!=E; ++I) {

561 for (TextsVec::iterator

562 TI = I->second.begin(), TE = I->second.end(); TI != TE; ++TI) {

563 receiver.insert(loc, *TI);

564 }

565 }

566

567 for (std::vector<std::pair<CharRange, SourceLocation> >::iterator

568 I = IndentationRanges.begin(), E = IndentationRanges.end(); I!=E; ++I) {

570 I->first.End);

572 }

573

574 for (std::list::iterator

575 I = Removals.begin(), E = Removals.end(); I != E; ++I) {

577 receiver.remove(range);

578 }

579}

580

581

582

583

584StringRef TransformActionsImpl::getUniqueText(StringRef text) {

585 return UniqueText.insert(std::make_pair(text, false)).first->first();

586}

587

588

589

590

599 }

601}

602

604

608 : Diags(diag), CapturedDiags(capturedDiags) {

609 Impl = new TransformActionsImpl(capturedDiags, ctx, PP);

610}

611

613 delete static_cast<TransformActionsImpl*>(Impl);

614}

615

617 static_cast<TransformActionsImpl*>(Impl)->startTransaction();

618}

619

621 return static_cast<TransformActionsImpl*>(Impl)->commitTransaction();

622}

623

625 static_cast<TransformActionsImpl*>(Impl)->abortTransaction();

626}

627

628

630 static_cast<TransformActionsImpl*>(Impl)->insert(loc, text);

631}

632

634 StringRef text) {

635 static_cast<TransformActionsImpl*>(Impl)->insertAfterToken(loc, text);

636}

637

639 static_cast<TransformActionsImpl*>(Impl)->remove(range);

640}

641

643 static_cast<TransformActionsImpl*>(Impl)->removeStmt(S);

644}

645

647 static_cast<TransformActionsImpl*>(Impl)->replace(range, text);

648}

649

652 static_cast<TransformActionsImpl*>(Impl)->replace(range, replacementRange);

653}

654

656 static_cast<TransformActionsImpl*>(Impl)->replaceStmt(S, text);

657}

658

660 StringRef replacementText) {

661 static_cast<TransformActionsImpl*>(Impl)->replaceText(loc, text,

662 replacementText);

663}

664

668 parentIndent);

669}

670

673 return static_cast<TransformActionsImpl*>(Impl)->clearDiagnostic(IDs, range);

674}

675

677 static_cast<TransformActionsImpl*>(Impl)->applyRewrites(receiver);

678}

679

682 assert(!static_cast<TransformActionsImpl *>(Impl)->isInTransaction() &&

683 "Errors should be emitted out of a transaction");

684 return Diags.Report(loc, diagId) << range;

685}

686

689 report(loc, diag::err_mt_message, range) << message;

690}

691

694 report(loc, diag::warn_mt_message, range) << message;

695}

696

699 report(loc, diag::note_mt_message, range) << message;

700}

Defines the clang::ASTContext interface.

static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y)

Defines the clang::Preprocessor interface.

Defines the SourceManager interface.

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

SourceManager & getSourceManager()

Represents a character-granular source range.

static CharSourceRange getCharRange(SourceRange R)

static CharSourceRange getTokenRange(SourceRange R)

SourceLocation getEnd() const

A little helper class used to produce diagnostics.

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

DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)

Issue the message to the client.

This represents one expression.

Expr * IgnoreImplicit() LLVM_READONLY

Skip past any implicit AST nodes which might surround this expression until reaching a fixed point.

A SourceLocation and its associated SourceManager.

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

bool isAtStartOfMacroExpansion(SourceLocation loc, SourceLocation *MacroBegin=nullptr) const

Returns true if the given MacroID location points at the first token of the macro expansion.

bool isAtEndOfMacroExpansion(SourceLocation loc, SourceLocation *MacroEnd=nullptr) const

Returns true if the given MacroID location points at the last token of the macro expansion.

SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)

Computes the source location just past the end of the token at this source location.

Encodes a location in the source.

bool isValid() const

Return true if this is a valid SourceLocation object.

SourceLocation getLocWithOffset(IntTy Offset) const

Return a source location with the specified offset from this SourceLocation.

This class handles loading and caching of source files into memory.

SourceLocation getExpansionLoc(SourceLocation Loc) const

Given a SourceLocation object Loc, return the expansion location referenced by the ID.

A trivial tuple used to represent a source range.

SourceLocation getEnd() const

SourceLocation getBegin() const

Stmt - This represents one statement.

SourceRange getSourceRange() const LLVM_READONLY

SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...

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

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

virtual ~RewriteReceiver()

virtual void insert(SourceLocation loc, StringRef text)=0

virtual void remove(CharSourceRange range)=0

virtual void increaseIndentation(CharSourceRange range, SourceLocation parentIndent)=0

void increaseIndentation(SourceRange range, SourceLocation parentIndent)

DiagnosticBuilder report(SourceLocation loc, unsigned diagId, SourceRange range=SourceRange())

void replaceStmt(Stmt *S, StringRef text)

void insertAfterToken(SourceLocation loc, StringRef text)

void insert(SourceLocation loc, StringRef text)

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

void remove(SourceRange range)

void applyRewrites(RewriteReceiver &receiver)

void reportNote(StringRef note, SourceLocation loc, SourceRange range=SourceRange())

void reportWarning(StringRef warning, SourceLocation loc, SourceRange range=SourceRange())

void reportError(StringRef error, SourceLocation loc, SourceRange range=SourceRange())

void replace(SourceRange range, StringRef text)

void replaceText(SourceLocation loc, StringRef text, StringRef replacementText)

TransformActions(DiagnosticsEngine &diag, CapturedDiagList &capturedDiags, ASTContext &ctx, Preprocessor &PP)

static StringRef getARCMTMacroName()

RangeSelector range(RangeSelector Begin, RangeSelector End)

DEPRECATED. Use enclose.

ASTEdit remove(RangeSelector S)

Removes the source selected by S.

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