Home | History | Annotate | Download | only in ARCMigrate
      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 using namespace clang;
     17 using namespace arcmt;
     18 
     19 namespace {
     20 
     21 /// \brief Collects transformations and merges them before applying them with
     22 /// with applyRewrites(). E.g. if the same source range
     23 /// is requested to be removed twice, only one rewriter remove will be invoked.
     24 /// Rewrites happen in "transactions"; if one rewrite in the transaction cannot
     25 /// be done (e.g. it resides in a macro) all rewrites in the transaction are
     26 /// aborted.
     27 /// FIXME: "Transactional" rewrites support should be baked in the Rewriter.
     28 class TransformActionsImpl {
     29   CapturedDiagList &CapturedDiags;
     30   ASTContext &Ctx;
     31   Preprocessor &PP;
     32 
     33   bool IsInTransaction;
     34 
     35   enum ActionKind {
     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 {
     44     ActionKind Kind;
     45     SourceLocation Loc;
     46     SourceRange R1, R2;
     47     StringRef Text1, Text2;
     48     Stmt *S;
     49     SmallVector<unsigned, 2> DiagIDs;
     50   };
     51 
     52   std::vector<ActionData> 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   /// \brief A range to remove. It is a character range.
     64   struct CharRange {
     65     FullSourceLoc Begin, End;
     66 
     67     CharRange(CharSourceRange range, SourceManager &srcMgr, Preprocessor &PP) {
     68       SourceLocation beginLoc = range.getBegin(), endLoc = range.getEnd();
     69       assert(beginLoc.isValid() && endLoc.isValid());
     70       if (range.isTokenRange()) {
     71         Begin = FullSourceLoc(srcMgr.getExpansionLoc(beginLoc), srcMgr);
     72         End = FullSourceLoc(getLocForEndOfToken(endLoc, srcMgr, PP), srcMgr);
     73       } else {
     74         Begin = FullSourceLoc(srcMgr.getExpansionLoc(beginLoc), srcMgr);
     75         End = FullSourceLoc(srcMgr.getExpansionLoc(endLoc), srcMgr);
     76       }
     77       assert(Begin.isValid() && End.isValid());
     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 
     97     static RangeComparison compare(SourceRange LHS, SourceRange RHS,
     98                                    SourceManager &SrcMgr, Preprocessor &PP) {
     99       return CharRange(CharSourceRange::getTokenRange(LHS), SrcMgr, PP)
    100                   .compareWith(CharRange(CharSourceRange::getTokenRange(RHS),
    101                                             SrcMgr, PP));
    102     }
    103   };
    104 
    105   typedef SmallVector<StringRef, 2> TextsVec;
    106   typedef std::map<FullSourceLoc, TextsVec, FullSourceLoc::BeforeThanCompare>
    107       InsertsMap;
    108   InsertsMap Inserts;
    109   /// \brief A list of ranges to remove. They are always sorted and they never
    110   /// intersect with each other.
    111   std::list<CharRange> Removals;
    112 
    113   llvm::DenseSet<Stmt *> StmtRemovals;
    114 
    115   std::vector<std::pair<CharRange, SourceLocation> > IndentationRanges;
    116 
    117   /// \brief Keeps text passed to transformation methods.
    118   llvm::StringMap<bool> UniqueText;
    119 
    120 public:
    121   TransformActionsImpl(CapturedDiagList &capturedDiags,
    122                        ASTContext &ctx, Preprocessor &PP)
    123     : CapturedDiags(capturedDiags), Ctx(ctx), PP(PP), IsInTransaction(false) { }
    124 
    125   void startTransaction();
    126   bool commitTransaction();
    127   void abortTransaction();
    128 
    129   bool isInTransaction() const { return IsInTransaction; }
    130 
    131   void insert(SourceLocation loc, StringRef text);
    132   void insertAfterToken(SourceLocation loc, StringRef text);
    133   void remove(SourceRange range);
    134   void removeStmt(Stmt *S);
    135   void replace(SourceRange range, StringRef text);
    136   void replace(SourceRange range, SourceRange replacementRange);
    137   void replaceStmt(Stmt *S, StringRef text);
    138   void replaceText(SourceLocation loc, StringRef text,
    139                    StringRef replacementText);
    140   void increaseIndentation(SourceRange range,
    141                            SourceLocation parentIndent);
    142 
    143   bool clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range);
    144 
    145   void applyRewrites(TransformActions::RewriteReceiver &receiver);
    146 
    147 private:
    148   bool canInsert(SourceLocation loc);
    149   bool canInsertAfterToken(SourceLocation loc);
    150   bool canRemoveRange(SourceRange range);
    151   bool canReplaceRange(SourceRange range, SourceRange replacementRange);
    152   bool canReplaceText(SourceLocation loc, StringRef text);
    153 
    154   void commitInsert(SourceLocation loc, StringRef text);
    155   void commitInsertAfterToken(SourceLocation loc, StringRef text);
    156   void commitRemove(SourceRange range);
    157   void commitRemoveStmt(Stmt *S);
    158   void commitReplace(SourceRange range, SourceRange replacementRange);
    159   void commitReplaceText(SourceLocation loc, StringRef text,
    160                          StringRef replacementText);
    161   void commitIncreaseIndentation(SourceRange range,SourceLocation parentIndent);
    162   void commitClearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range);
    163 
    164   void addRemoval(CharSourceRange range);
    165   void addInsertion(SourceLocation loc, StringRef text);
    166 
    167   /// \brief Stores text passed to the transformation methods to keep the string
    168   /// "alive". Since the vast majority of text will be the same, we also unique
    169   /// the strings using a StringMap.
    170   StringRef getUniqueText(StringRef text);
    171 
    172   /// \brief Computes the source location just past the end of the token at
    173   /// the given source location. If the location points at a macro, the whole
    174   /// macro expansion is skipped.
    175   static SourceLocation getLocForEndOfToken(SourceLocation loc,
    176                                             SourceManager &SM,Preprocessor &PP);
    177 };
    178 
    179 } // anonymous namespace
    180 
    181 void TransformActionsImpl::startTransaction() {
    182   assert(!IsInTransaction &&
    183          "Cannot start a transaction in the middle of another one");
    184   IsInTransaction = true;
    185 }
    186 
    187 bool TransformActionsImpl::commitTransaction() {
    188   assert(IsInTransaction && "No transaction started");
    189 
    190   if (CachedActions.empty()) {
    191     IsInTransaction = false;
    192     return false;
    193   }
    194 
    195   // Verify that all actions are possible otherwise abort the whole transaction.
    196   bool AllActionsPossible = true;
    197   for (unsigned i = 0, e = CachedActions.size(); i != e; ++i) {
    198     ActionData &act = CachedActions[i];
    199     switch (act.Kind) {
    200     case Act_Insert:
    201       if (!canInsert(act.Loc))
    202         AllActionsPossible = false;
    203       break;
    204     case Act_InsertAfterToken:
    205       if (!canInsertAfterToken(act.Loc))
    206         AllActionsPossible = false;
    207       break;
    208     case Act_Remove:
    209       if (!canRemoveRange(act.R1))
    210         AllActionsPossible = false;
    211       break;
    212     case Act_RemoveStmt:
    213       assert(act.S);
    214       if (!canRemoveRange(act.S->getSourceRange()))
    215         AllActionsPossible = false;
    216       break;
    217     case Act_Replace:
    218       if (!canReplaceRange(act.R1, act.R2))
    219         AllActionsPossible = false;
    220       break;
    221     case Act_ReplaceText:
    222       if (!canReplaceText(act.Loc, act.Text1))
    223         AllActionsPossible = false;
    224       break;
    225     case Act_IncreaseIndentation:
    226       // This is not important, we don't care if it will fail.
    227       break;
    228     case Act_ClearDiagnostic:
    229       // We are just checking source rewrites.
    230       break;
    231     }
    232     if (!AllActionsPossible)
    233       break;
    234   }
    235 
    236   if (!AllActionsPossible) {
    237     abortTransaction();
    238     return true;
    239   }
    240 
    241   for (unsigned i = 0, e = CachedActions.size(); i != e; ++i) {
    242     ActionData &act = CachedActions[i];
    243     switch (act.Kind) {
    244     case Act_Insert:
    245       commitInsert(act.Loc, act.Text1);
    246       break;
    247     case Act_InsertAfterToken:
    248       commitInsertAfterToken(act.Loc, act.Text1);
    249       break;
    250     case Act_Remove:
    251       commitRemove(act.R1);
    252       break;
    253     case Act_RemoveStmt:
    254       commitRemoveStmt(act.S);
    255       break;
    256     case Act_Replace:
    257       commitReplace(act.R1, act.R2);
    258       break;
    259     case Act_ReplaceText:
    260       commitReplaceText(act.Loc, act.Text1, act.Text2);
    261       break;
    262     case Act_IncreaseIndentation:
    263       commitIncreaseIndentation(act.R1, act.Loc);
    264       break;
    265     case Act_ClearDiagnostic:
    266       commitClearDiagnostic(act.DiagIDs, act.R1);
    267       break;
    268     }
    269   }
    270 
    271   CachedActions.clear();
    272   IsInTransaction = false;
    273   return false;
    274 }
    275 
    276 void TransformActionsImpl::abortTransaction() {
    277   assert(IsInTransaction && "No transaction started");
    278   CachedActions.clear();
    279   IsInTransaction = false;
    280 }
    281 
    282 void TransformActionsImpl::insert(SourceLocation loc, StringRef text) {
    283   assert(IsInTransaction && "Actions only allowed during a transaction");
    284   text = getUniqueText(text);
    285   ActionData data;
    286   data.Kind = Act_Insert;
    287   data.Loc = loc;
    288   data.Text1 = text;
    289   CachedActions.push_back(data);
    290 }
    291 
    292 void TransformActionsImpl::insertAfterToken(SourceLocation loc, StringRef text) {
    293   assert(IsInTransaction && "Actions only allowed during a transaction");
    294   text = getUniqueText(text);
    295   ActionData data;
    296   data.Kind = Act_InsertAfterToken;
    297   data.Loc = loc;
    298   data.Text1 = text;
    299   CachedActions.push_back(data);
    300 }
    301 
    302 void TransformActionsImpl::remove(SourceRange range) {
    303   assert(IsInTransaction && "Actions only allowed during a transaction");
    304   ActionData data;
    305   data.Kind = Act_Remove;
    306   data.R1 = range;
    307   CachedActions.push_back(data);
    308 }
    309 
    310 void TransformActionsImpl::removeStmt(Stmt *S) {
    311   assert(IsInTransaction && "Actions only allowed during a transaction");
    312   ActionData data;
    313   data.Kind = Act_RemoveStmt;
    314   data.S = S->IgnoreImplicit(); // important for uniquing
    315   CachedActions.push_back(data);
    316 }
    317 
    318 void TransformActionsImpl::replace(SourceRange range, StringRef text) {
    319   assert(IsInTransaction && "Actions only allowed during a transaction");
    320   text = getUniqueText(text);
    321   remove(range);
    322   insert(range.getBegin(), text);
    323 }
    324 
    325 void TransformActionsImpl::replace(SourceRange range,
    326                                    SourceRange replacementRange) {
    327   assert(IsInTransaction && "Actions only allowed during a transaction");
    328   ActionData data;
    329   data.Kind = Act_Replace;
    330   data.R1 = range;
    331   data.R2 = replacementRange;
    332   CachedActions.push_back(data);
    333 }
    334 
    335 void TransformActionsImpl::replaceText(SourceLocation loc, StringRef text,
    336                                        StringRef replacementText) {
    337   text = getUniqueText(text);
    338   replacementText = getUniqueText(replacementText);
    339   ActionData data;
    340   data.Kind = Act_ReplaceText;
    341   data.Loc = loc;
    342   data.Text1 = text;
    343   data.Text2 = replacementText;
    344   CachedActions.push_back(data);
    345 }
    346 
    347 void TransformActionsImpl::replaceStmt(Stmt *S, StringRef text) {
    348   assert(IsInTransaction && "Actions only allowed during a transaction");
    349   text = getUniqueText(text);
    350   insert(S->getLocStart(), text);
    351   removeStmt(S);
    352 }
    353 
    354 void TransformActionsImpl::increaseIndentation(SourceRange range,
    355                                                SourceLocation parentIndent) {
    356   if (range.isInvalid()) return;
    357   assert(IsInTransaction && "Actions only allowed during a transaction");
    358   ActionData data;
    359   data.Kind = Act_IncreaseIndentation;
    360   data.R1 = range;
    361   data.Loc = parentIndent;
    362   CachedActions.push_back(data);
    363 }
    364 
    365 bool TransformActionsImpl::clearDiagnostic(ArrayRef<unsigned> IDs,
    366                                            SourceRange range) {
    367   assert(IsInTransaction && "Actions only allowed during a transaction");
    368   if (!CapturedDiags.hasDiagnostic(IDs, range))
    369     return false;
    370 
    371   ActionData data;
    372   data.Kind = Act_ClearDiagnostic;
    373   data.R1 = range;
    374   data.DiagIDs.append(IDs.begin(), IDs.end());
    375   CachedActions.push_back(data);
    376   return true;
    377 }
    378 
    379 bool TransformActionsImpl::canInsert(SourceLocation loc) {
    380   if (loc.isInvalid())
    381     return false;
    382 
    383   SourceManager &SM = Ctx.getSourceManager();
    384   if (SM.isInSystemHeader(SM.getExpansionLoc(loc)))
    385     return false;
    386 
    387   if (loc.isFileID())
    388     return true;
    389   return PP.isAtStartOfMacroExpansion(loc);
    390 }
    391 
    392 bool TransformActionsImpl::canInsertAfterToken(SourceLocation loc) {
    393   if (loc.isInvalid())
    394     return false;
    395 
    396   SourceManager &SM = Ctx.getSourceManager();
    397   if (SM.isInSystemHeader(SM.getExpansionLoc(loc)))
    398     return false;
    399 
    400   if (loc.isFileID())
    401     return true;
    402   return PP.isAtEndOfMacroExpansion(loc);
    403 }
    404 
    405 bool TransformActionsImpl::canRemoveRange(SourceRange range) {
    406   return canInsert(range.getBegin()) && canInsertAfterToken(range.getEnd());
    407 }
    408 
    409 bool TransformActionsImpl::canReplaceRange(SourceRange range,
    410                                            SourceRange replacementRange) {
    411   return canRemoveRange(range) && canRemoveRange(replacementRange);
    412 }
    413 
    414 bool TransformActionsImpl::canReplaceText(SourceLocation loc, StringRef text) {
    415   if (!canInsert(loc))
    416     return false;
    417 
    418   SourceManager &SM = Ctx.getSourceManager();
    419   loc = SM.getExpansionLoc(loc);
    420 
    421   // Break down the source location.
    422   std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
    423 
    424   // Try to load the file buffer.
    425   bool invalidTemp = false;
    426   StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
    427   if (invalidTemp)
    428     return false;
    429 
    430   return file.substr(locInfo.second).startswith(text);
    431 }
    432 
    433 void TransformActionsImpl::commitInsert(SourceLocation loc, StringRef text) {
    434   addInsertion(loc, text);
    435 }
    436 
    437 void TransformActionsImpl::commitInsertAfterToken(SourceLocation loc,
    438                                                   StringRef text) {
    439   addInsertion(getLocForEndOfToken(loc, Ctx.getSourceManager(), PP), text);
    440 }
    441 
    442 void TransformActionsImpl::commitRemove(SourceRange range) {
    443   addRemoval(CharSourceRange::getTokenRange(range));
    444 }
    445 
    446 void TransformActionsImpl::commitRemoveStmt(Stmt *S) {
    447   assert(S);
    448   if (StmtRemovals.count(S))
    449     return; // already removed.
    450 
    451   if (Expr *E = dyn_cast<Expr>(S)) {
    452     commitRemove(E->getSourceRange());
    453     commitInsert(E->getSourceRange().getBegin(), getARCMTMacroName());
    454   } else
    455     commitRemove(S->getSourceRange());
    456 
    457   StmtRemovals.insert(S);
    458 }
    459 
    460 void TransformActionsImpl::commitReplace(SourceRange range,
    461                                          SourceRange replacementRange) {
    462   RangeComparison comp = CharRange::compare(replacementRange, range,
    463                                                Ctx.getSourceManager(), PP);
    464   assert(comp == Range_Contained);
    465   if (comp != Range_Contained)
    466     return; // Although we asserted, be extra safe for release build.
    467   if (range.getBegin() != replacementRange.getBegin())
    468     addRemoval(CharSourceRange::getCharRange(range.getBegin(),
    469                                              replacementRange.getBegin()));
    470   if (replacementRange.getEnd() != range.getEnd())
    471     addRemoval(CharSourceRange::getTokenRange(
    472                                   getLocForEndOfToken(replacementRange.getEnd(),
    473                                                       Ctx.getSourceManager(), PP),
    474                                   range.getEnd()));
    475 }
    476 void TransformActionsImpl::commitReplaceText(SourceLocation loc,
    477                                              StringRef text,
    478                                              StringRef replacementText) {
    479   SourceManager &SM = Ctx.getSourceManager();
    480   loc = SM.getExpansionLoc(loc);
    481   // canReplaceText already checked if loc points at text.
    482   SourceLocation afterText = loc.getLocWithOffset(text.size());
    483 
    484   addRemoval(CharSourceRange::getCharRange(loc, afterText));
    485   commitInsert(loc, replacementText);
    486 }
    487 
    488 void TransformActionsImpl::commitIncreaseIndentation(SourceRange range,
    489                                                   SourceLocation parentIndent) {
    490   SourceManager &SM = Ctx.getSourceManager();
    491   IndentationRanges.push_back(
    492                  std::make_pair(CharRange(CharSourceRange::getTokenRange(range),
    493                                           SM, PP),
    494                                 SM.getExpansionLoc(parentIndent)));
    495 }
    496 
    497 void TransformActionsImpl::commitClearDiagnostic(ArrayRef<unsigned> IDs,
    498                                                  SourceRange range) {
    499   CapturedDiags.clearDiagnostic(IDs, range);
    500 }
    501 
    502 void TransformActionsImpl::addInsertion(SourceLocation loc, StringRef text) {
    503   SourceManager &SM = Ctx.getSourceManager();
    504   loc = SM.getExpansionLoc(loc);
    505   for (std::list<CharRange>::reverse_iterator
    506          I = Removals.rbegin(), E = Removals.rend(); I != E; ++I) {
    507     if (!SM.isBeforeInTranslationUnit(loc, I->End))
    508       break;
    509     if (I->Begin.isBeforeInTranslationUnitThan(loc))
    510       return;
    511   }
    512 
    513   Inserts[FullSourceLoc(loc, SM)].push_back(text);
    514 }
    515 
    516 void TransformActionsImpl::addRemoval(CharSourceRange range) {
    517   CharRange newRange(range, Ctx.getSourceManager(), PP);
    518   if (newRange.Begin == newRange.End)
    519     return;
    520 
    521   Inserts.erase(Inserts.upper_bound(newRange.Begin),
    522                 Inserts.lower_bound(newRange.End));
    523 
    524   std::list<CharRange>::iterator I = Removals.end();
    525   while (I != Removals.begin()) {
    526     std::list<CharRange>::iterator RI = I;
    527     --RI;
    528     RangeComparison comp = newRange.compareWith(*RI);
    529     switch (comp) {
    530     case Range_Before:
    531       --I;
    532       break;
    533     case Range_After:
    534       Removals.insert(I, newRange);
    535       return;
    536     case Range_Contained:
    537       return;
    538     case Range_Contains:
    539       RI->End = newRange.End;
    540     case Range_ExtendsBegin:
    541       newRange.End = RI->End;
    542       Removals.erase(RI);
    543       break;
    544     case Range_ExtendsEnd:
    545       RI->End = newRange.End;
    546       return;
    547     }
    548   }
    549 
    550   Removals.insert(Removals.begin(), newRange);
    551 }
    552 
    553 void TransformActionsImpl::applyRewrites(
    554                                   TransformActions::RewriteReceiver &receiver) {
    555   for (InsertsMap::iterator I = Inserts.begin(), E = Inserts.end(); I!=E; ++I) {
    556     SourceLocation loc = I->first;
    557     for (TextsVec::iterator
    558            TI = I->second.begin(), TE = I->second.end(); TI != TE; ++TI) {
    559       receiver.insert(loc, *TI);
    560     }
    561   }
    562 
    563   for (std::vector<std::pair<CharRange, SourceLocation> >::iterator
    564        I = IndentationRanges.begin(), E = IndentationRanges.end(); I!=E; ++I) {
    565     CharSourceRange range = CharSourceRange::getCharRange(I->first.Begin,
    566                                                           I->first.End);
    567     receiver.increaseIndentation(range, I->second);
    568   }
    569 
    570   for (std::list<CharRange>::iterator
    571          I = Removals.begin(), E = Removals.end(); I != E; ++I) {
    572     CharSourceRange range = CharSourceRange::getCharRange(I->Begin, I->End);
    573     receiver.remove(range);
    574   }
    575 }
    576 
    577 /// \brief Stores text passed to the transformation methods to keep the string
    578 /// "alive". Since the vast majority of text will be the same, we also unique
    579 /// the strings using a StringMap.
    580 StringRef TransformActionsImpl::getUniqueText(StringRef text) {
    581   llvm::StringMapEntry<bool> &entry = UniqueText.GetOrCreateValue(text);
    582   return entry.getKey();
    583 }
    584 
    585 /// \brief Computes the source location just past the end of the token at
    586 /// the given source location. If the location points at a macro, the whole
    587 /// macro expansion is skipped.
    588 SourceLocation TransformActionsImpl::getLocForEndOfToken(SourceLocation loc,
    589                                                          SourceManager &SM,
    590                                                          Preprocessor &PP) {
    591   if (loc.isMacroID())
    592     loc = SM.getExpansionRange(loc).second;
    593   return PP.getLocForEndOfToken(loc);
    594 }
    595 
    596 TransformActions::RewriteReceiver::~RewriteReceiver() { }
    597 
    598 TransformActions::TransformActions(DiagnosticsEngine &diag,
    599                                    CapturedDiagList &capturedDiags,
    600                                    ASTContext &ctx, Preprocessor &PP)
    601   : Diags(diag), CapturedDiags(capturedDiags), ReportedErrors(false) {
    602   Impl = new TransformActionsImpl(capturedDiags, ctx, PP);
    603 }
    604 
    605 TransformActions::~TransformActions() {
    606   delete static_cast<TransformActionsImpl*>(Impl);
    607 }
    608 
    609 void TransformActions::startTransaction() {
    610   static_cast<TransformActionsImpl*>(Impl)->startTransaction();
    611 }
    612 
    613 bool TransformActions::commitTransaction() {
    614   return static_cast<TransformActionsImpl*>(Impl)->commitTransaction();
    615 }
    616 
    617 void TransformActions::abortTransaction() {
    618   static_cast<TransformActionsImpl*>(Impl)->abortTransaction();
    619 }
    620 
    621 
    622 void TransformActions::insert(SourceLocation loc, StringRef text) {
    623   static_cast<TransformActionsImpl*>(Impl)->insert(loc, text);
    624 }
    625 
    626 void TransformActions::insertAfterToken(SourceLocation loc,
    627                                         StringRef text) {
    628   static_cast<TransformActionsImpl*>(Impl)->insertAfterToken(loc, text);
    629 }
    630 
    631 void TransformActions::remove(SourceRange range) {
    632   static_cast<TransformActionsImpl*>(Impl)->remove(range);
    633 }
    634 
    635 void TransformActions::removeStmt(Stmt *S) {
    636   static_cast<TransformActionsImpl*>(Impl)->removeStmt(S);
    637 }
    638 
    639 void TransformActions::replace(SourceRange range, StringRef text) {
    640   static_cast<TransformActionsImpl*>(Impl)->replace(range, text);
    641 }
    642 
    643 void TransformActions::replace(SourceRange range,
    644                                SourceRange replacementRange) {
    645   static_cast<TransformActionsImpl*>(Impl)->replace(range, replacementRange);
    646 }
    647 
    648 void TransformActions::replaceStmt(Stmt *S, StringRef text) {
    649   static_cast<TransformActionsImpl*>(Impl)->replaceStmt(S, text);
    650 }
    651 
    652 void TransformActions::replaceText(SourceLocation loc, StringRef text,
    653                                    StringRef replacementText) {
    654   static_cast<TransformActionsImpl*>(Impl)->replaceText(loc, text,
    655                                                         replacementText);
    656 }
    657 
    658 void TransformActions::increaseIndentation(SourceRange range,
    659                                            SourceLocation parentIndent) {
    660   static_cast<TransformActionsImpl*>(Impl)->increaseIndentation(range,
    661                                                                 parentIndent);
    662 }
    663 
    664 bool TransformActions::clearDiagnostic(ArrayRef<unsigned> IDs,
    665                                        SourceRange range) {
    666   return static_cast<TransformActionsImpl*>(Impl)->clearDiagnostic(IDs, range);
    667 }
    668 
    669 void TransformActions::applyRewrites(RewriteReceiver &receiver) {
    670   static_cast<TransformActionsImpl*>(Impl)->applyRewrites(receiver);
    671 }
    672 
    673 void TransformActions::reportError(StringRef error, SourceLocation loc,
    674                                    SourceRange range) {
    675   assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() &&
    676          "Errors should be emitted out of a transaction");
    677   // FIXME: Use a custom category name to distinguish rewriter errors.
    678   std::string rewriteErr = "[rewriter] ";
    679   rewriteErr += error;
    680   unsigned diagID
    681      = Diags.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Error,
    682                                                  rewriteErr);
    683   Diags.Report(loc, diagID) << range;
    684   ReportedErrors = true;
    685 }
    686 
    687 void TransformActions::reportNote(StringRef note, SourceLocation loc,
    688                                   SourceRange range) {
    689   assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() &&
    690          "Errors should be emitted out of a transaction");
    691   // FIXME: Use a custom category name to distinguish rewriter errors.
    692   std::string rewriteNote = "[rewriter] ";
    693   rewriteNote += note;
    694   unsigned diagID
    695      = Diags.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Note,
    696                                                  rewriteNote);
    697   Diags.Report(loc, diagID) << range;
    698 }
    699