TransformActions.cpp revision 7e5e5f4cc36fe50f46ad76dca7a266434c94f475
1//===--- ARCMT.cpp - Migration to ARC mode --------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "Internals.h"
11#include "clang/AST/Expr.h"
12#include "clang/Lex/Preprocessor.h"
13#include "clang/Basic/SourceManager.h"
14#include "llvm/ADT/DenseSet.h"
15#include <map>
16
17using namespace clang;
18using namespace arcmt;
19using llvm::StringRef;
20
21namespace {
22
23/// \brief Collects transformations and merges them before applying them with
24/// with applyRewrites(). E.g. if the same source range
25/// is requested to be removed twice, only one rewriter remove will be invoked.
26/// Rewrites happen in "transactions"; if one rewrite in the transaction cannot
27/// be done (e.g. it resides in a macro) all rewrites in the transaction are
28/// aborted.
29/// FIXME: "Transactional" rewrites support should be baked in the Rewriter.
30class TransformActionsImpl {
31  CapturedDiagList &CapturedDiags;
32  ASTContext &Ctx;
33  Preprocessor &PP;
34
35  bool IsInTransaction;
36
37  enum ActionKind {
38    Act_Insert, Act_InsertAfterToken,
39    Act_Remove, Act_RemoveStmt,
40    Act_Replace, Act_ReplaceText,
41    Act_IncreaseIndentation,
42    Act_ClearDiagnostic
43  };
44
45  struct ActionData {
46    ActionKind Kind;
47    SourceLocation Loc;
48    SourceRange R1, R2;
49    llvm::StringRef Text1, Text2;
50    Stmt *S;
51    llvm::SmallVector<unsigned, 2> DiagIDs;
52  };
53
54  std::vector<ActionData> CachedActions;
55
56  enum RangeComparison {
57    Range_Before,
58    Range_After,
59    Range_Contains,
60    Range_Contained,
61    Range_ExtendsBegin,
62    Range_ExtendsEnd
63  };
64
65  /// \brief A range to remove. It is a character range.
66  struct CharRange {
67    FullSourceLoc Begin, End;
68
69    CharRange(CharSourceRange range, SourceManager &srcMgr, Preprocessor &PP) {
70      SourceLocation beginLoc = range.getBegin(), endLoc = range.getEnd();
71      assert(beginLoc.isValid() && endLoc.isValid());
72      if (range.isTokenRange()) {
73        Begin = FullSourceLoc(srcMgr.getInstantiationLoc(beginLoc), srcMgr);
74        End = FullSourceLoc(getLocForEndOfToken(endLoc, srcMgr, PP), srcMgr);
75      } else {
76        Begin = FullSourceLoc(srcMgr.getInstantiationLoc(beginLoc), srcMgr);
77        End = FullSourceLoc(srcMgr.getInstantiationLoc(endLoc), srcMgr);
78      }
79      assert(Begin.isValid() && End.isValid());
80    }
81
82    RangeComparison compareWith(const CharRange &RHS) const {
83      if (End.isBeforeInTranslationUnitThan(RHS.Begin))
84        return Range_Before;
85      if (RHS.End.isBeforeInTranslationUnitThan(Begin))
86        return Range_After;
87      if (!Begin.isBeforeInTranslationUnitThan(RHS.Begin) &&
88          !RHS.End.isBeforeInTranslationUnitThan(End))
89        return Range_Contained;
90      if (Begin.isBeforeInTranslationUnitThan(RHS.Begin) &&
91          RHS.End.isBeforeInTranslationUnitThan(End))
92        return Range_Contains;
93      if (Begin.isBeforeInTranslationUnitThan(RHS.Begin))
94        return Range_ExtendsBegin;
95      else
96        return Range_ExtendsEnd;
97    }
98
99    static RangeComparison compare(SourceRange LHS, SourceRange RHS,
100                                   SourceManager &SrcMgr, Preprocessor &PP) {
101      return CharRange(CharSourceRange::getTokenRange(LHS), SrcMgr, PP)
102                  .compareWith(CharRange(CharSourceRange::getTokenRange(RHS),
103                                            SrcMgr, PP));
104    }
105  };
106
107  typedef llvm::SmallVector<StringRef, 2> TextsVec;
108  typedef std::map<FullSourceLoc, TextsVec, FullSourceLoc::BeforeThanCompare>
109      InsertsMap;
110  InsertsMap Inserts;
111  /// \brief A list of ranges to remove. They are always sorted and they never
112  /// intersect with each other.
113  std::list<CharRange> Removals;
114
115  llvm::DenseSet<Stmt *> StmtRemovals;
116
117  std::vector<std::pair<CharRange, SourceLocation> > IndentationRanges;
118
119  /// \brief Keeps text passed to transformation methods.
120  llvm::StringMap<bool> UniqueText;
121
122public:
123  TransformActionsImpl(CapturedDiagList &capturedDiags,
124                       ASTContext &ctx, Preprocessor &PP)
125    : CapturedDiags(capturedDiags), Ctx(ctx), PP(PP), IsInTransaction(false) { }
126
127  void startTransaction();
128  bool commitTransaction();
129  void abortTransaction();
130
131  bool isInTransaction() const { return IsInTransaction; }
132
133  void insert(SourceLocation loc, llvm::StringRef text);
134  void insertAfterToken(SourceLocation loc, llvm::StringRef text);
135  void remove(SourceRange range);
136  void removeStmt(Stmt *S);
137  void replace(SourceRange range, llvm::StringRef text);
138  void replace(SourceRange range, SourceRange replacementRange);
139  void replaceStmt(Stmt *S, llvm::StringRef text);
140  void replaceText(SourceLocation loc, llvm::StringRef text,
141                   llvm::StringRef replacementText);
142  void increaseIndentation(SourceRange range,
143                           SourceLocation parentIndent);
144
145  bool clearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range);
146
147  void applyRewrites(TransformActions::RewriteReceiver &receiver);
148
149private:
150  bool canInsert(SourceLocation loc);
151  bool canInsertAfterToken(SourceLocation loc);
152  bool canRemoveRange(SourceRange range);
153  bool canReplaceRange(SourceRange range, SourceRange replacementRange);
154  bool canReplaceText(SourceLocation loc, llvm::StringRef text);
155
156  void commitInsert(SourceLocation loc, StringRef text);
157  void commitInsertAfterToken(SourceLocation loc, StringRef text);
158  void commitRemove(SourceRange range);
159  void commitRemoveStmt(Stmt *S);
160  void commitReplace(SourceRange range, SourceRange replacementRange);
161  void commitReplaceText(SourceLocation loc, llvm::StringRef text,
162                         llvm::StringRef replacementText);
163  void commitIncreaseIndentation(SourceRange range,SourceLocation parentIndent);
164  void commitClearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range);
165
166  void addRemoval(CharSourceRange range);
167  void addInsertion(SourceLocation loc, StringRef text);
168
169  /// \brief Stores text passed to the transformation methods to keep the string
170  /// "alive". Since the vast majority of text will be the same, we also unique
171  /// the strings using a StringMap.
172  StringRef getUniqueText(StringRef text);
173
174  /// \brief Computes the source location just past the end of the token at
175  /// the given source location. If the location points at a macro, the whole
176  /// macro instantiation is skipped.
177  static SourceLocation getLocForEndOfToken(SourceLocation loc,
178                                            SourceManager &SM,Preprocessor &PP);
179};
180
181} // anonymous namespace
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  // Verify that all actions are possible otherwise abort the whole transaction.
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      // This is not important, we don't care if it will fail.
229      break;
230    case Act_ClearDiagnostic:
231      // We are just checking source rewrites.
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;
308  data.R1 = range;
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  data.S = S->IgnoreImplicit(); // important for uniquing
317  CachedActions.push_back(data);
318}
319
320void TransformActionsImpl::replace(SourceRange range, StringRef text) {
321  assert(IsInTransaction && "Actions only allowed during a transaction");
322  text = getUniqueText(text);
323  remove(range);
324  insert(range.getBegin(), text);
325}
326
327void TransformActionsImpl::replace(SourceRange range,
328                                   SourceRange replacementRange) {
329  assert(IsInTransaction && "Actions only allowed during a transaction");
330  ActionData data;
331  data.Kind = Act_Replace;
332  data.R1 = range;
333  data.R2 = replacementRange;
334  CachedActions.push_back(data);
335}
336
337void TransformActionsImpl::replaceText(SourceLocation loc, StringRef text,
338                                       StringRef replacementText) {
339  text = getUniqueText(text);
340  replacementText = getUniqueText(replacementText);
341  ActionData data;
342  data.Kind = Act_ReplaceText;
343  data.Loc = loc;
344  data.Text1 = text;
345  data.Text2 = replacementText;
346  CachedActions.push_back(data);
347}
348
349void TransformActionsImpl::replaceStmt(Stmt *S, StringRef text) {
350  assert(IsInTransaction && "Actions only allowed during a transaction");
351  text = getUniqueText(text);
352  insert(S->getLocStart(), text);
353  removeStmt(S);
354}
355
356void TransformActionsImpl::increaseIndentation(SourceRange range,
357                                               SourceLocation parentIndent) {
358  if (range.isInvalid()) return;
359  assert(IsInTransaction && "Actions only allowed during a transaction");
360  ActionData data;
361  data.Kind = Act_IncreaseIndentation;
362  data.R1 = range;
363  data.Loc = parentIndent;
364  CachedActions.push_back(data);
365}
366
367bool TransformActionsImpl::clearDiagnostic(llvm::ArrayRef<unsigned> IDs,
368                                           SourceRange range) {
369  assert(IsInTransaction && "Actions only allowed during a transaction");
370  if (!CapturedDiags.hasDiagnostic(IDs, range))
371    return false;
372
373  ActionData data;
374  data.Kind = Act_ClearDiagnostic;
375  data.R1 = range;
376  data.DiagIDs.append(IDs.begin(), IDs.end());
377  CachedActions.push_back(data);
378  return true;
379}
380
381bool TransformActionsImpl::canInsert(SourceLocation loc) {
382  if (loc.isInvalid())
383    return false;
384
385  SourceManager &SM = Ctx.getSourceManager();
386  if (SM.isInSystemHeader(SM.getInstantiationLoc(loc)))
387    return false;
388
389  if (loc.isFileID())
390    return true;
391  return SM.isAtStartOfMacroInstantiation(loc, Ctx.getLangOptions());
392}
393
394bool TransformActionsImpl::canInsertAfterToken(SourceLocation loc) {
395  if (loc.isInvalid())
396    return false;
397
398  SourceManager &SM = Ctx.getSourceManager();
399  if (SM.isInSystemHeader(SM.getInstantiationLoc(loc)))
400    return false;
401
402  if (loc.isFileID())
403    return true;
404  return SM.isAtEndOfMacroInstantiation(loc, Ctx.getLangOptions());
405}
406
407bool TransformActionsImpl::canRemoveRange(SourceRange range) {
408  return canInsert(range.getBegin()) && canInsertAfterToken(range.getEnd());
409}
410
411bool TransformActionsImpl::canReplaceRange(SourceRange range,
412                                           SourceRange replacementRange) {
413  return canRemoveRange(range) && canRemoveRange(replacementRange);
414}
415
416bool TransformActionsImpl::canReplaceText(SourceLocation loc, StringRef text) {
417  if (!canInsert(loc))
418    return false;
419
420  SourceManager &SM = Ctx.getSourceManager();
421  loc = SM.getInstantiationLoc(loc);
422
423  // Break down the source location.
424  std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
425
426  // Try to load the file buffer.
427  bool invalidTemp = false;
428  llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
429  if (invalidTemp)
430    return false;
431
432  return file.substr(locInfo.second).startswith(text);
433}
434
435void TransformActionsImpl::commitInsert(SourceLocation loc, StringRef text) {
436  addInsertion(loc, text);
437}
438
439void TransformActionsImpl::commitInsertAfterToken(SourceLocation loc,
440                                                  StringRef text) {
441  addInsertion(getLocForEndOfToken(loc, Ctx.getSourceManager(), PP), text);
442}
443
444void TransformActionsImpl::commitRemove(SourceRange range) {
445  addRemoval(CharSourceRange::getTokenRange(range));
446}
447
448void TransformActionsImpl::commitRemoveStmt(Stmt *S) {
449  assert(S);
450  if (StmtRemovals.count(S))
451    return; // already removed.
452
453  if (Expr *E = dyn_cast<Expr>(S)) {
454    commitRemove(E->getSourceRange());
455    commitInsert(E->getSourceRange().getBegin(), getARCMTMacroName());
456  } else
457    commitRemove(S->getSourceRange());
458
459  StmtRemovals.insert(S);
460}
461
462void TransformActionsImpl::commitReplace(SourceRange range,
463                                         SourceRange replacementRange) {
464  RangeComparison comp = CharRange::compare(replacementRange, range,
465                                               Ctx.getSourceManager(), PP);
466  assert(comp == Range_Contained);
467  if (comp != Range_Contained)
468    return; // Although we asserted, be extra safe for release build.
469  if (range.getBegin() != replacementRange.getBegin())
470    addRemoval(CharSourceRange::getCharRange(range.getBegin(),
471                                             replacementRange.getBegin()));
472  if (replacementRange.getEnd() != range.getEnd())
473    addRemoval(CharSourceRange::getTokenRange(
474                                  getLocForEndOfToken(replacementRange.getEnd(),
475                                                      Ctx.getSourceManager(), PP),
476                                  range.getEnd()));
477}
478void TransformActionsImpl::commitReplaceText(SourceLocation loc,
479                                             StringRef text,
480                                             StringRef replacementText) {
481  SourceManager &SM = Ctx.getSourceManager();
482  loc = SM.getInstantiationLoc(loc);
483  // canReplaceText already checked if loc points at text.
484  SourceLocation afterText = loc.getFileLocWithOffset(text.size());
485
486  addRemoval(CharSourceRange::getCharRange(loc, afterText));
487  commitInsert(loc, replacementText);
488}
489
490void TransformActionsImpl::commitIncreaseIndentation(SourceRange range,
491                                                  SourceLocation parentIndent) {
492  SourceManager &SM = Ctx.getSourceManager();
493  IndentationRanges.push_back(
494                 std::make_pair(CharRange(CharSourceRange::getTokenRange(range),
495                                          SM, PP),
496                                SM.getInstantiationLoc(parentIndent)));
497}
498
499void TransformActionsImpl::commitClearDiagnostic(llvm::ArrayRef<unsigned> IDs,
500                                                 SourceRange range) {
501  CapturedDiags.clearDiagnostic(IDs, range);
502}
503
504void TransformActionsImpl::addInsertion(SourceLocation loc, StringRef text) {
505  SourceManager &SM = Ctx.getSourceManager();
506  loc = SM.getInstantiationLoc(loc);
507  for (std::list<CharRange>::reverse_iterator
508         I = Removals.rbegin(), E = Removals.rend(); I != E; ++I) {
509    if (!SM.isBeforeInTranslationUnit(loc, I->End))
510      break;
511    if (I->Begin.isBeforeInTranslationUnitThan(loc))
512      return;
513  }
514
515  Inserts[FullSourceLoc(loc, SM)].push_back(text);
516}
517
518void TransformActionsImpl::addRemoval(CharSourceRange range) {
519  CharRange newRange(range, Ctx.getSourceManager(), PP);
520  if (newRange.Begin == newRange.End)
521    return;
522
523  Inserts.erase(Inserts.upper_bound(newRange.Begin),
524                Inserts.lower_bound(newRange.End));
525
526  std::list<CharRange>::iterator I = Removals.end();
527  while (I != Removals.begin()) {
528    std::list<CharRange>::iterator RI = I;
529    --RI;
530    RangeComparison comp = newRange.compareWith(*RI);
531    switch (comp) {
532    case Range_Before:
533      --I;
534      break;
535    case Range_After:
536      Removals.insert(I, newRange);
537      return;
538    case Range_Contained:
539      return;
540    case Range_Contains:
541      RI->End = newRange.End;
542    case Range_ExtendsBegin:
543      newRange.End = RI->End;
544      Removals.erase(RI);
545      break;
546    case Range_ExtendsEnd:
547      RI->End = newRange.End;
548      return;
549    }
550  }
551
552  Removals.insert(Removals.begin(), newRange);
553}
554
555void TransformActionsImpl::applyRewrites(
556                                  TransformActions::RewriteReceiver &receiver) {
557  for (InsertsMap::iterator I = Inserts.begin(), E = Inserts.end(); I!=E; ++I) {
558    SourceLocation loc = I->first;
559    for (TextsVec::iterator
560           TI = I->second.begin(), TE = I->second.end(); TI != TE; ++TI) {
561      receiver.insert(loc, *TI);
562    }
563  }
564
565  for (std::vector<std::pair<CharRange, SourceLocation> >::iterator
566       I = IndentationRanges.begin(), E = IndentationRanges.end(); I!=E; ++I) {
567    CharSourceRange range = CharSourceRange::getCharRange(I->first.Begin,
568                                                          I->first.End);
569    receiver.increaseIndentation(range, I->second);
570  }
571
572  for (std::list<CharRange>::iterator
573         I = Removals.begin(), E = Removals.end(); I != E; ++I) {
574    CharSourceRange range = CharSourceRange::getCharRange(I->Begin, I->End);
575    receiver.remove(range);
576  }
577}
578
579/// \brief Stores text passed to the transformation methods to keep the string
580/// "alive". Since the vast majority of text will be the same, we also unique
581/// the strings using a StringMap.
582StringRef TransformActionsImpl::getUniqueText(StringRef text) {
583  llvm::StringMapEntry<bool> &entry = UniqueText.GetOrCreateValue(text);
584  return entry.getKey();
585}
586
587/// \brief Computes the source location just past the end of the token at
588/// the given source location. If the location points at a macro, the whole
589/// macro instantiation is skipped.
590SourceLocation TransformActionsImpl::getLocForEndOfToken(SourceLocation loc,
591                                                         SourceManager &SM,
592                                                         Preprocessor &PP) {
593  if (loc.isMacroID())
594    loc = SM.getInstantiationRange(loc).second;
595  return PP.getLocForEndOfToken(loc);
596}
597
598TransformActions::RewriteReceiver::~RewriteReceiver() { }
599
600TransformActions::TransformActions(Diagnostic &diag,
601                                   CapturedDiagList &capturedDiags,
602                                   ASTContext &ctx, Preprocessor &PP)
603  : Diags(diag), CapturedDiags(capturedDiags) {
604  Impl = new TransformActionsImpl(capturedDiags, ctx, PP);
605}
606
607TransformActions::~TransformActions() {
608  delete static_cast<TransformActionsImpl*>(Impl);
609}
610
611void TransformActions::startTransaction() {
612  static_cast<TransformActionsImpl*>(Impl)->startTransaction();
613}
614
615bool TransformActions::commitTransaction() {
616  return static_cast<TransformActionsImpl*>(Impl)->commitTransaction();
617}
618
619void TransformActions::abortTransaction() {
620  static_cast<TransformActionsImpl*>(Impl)->abortTransaction();
621}
622
623
624void TransformActions::insert(SourceLocation loc, llvm::StringRef text) {
625  static_cast<TransformActionsImpl*>(Impl)->insert(loc, text);
626}
627
628void TransformActions::insertAfterToken(SourceLocation loc,
629                                        llvm::StringRef text) {
630  static_cast<TransformActionsImpl*>(Impl)->insertAfterToken(loc, text);
631}
632
633void TransformActions::remove(SourceRange range) {
634  static_cast<TransformActionsImpl*>(Impl)->remove(range);
635}
636
637void TransformActions::removeStmt(Stmt *S) {
638  static_cast<TransformActionsImpl*>(Impl)->removeStmt(S);
639}
640
641void TransformActions::replace(SourceRange range, llvm::StringRef text) {
642  static_cast<TransformActionsImpl*>(Impl)->replace(range, text);
643}
644
645void TransformActions::replace(SourceRange range,
646                               SourceRange replacementRange) {
647  static_cast<TransformActionsImpl*>(Impl)->replace(range, replacementRange);
648}
649
650void TransformActions::replaceStmt(Stmt *S, llvm::StringRef text) {
651  static_cast<TransformActionsImpl*>(Impl)->replaceStmt(S, text);
652}
653
654void TransformActions::replaceText(SourceLocation loc, llvm::StringRef text,
655                                   llvm::StringRef replacementText) {
656  static_cast<TransformActionsImpl*>(Impl)->replaceText(loc, text,
657                                                        replacementText);
658}
659
660void TransformActions::increaseIndentation(SourceRange range,
661                                           SourceLocation parentIndent) {
662  static_cast<TransformActionsImpl*>(Impl)->increaseIndentation(range,
663                                                                parentIndent);
664}
665
666bool TransformActions::clearDiagnostic(llvm::ArrayRef<unsigned> IDs,
667                                       SourceRange range) {
668  return static_cast<TransformActionsImpl*>(Impl)->clearDiagnostic(IDs, range);
669}
670
671void TransformActions::applyRewrites(RewriteReceiver &receiver) {
672  static_cast<TransformActionsImpl*>(Impl)->applyRewrites(receiver);
673}
674
675void TransformActions::reportError(llvm::StringRef error, SourceLocation loc,
676                                   SourceRange range) {
677  assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() &&
678         "Errors should be emitted out of a transaction");
679  // FIXME: Use a custom category name to distinguish rewriter errors.
680  std::string rewriteErr = "[rewriter] ";
681  rewriteErr += error;
682  unsigned diagID
683     = Diags.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Error,
684                                                 rewriteErr);
685  Diags.Report(loc, diagID) << range;
686}
687
688void TransformActions::reportNote(llvm::StringRef note, SourceLocation loc,
689                                  SourceRange range) {
690  assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() &&
691         "Errors should be emitted out of a transaction");
692  // FIXME: Use a custom category name to distinguish rewriter errors.
693  std::string rewriteNote = "[rewriter] ";
694  rewriteNote += note;
695  unsigned diagID
696     = Diags.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Note,
697                                                 rewriteNote);
698  Diags.Report(loc, diagID) << range;
699}
700