15 #include "llvm/ADT/DenseSet.h"
17 using namespace clang;
18 using namespace arcmt;
29 class TransformActionsImpl {
37 Act_Insert, Act_InsertAfterToken,
38 Act_Remove, Act_RemoveStmt,
39 Act_Replace, Act_ReplaceText,
40 Act_IncreaseIndentation,
48 StringRef Text1, Text2;
53 std::vector<ActionData> CachedActions;
55 enum RangeComparison {
70 assert(beginLoc.
isValid() && endLoc.isValid());
78 assert(Begin.isValid() && End.
isValid());
81 RangeComparison compareWith(
const CharRange &RHS)
const {
84 if (RHS.End.isBeforeInTranslationUnitThan(Begin))
86 if (!Begin.isBeforeInTranslationUnitThan(RHS.Begin) &&
87 !RHS.End.isBeforeInTranslationUnitThan(End))
88 return Range_Contained;
89 if (Begin.isBeforeInTranslationUnitThan(RHS.Begin) &&
90 RHS.End.isBeforeInTranslationUnitThan(End))
91 return Range_Contains;
92 if (Begin.isBeforeInTranslationUnitThan(RHS.Begin))
93 return Range_ExtendsBegin;
95 return Range_ExtendsEnd;
107 typedef std::map<FullSourceLoc, TextsVec, FullSourceLoc::BeforeThanCompare>
112 std::list<CharRange> Removals;
116 std::vector<std::pair<CharRange, SourceLocation> > IndentationRanges;
119 llvm::StringMap<bool> UniqueText;
124 : CapturedDiags(capturedDiags), Ctx(ctx), PP(PP), IsInTransaction(
false) { }
128 void startTransaction();
129 bool commitTransaction();
130 void abortTransaction();
132 bool isInTransaction()
const {
return IsInTransaction; }
137 void removeStmt(
Stmt *
S);
140 void replaceStmt(
Stmt *
S, StringRef
text);
142 StringRef replacementText);
160 void commitRemoveStmt(
Stmt *
S);
163 StringRef replacementText);
173 StringRef getUniqueText(StringRef
text);
184 void TransformActionsImpl::startTransaction() {
185 assert(!IsInTransaction &&
186 "Cannot start a transaction in the middle of another one");
187 IsInTransaction =
true;
190 bool TransformActionsImpl::commitTransaction() {
191 assert(IsInTransaction &&
"No transaction started");
193 if (CachedActions.empty()) {
194 IsInTransaction =
false;
199 bool AllActionsPossible =
true;
200 for (
unsigned i = 0, e = CachedActions.size(); i != e; ++i) {
201 ActionData &act = CachedActions[i];
204 if (!canInsert(act.Loc))
205 AllActionsPossible =
false;
207 case Act_InsertAfterToken:
208 if (!canInsertAfterToken(act.Loc))
209 AllActionsPossible =
false;
212 if (!canRemoveRange(act.R1))
213 AllActionsPossible =
false;
217 if (!canRemoveRange(act.S->getSourceRange()))
218 AllActionsPossible =
false;
221 if (!canReplaceRange(act.R1, act.R2))
222 AllActionsPossible =
false;
224 case Act_ReplaceText:
225 if (!canReplaceText(act.Loc, act.Text1))
226 AllActionsPossible =
false;
228 case Act_IncreaseIndentation:
231 case Act_ClearDiagnostic:
235 if (!AllActionsPossible)
239 if (!AllActionsPossible) {
244 for (
unsigned i = 0, e = CachedActions.size(); i != e; ++i) {
245 ActionData &act = CachedActions[i];
248 commitInsert(act.Loc, act.Text1);
250 case Act_InsertAfterToken:
251 commitInsertAfterToken(act.Loc, act.Text1);
254 commitRemove(act.R1);
257 commitRemoveStmt(act.S);
260 commitReplace(act.R1, act.R2);
262 case Act_ReplaceText:
263 commitReplaceText(act.Loc, act.Text1, act.Text2);
265 case Act_IncreaseIndentation:
266 commitIncreaseIndentation(act.R1, act.Loc);
268 case Act_ClearDiagnostic:
269 commitClearDiagnostic(act.DiagIDs, act.R1);
274 CachedActions.clear();
275 IsInTransaction =
false;
279 void TransformActionsImpl::abortTransaction() {
280 assert(IsInTransaction &&
"No transaction started");
281 CachedActions.clear();
282 IsInTransaction =
false;
286 assert(IsInTransaction &&
"Actions only allowed during a transaction");
287 text = getUniqueText(text);
289 data.Kind = Act_Insert;
292 CachedActions.push_back(data);
295 void TransformActionsImpl::insertAfterToken(
SourceLocation loc, StringRef text) {
296 assert(IsInTransaction &&
"Actions only allowed during a transaction");
297 text = getUniqueText(text);
299 data.Kind = Act_InsertAfterToken;
302 CachedActions.push_back(data);
305 void TransformActionsImpl::remove(
SourceRange range) {
306 assert(IsInTransaction &&
"Actions only allowed during a transaction");
308 data.Kind = Act_Remove;
310 CachedActions.push_back(data);
313 void TransformActionsImpl::removeStmt(
Stmt *
S) {
314 assert(IsInTransaction &&
"Actions only allowed during a transaction");
316 data.Kind = Act_RemoveStmt;
317 data.S = S->IgnoreImplicit();
318 CachedActions.push_back(data);
321 void TransformActionsImpl::replace(
SourceRange range, StringRef text) {
322 assert(IsInTransaction &&
"Actions only allowed during a transaction");
323 text = getUniqueText(text);
328 void TransformActionsImpl::replace(
SourceRange range,
330 assert(IsInTransaction &&
"Actions only allowed during a transaction");
332 data.Kind = Act_Replace;
334 data.R2 = replacementRange;
335 CachedActions.push_back(data);
338 void TransformActionsImpl::replaceText(
SourceLocation loc, StringRef text,
339 StringRef replacementText) {
340 text = getUniqueText(text);
341 replacementText = getUniqueText(replacementText);
343 data.Kind = Act_ReplaceText;
346 data.Text2 = replacementText;
347 CachedActions.push_back(data);
350 void TransformActionsImpl::replaceStmt(
Stmt *S, StringRef text) {
351 assert(IsInTransaction &&
"Actions only allowed during a transaction");
352 text = getUniqueText(text);
353 insert(S->getLocStart(),
text);
357 void TransformActionsImpl::increaseIndentation(
SourceRange range,
360 assert(IsInTransaction &&
"Actions only allowed during a transaction");
362 data.Kind = Act_IncreaseIndentation;
364 data.Loc = parentIndent;
365 CachedActions.push_back(data);
370 assert(IsInTransaction &&
"Actions only allowed during a transaction");
371 if (!CapturedDiags.hasDiagnostic(IDs, range))
375 data.Kind = Act_ClearDiagnostic;
377 data.DiagIDs.append(IDs.begin(), IDs.end());
378 CachedActions.push_back(data);
395 bool TransformActionsImpl::canInsertAfterToken(
SourceLocation loc) {
408 bool TransformActionsImpl::canRemoveRange(
SourceRange range) {
409 return canInsert(range.
getBegin()) && canInsertAfterToken(range.
getEnd());
412 bool TransformActionsImpl::canReplaceRange(
SourceRange range,
414 return canRemoveRange(range) && canRemoveRange(replacementRange);
417 bool TransformActionsImpl::canReplaceText(
SourceLocation loc, StringRef text) {
428 bool invalidTemp =
false;
429 StringRef file = SM.
getBufferData(locInfo.first, &invalidTemp);
433 return file.substr(locInfo.second).startswith(text);
436 void TransformActionsImpl::commitInsert(
SourceLocation loc, StringRef text) {
437 addInsertion(loc, text);
440 void TransformActionsImpl::commitInsertAfterToken(
SourceLocation loc,
442 addInsertion(getLocForEndOfToken(loc, Ctx.getSourceManager(), PP), text);
445 void TransformActionsImpl::commitRemove(
SourceRange range) {
449 void TransformActionsImpl::commitRemoveStmt(
Stmt *S) {
451 if (StmtRemovals.count(S))
454 if (
Expr *E = dyn_cast<Expr>(S)) {
455 commitRemove(E->getSourceRange());
458 commitRemove(S->getSourceRange());
460 StmtRemovals.insert(S);
463 void TransformActionsImpl::commitReplace(
SourceRange range,
466 Ctx.getSourceManager(), PP);
467 assert(comp == Range_Contained);
468 if (comp != Range_Contained)
475 getLocForEndOfToken(replacementRange.
getEnd(),
476 Ctx.getSourceManager(), PP),
481 StringRef replacementText) {
488 commitInsert(loc, replacementText);
491 void TransformActionsImpl::commitIncreaseIndentation(
SourceRange range,
494 IndentationRanges.push_back(
502 CapturedDiags.clearDiagnostic(IDs, range);
505 void TransformActionsImpl::addInsertion(
SourceLocation loc, StringRef text) {
508 for (std::list<CharRange>::reverse_iterator
509 I = Removals.rbegin(), E = Removals.rend(); I != E; ++I) {
512 if (I->Begin.isBeforeInTranslationUnitThan(loc))
520 CharRange newRange(range, Ctx.getSourceManager(), PP);
521 if (newRange.Begin == newRange.End)
524 Inserts.erase(Inserts.upper_bound(newRange.Begin),
525 Inserts.lower_bound(newRange.End));
527 std::list<CharRange>::iterator I = Removals.end();
528 while (I != Removals.begin()) {
529 std::list<CharRange>::iterator RI = I;
531 RangeComparison comp = newRange.compareWith(*RI);
537 Removals.insert(I, newRange);
539 case Range_Contained:
542 RI->End = newRange.End;
543 case Range_ExtendsBegin:
544 newRange.End = RI->End;
547 case Range_ExtendsEnd:
548 RI->End = newRange.End;
553 Removals.insert(Removals.begin(), newRange);
556 void TransformActionsImpl::applyRewrites(
558 for (InsertsMap::iterator I = Inserts.begin(), E = Inserts.end(); I!=E; ++I) {
560 for (TextsVec::iterator
561 TI = I->second.begin(), TE = I->second.end(); TI != TE; ++TI) {
562 receiver.
insert(loc, *TI);
566 for (std::vector<std::pair<CharRange, SourceLocation> >::iterator
567 I = IndentationRanges.begin(), E = IndentationRanges.end(); I!=E; ++I) {
573 for (std::list<CharRange>::iterator
574 I = Removals.begin(), E = Removals.end(); I != E; ++I) {
583 StringRef TransformActionsImpl::getUniqueText(StringRef text) {
584 return UniqueText.insert(std::make_pair(text,
false)).first->first();
603 : Diags(diag), CapturedDiags(capturedDiags) {
604 Impl =
new TransformActionsImpl(capturedDiags, ctx, PP);
608 delete static_cast<TransformActionsImpl*
>(Impl);
625 static_cast<TransformActionsImpl*
>(Impl)->
insert(loc, text);
634 static_cast<TransformActionsImpl*
>(Impl)->
remove(range);
638 static_cast<TransformActionsImpl*
>(Impl)->
removeStmt(S);
642 static_cast<TransformActionsImpl*
>(Impl)->
replace(range, text);
647 static_cast<TransformActionsImpl*
>(Impl)->
replace(range, replacementRange);
651 static_cast<TransformActionsImpl*
>(Impl)->
replaceStmt(S, text);
655 StringRef replacementText) {
656 static_cast<TransformActionsImpl*
>(Impl)->
replaceText(loc, text,
668 return static_cast<TransformActionsImpl*
>(Impl)->
clearDiagnostic(IDs, range);
672 static_cast<TransformActionsImpl*
>(Impl)->
applyRewrites(receiver);
677 assert(!static_cast<TransformActionsImpl *>(Impl)->isInTransaction() &&
678 "Errors should be emitted out of a transaction");
679 return Diags.
Report(loc, diagId) << range;
684 report(loc, diag::err_mt_message, range) << message;
689 report(loc, diag::warn_mt_message, range) << message;
694 report(loc, diag::note_mt_message, range) << message;
Defines the clang::ASTContext interface.
SourceLocation getEnd() const
SourceLocation getBegin() const
Defines the SourceManager interface.
static StringRef getARCMTMacroName()
static CharSourceRange getTokenRange(SourceRange R)
bool isAtStartOfMacroExpansion(SourceLocation loc, SourceLocation *MacroBegin=nullptr) const
Returns true if the given MacroID location points at the first token of the macro expansion...
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)
Computes the source location just past the end of the token at this source location.
StringRef getBufferData(FileID FID, bool *Invalid=nullptr) const
Return a StringRef to the source buffer data for the specified FileID.
std::pair< SourceLocation, SourceLocation > getExpansionRange(SourceLocation Loc) const
Given a SourceLocation object, return the range of tokens covered by the expansion in the ultimate fi...
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
Concrete class used by the front-end to report problems and issues.
bool isAtEndOfMacroExpansion(SourceLocation loc, SourceLocation *MacroEnd=nullptr) const
Returns true if the given MacroID location points at the last token of the macro expansion.
A little helper class used to produce diagnostics.
Represents a character-granular source range.
static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y)
SourceLocation getEnd() const
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
Defines the clang::Preprocessor interface.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
static CharSourceRange getCharRange(SourceRange R)
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token. Return false if the end o...
Encodes a location in the source. The SourceManager can decode this to get at the full include stack...
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getBegin() const
bool isBeforeInTranslationUnitThan(SourceLocation Loc) const
Determines the order of 2 source locations in the translation unit.
A SourceLocation and its associated SourceManager.
A trivial tuple used to represent a source range.
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
This class handles loading and caching of source files into memory.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.