14 #include "llvm/ADT/DenseSet.h" 16 using namespace clang;
17 using namespace arcmt;
28 class TransformActionsImpl {
36 Act_Insert, Act_InsertAfterToken,
37 Act_Remove, Act_RemoveStmt,
38 Act_Replace, Act_ReplaceText,
39 Act_IncreaseIndentation,
47 StringRef Text1, Text2;
52 std::vector<ActionData> CachedActions;
54 enum RangeComparison {
69 assert(beginLoc.
isValid() && endLoc.isValid());
72 End =
FullSourceLoc(getLocForEndOfToken(endLoc, srcMgr, PP), srcMgr);
80 RangeComparison compareWith(
const CharRange &RHS)
const {
83 if (RHS.End.isBeforeInTranslationUnitThan(Begin))
86 !RHS.End.isBeforeInTranslationUnitThan(End))
87 return Range_Contained;
89 RHS.End.isBeforeInTranslationUnitThan(End))
90 return Range_Contains;
92 return Range_ExtendsBegin;
94 return Range_ExtendsEnd;
106 typedef std::map<FullSourceLoc, TextsVec, FullSourceLoc::BeforeThanCompare>
111 std::list<CharRange> Removals;
115 std::vector<std::pair<CharRange, SourceLocation> > IndentationRanges;
118 llvm::StringMap<bool> UniqueText;
123 : CapturedDiags(capturedDiags), Ctx(ctx), PP(PP), IsInTransaction(
false) { }
127 void startTransaction();
128 bool commitTransaction();
129 void abortTransaction();
131 bool isInTransaction()
const {
return IsInTransaction; }
136 void removeStmt(
Stmt *S);
139 void replaceStmt(
Stmt *S, StringRef
text);
141 StringRef replacementText);
159 void commitRemoveStmt(
Stmt *S);
162 StringRef replacementText);
172 StringRef getUniqueText(StringRef
text);
183 void TransformActionsImpl::startTransaction() {
184 assert(!IsInTransaction &&
185 "Cannot start a transaction in the middle of another one");
186 IsInTransaction =
true;
189 bool TransformActionsImpl::commitTransaction() {
190 assert(IsInTransaction &&
"No transaction started");
192 if (CachedActions.empty()) {
193 IsInTransaction =
false;
198 bool AllActionsPossible =
true;
199 for (
unsigned i = 0, e = CachedActions.size(); i != e; ++i) {
200 ActionData &act = CachedActions[i];
203 if (!canInsert(act.Loc))
204 AllActionsPossible =
false;
206 case Act_InsertAfterToken:
207 if (!canInsertAfterToken(act.Loc))
208 AllActionsPossible =
false;
211 if (!canRemoveRange(act.R1))
212 AllActionsPossible =
false;
216 if (!canRemoveRange(act.S->getSourceRange()))
217 AllActionsPossible =
false;
220 if (!canReplaceRange(act.R1, act.R2))
221 AllActionsPossible =
false;
223 case Act_ReplaceText:
224 if (!canReplaceText(act.Loc, act.Text1))
225 AllActionsPossible =
false;
227 case Act_IncreaseIndentation:
230 case Act_ClearDiagnostic:
234 if (!AllActionsPossible)
238 if (!AllActionsPossible) {
243 for (
unsigned i = 0, e = CachedActions.size(); i != e; ++i) {
244 ActionData &act = CachedActions[i];
247 commitInsert(act.Loc, act.Text1);
249 case Act_InsertAfterToken:
250 commitInsertAfterToken(act.Loc, act.Text1);
253 commitRemove(act.R1);
256 commitRemoveStmt(act.S);
259 commitReplace(act.R1, act.R2);
261 case Act_ReplaceText:
262 commitReplaceText(act.Loc, act.Text1, act.Text2);
264 case Act_IncreaseIndentation:
265 commitIncreaseIndentation(act.R1, act.Loc);
267 case Act_ClearDiagnostic:
268 commitClearDiagnostic(act.DiagIDs, act.R1);
273 CachedActions.clear();
274 IsInTransaction =
false;
278 void TransformActionsImpl::abortTransaction() {
279 assert(IsInTransaction &&
"No transaction started");
280 CachedActions.clear();
281 IsInTransaction =
false;
285 assert(IsInTransaction &&
"Actions only allowed during a transaction");
286 text = getUniqueText(text);
288 data.Kind = Act_Insert;
291 CachedActions.push_back(data);
294 void TransformActionsImpl::insertAfterToken(
SourceLocation loc, StringRef text) {
295 assert(IsInTransaction &&
"Actions only allowed during a transaction");
296 text = getUniqueText(text);
298 data.Kind = Act_InsertAfterToken;
301 CachedActions.push_back(data);
305 assert(IsInTransaction &&
"Actions only allowed during a transaction");
307 data.Kind = Act_Remove;
309 CachedActions.push_back(data);
312 void TransformActionsImpl::removeStmt(
Stmt *S) {
313 assert(IsInTransaction &&
"Actions only allowed during a transaction");
315 data.Kind = Act_RemoveStmt;
316 if (
auto *E = dyn_cast<Expr>(S))
317 S = E->IgnoreImplicit();
319 CachedActions.push_back(data);
322 void TransformActionsImpl::replace(
SourceRange range, StringRef text) {
323 assert(IsInTransaction &&
"Actions only allowed during a transaction");
324 text = getUniqueText(text);
329 void TransformActionsImpl::replace(
SourceRange range,
331 assert(IsInTransaction &&
"Actions only allowed during a transaction");
333 data.Kind = Act_Replace;
335 data.R2 = replacementRange;
336 CachedActions.push_back(data);
339 void TransformActionsImpl::replaceText(
SourceLocation loc, StringRef text,
340 StringRef replacementText) {
341 text = getUniqueText(text);
342 replacementText = getUniqueText(replacementText);
344 data.Kind = Act_ReplaceText;
347 data.Text2 = replacementText;
348 CachedActions.push_back(data);
351 void TransformActionsImpl::replaceStmt(
Stmt *S, StringRef text) {
352 assert(IsInTransaction &&
"Actions only allowed during a transaction");
353 text = getUniqueText(text);
358 void TransformActionsImpl::increaseIndentation(
SourceRange range,
361 assert(IsInTransaction &&
"Actions only allowed during a transaction");
363 data.Kind = Act_IncreaseIndentation;
365 data.Loc = parentIndent;
366 CachedActions.push_back(data);
371 assert(IsInTransaction &&
"Actions only allowed during a transaction");
376 data.Kind = Act_ClearDiagnostic;
378 data.DiagIDs.append(IDs.begin(), IDs.end());
379 CachedActions.push_back(data);
396 bool TransformActionsImpl::canInsertAfterToken(
SourceLocation loc) {
409 bool TransformActionsImpl::canRemoveRange(
SourceRange range) {
410 return canInsert(range.
getBegin()) && canInsertAfterToken(range.
getEnd());
413 bool TransformActionsImpl::canReplaceRange(
SourceRange range,
415 return canRemoveRange(range) && canRemoveRange(replacementRange);
418 bool TransformActionsImpl::canReplaceText(
SourceLocation loc, StringRef text) {
429 bool invalidTemp =
false;
430 StringRef file = SM.
getBufferData(locInfo.first, &invalidTemp);
434 return file.substr(locInfo.second).startswith(text);
437 void TransformActionsImpl::commitInsert(
SourceLocation loc, StringRef text) {
438 addInsertion(loc, text);
441 void TransformActionsImpl::commitInsertAfterToken(
SourceLocation loc,
446 void TransformActionsImpl::commitRemove(
SourceRange range) {
450 void TransformActionsImpl::commitRemoveStmt(
Stmt *S) {
452 if (StmtRemovals.count(S))
455 if (
Expr *E = dyn_cast<Expr>(S)) {
456 commitRemove(E->getSourceRange());
461 StmtRemovals.insert(S);
464 void TransformActionsImpl::commitReplace(
SourceRange range,
468 assert(comp == Range_Contained);
469 if (comp != Range_Contained)
476 getLocForEndOfToken(replacementRange.
getEnd(),
482 StringRef replacementText) {
489 commitInsert(loc, replacementText);
492 void TransformActionsImpl::commitIncreaseIndentation(
SourceRange range,
495 IndentationRanges.push_back(
506 void TransformActionsImpl::addInsertion(
SourceLocation loc, StringRef text) {
509 for (
const CharRange &I : llvm::reverse(Removals)) {
512 if (I.Begin.isBeforeInTranslationUnitThan(loc))
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;
544 case Range_ExtendsBegin:
545 newRange.End = RI->End;
548 case Range_ExtendsEnd:
549 RI->End = newRange.End;
554 Removals.insert(Removals.begin(), newRange);
557 void 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);
567 for (std::vector<std::pair<CharRange, SourceLocation> >::
iterator 568 I = IndentationRanges.begin(), E = IndentationRanges.end(); I!=E; ++I) {
574 for (std::list<CharRange>::iterator
575 I = Removals.begin(), E = Removals.end(); I != E; ++I) {
584 StringRef TransformActionsImpl::getUniqueText(StringRef text) {
585 return UniqueText.insert(std::make_pair(text,
false)).first->first();
608 : Diags(diag), CapturedDiags(capturedDiags) {
609 Impl =
new TransformActionsImpl(capturedDiags, ctx, PP);
613 delete static_cast<TransformActionsImpl*
>(Impl);
630 static_cast<TransformActionsImpl*
>(Impl)->
insert(loc, text);
639 static_cast<TransformActionsImpl*
>(Impl)->
remove(range);
643 static_cast<TransformActionsImpl*
>(Impl)->
removeStmt(S);
647 static_cast<TransformActionsImpl*
>(Impl)->
replace(range, text);
652 static_cast<TransformActionsImpl*
>(Impl)->
replace(range, replacementRange);
656 static_cast<TransformActionsImpl*
>(Impl)->
replaceStmt(S, text);
660 StringRef replacementText) {
661 static_cast<TransformActionsImpl*
>(Impl)->
replaceText(loc, text,
673 return static_cast<TransformActionsImpl*
>(Impl)->
clearDiagnostic(IDs, range);
677 static_cast<TransformActionsImpl*
>(Impl)->
applyRewrites(receiver);
682 assert(!static_cast<TransformActionsImpl *>(Impl)->isInTransaction() &&
683 "Errors should be emitted out of a transaction");
689 report(loc, diag::err_mt_message, range) << message;
694 report(loc, diag::warn_mt_message, range) << message;
699 report(loc, diag::note_mt_message, range) << message;
Defines the clang::ASTContext interface.
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
Stmt - This represents one statement.
Defines the SourceManager interface.
static StringRef getARCMTMacroName()
static CharSourceRange getTokenRange(SourceRange R)
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
bool hasDiagnostic(ArrayRef< unsigned > IDs, SourceRange range) const
StringRef getBufferData(FileID FID, bool *Invalid=nullptr) const
Return a StringRef to the source buffer data for the specified FileID.
SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)
Computes the source location just past the end of the token at this source location.
SourceLocation getBegin() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceLocation getBeginLoc() const LLVM_READONLY
bool clearDiagnostic(ArrayRef< unsigned > IDs, SourceRange range)
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
Concrete class used by the front-end to report problems and issues.
A little helper class used to produce diagnostics.
This represents one expression.
Represents a character-granular source range.
static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y)
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
Defines the clang::Preprocessor interface.
SourceLocation getEnd() const
static CharSourceRange getCharRange(SourceRange R)
bool isBeforeInTranslationUnitThan(SourceLocation Loc) const
Determines the order of 2 source locations in the translation unit.
Encodes a location in the source.
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.
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token.
Dataflow Directional Tag Classes.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getEnd() const
CharSourceRange getExpansionRange(SourceLocation Loc) const
Given a SourceLocation object, return the range of tokens covered by the expansion in the ultimate fi...
SourceManager & getSourceManager()
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
A SourceLocation and its associated SourceManager.
A trivial tuple used to represent a source range.
SourceLocation getBegin() const
This class handles loading and caching of source files into memory.
std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.