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 (.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 (.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.