Home | History | Annotate | Line # | Download | only in Edit
EditedSource.cpp revision 1.1.1.1
      1  1.1  joerg //===- EditedSource.cpp - Collection of source edits ----------------------===//
      2  1.1  joerg //
      3  1.1  joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4  1.1  joerg // See https://llvm.org/LICENSE.txt for license information.
      5  1.1  joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6  1.1  joerg //
      7  1.1  joerg //===----------------------------------------------------------------------===//
      8  1.1  joerg 
      9  1.1  joerg #include "clang/Edit/EditedSource.h"
     10  1.1  joerg #include "clang/Basic/CharInfo.h"
     11  1.1  joerg #include "clang/Basic/LLVM.h"
     12  1.1  joerg #include "clang/Basic/SourceLocation.h"
     13  1.1  joerg #include "clang/Basic/SourceManager.h"
     14  1.1  joerg #include "clang/Edit/Commit.h"
     15  1.1  joerg #include "clang/Edit/EditsReceiver.h"
     16  1.1  joerg #include "clang/Edit/FileOffset.h"
     17  1.1  joerg #include "clang/Lex/Lexer.h"
     18  1.1  joerg #include "llvm/ADT/STLExtras.h"
     19  1.1  joerg #include "llvm/ADT/SmallString.h"
     20  1.1  joerg #include "llvm/ADT/StringRef.h"
     21  1.1  joerg #include "llvm/ADT/Twine.h"
     22  1.1  joerg #include <algorithm>
     23  1.1  joerg #include <cassert>
     24  1.1  joerg #include <tuple>
     25  1.1  joerg #include <utility>
     26  1.1  joerg 
     27  1.1  joerg using namespace clang;
     28  1.1  joerg using namespace edit;
     29  1.1  joerg 
     30  1.1  joerg void EditsReceiver::remove(CharSourceRange range) {
     31  1.1  joerg   replace(range, StringRef());
     32  1.1  joerg }
     33  1.1  joerg 
     34  1.1  joerg void EditedSource::deconstructMacroArgLoc(SourceLocation Loc,
     35  1.1  joerg                                           SourceLocation &ExpansionLoc,
     36  1.1  joerg                                           MacroArgUse &ArgUse) {
     37  1.1  joerg   assert(SourceMgr.isMacroArgExpansion(Loc));
     38  1.1  joerg   SourceLocation DefArgLoc =
     39  1.1  joerg       SourceMgr.getImmediateExpansionRange(Loc).getBegin();
     40  1.1  joerg   SourceLocation ImmediateExpansionLoc =
     41  1.1  joerg       SourceMgr.getImmediateExpansionRange(DefArgLoc).getBegin();
     42  1.1  joerg   ExpansionLoc = ImmediateExpansionLoc;
     43  1.1  joerg   while (SourceMgr.isMacroBodyExpansion(ExpansionLoc))
     44  1.1  joerg     ExpansionLoc =
     45  1.1  joerg         SourceMgr.getImmediateExpansionRange(ExpansionLoc).getBegin();
     46  1.1  joerg   SmallString<20> Buf;
     47  1.1  joerg   StringRef ArgName = Lexer::getSpelling(SourceMgr.getSpellingLoc(DefArgLoc),
     48  1.1  joerg                                          Buf, SourceMgr, LangOpts);
     49  1.1  joerg   ArgUse = MacroArgUse{nullptr, SourceLocation(), SourceLocation()};
     50  1.1  joerg   if (!ArgName.empty())
     51  1.1  joerg     ArgUse = {&IdentTable.get(ArgName), ImmediateExpansionLoc,
     52  1.1  joerg               SourceMgr.getSpellingLoc(DefArgLoc)};
     53  1.1  joerg }
     54  1.1  joerg 
     55  1.1  joerg void EditedSource::startingCommit() {}
     56  1.1  joerg 
     57  1.1  joerg void EditedSource::finishedCommit() {
     58  1.1  joerg   for (auto &ExpArg : CurrCommitMacroArgExps) {
     59  1.1  joerg     SourceLocation ExpLoc;
     60  1.1  joerg     MacroArgUse ArgUse;
     61  1.1  joerg     std::tie(ExpLoc, ArgUse) = ExpArg;
     62  1.1  joerg     auto &ArgUses = ExpansionToArgMap[ExpLoc.getRawEncoding()];
     63  1.1  joerg     if (llvm::find(ArgUses, ArgUse) == ArgUses.end())
     64  1.1  joerg       ArgUses.push_back(ArgUse);
     65  1.1  joerg   }
     66  1.1  joerg   CurrCommitMacroArgExps.clear();
     67  1.1  joerg }
     68  1.1  joerg 
     69  1.1  joerg StringRef EditedSource::copyString(const Twine &twine) {
     70  1.1  joerg   SmallString<128> Data;
     71  1.1  joerg   return copyString(twine.toStringRef(Data));
     72  1.1  joerg }
     73  1.1  joerg 
     74  1.1  joerg bool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
     75  1.1  joerg   FileEditsTy::iterator FA = getActionForOffset(Offs);
     76  1.1  joerg   if (FA != FileEdits.end()) {
     77  1.1  joerg     if (FA->first != Offs)
     78  1.1  joerg       return false; // position has been removed.
     79  1.1  joerg   }
     80  1.1  joerg 
     81  1.1  joerg   if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
     82  1.1  joerg     SourceLocation ExpLoc;
     83  1.1  joerg     MacroArgUse ArgUse;
     84  1.1  joerg     deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
     85  1.1  joerg     auto I = ExpansionToArgMap.find(ExpLoc.getRawEncoding());
     86  1.1  joerg     if (I != ExpansionToArgMap.end() &&
     87  1.1  joerg         find_if(I->second, [&](const MacroArgUse &U) {
     88  1.1  joerg           return ArgUse.Identifier == U.Identifier &&
     89  1.1  joerg                  std::tie(ArgUse.ImmediateExpansionLoc, ArgUse.UseLoc) !=
     90  1.1  joerg                      std::tie(U.ImmediateExpansionLoc, U.UseLoc);
     91  1.1  joerg         }) != I->second.end()) {
     92  1.1  joerg       // Trying to write in a macro argument input that has already been
     93  1.1  joerg       // written by a previous commit for another expansion of the same macro
     94  1.1  joerg       // argument name. For example:
     95  1.1  joerg       //
     96  1.1  joerg       // \code
     97  1.1  joerg       //   #define MAC(x) ((x)+(x))
     98  1.1  joerg       //   MAC(a)
     99  1.1  joerg       // \endcode
    100  1.1  joerg       //
    101  1.1  joerg       // A commit modified the macro argument 'a' due to the first '(x)'
    102  1.1  joerg       // expansion inside the macro definition, and a subsequent commit tried
    103  1.1  joerg       // to modify 'a' again for the second '(x)' expansion. The edits of the
    104  1.1  joerg       // second commit will be rejected.
    105  1.1  joerg       return false;
    106  1.1  joerg     }
    107  1.1  joerg   }
    108  1.1  joerg   return true;
    109  1.1  joerg }
    110  1.1  joerg 
    111  1.1  joerg bool EditedSource::commitInsert(SourceLocation OrigLoc,
    112  1.1  joerg                                 FileOffset Offs, StringRef text,
    113  1.1  joerg                                 bool beforePreviousInsertions) {
    114  1.1  joerg   if (!canInsertInOffset(OrigLoc, Offs))
    115  1.1  joerg     return false;
    116  1.1  joerg   if (text.empty())
    117  1.1  joerg     return true;
    118  1.1  joerg 
    119  1.1  joerg   if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
    120  1.1  joerg     MacroArgUse ArgUse;
    121  1.1  joerg     SourceLocation ExpLoc;
    122  1.1  joerg     deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
    123  1.1  joerg     if (ArgUse.Identifier)
    124  1.1  joerg       CurrCommitMacroArgExps.emplace_back(ExpLoc, ArgUse);
    125  1.1  joerg   }
    126  1.1  joerg 
    127  1.1  joerg   FileEdit &FA = FileEdits[Offs];
    128  1.1  joerg   if (FA.Text.empty()) {
    129  1.1  joerg     FA.Text = copyString(text);
    130  1.1  joerg     return true;
    131  1.1  joerg   }
    132  1.1  joerg 
    133  1.1  joerg   if (beforePreviousInsertions)
    134  1.1  joerg     FA.Text = copyString(Twine(text) + FA.Text);
    135  1.1  joerg   else
    136  1.1  joerg     FA.Text = copyString(Twine(FA.Text) + text);
    137  1.1  joerg 
    138  1.1  joerg   return true;
    139  1.1  joerg }
    140  1.1  joerg 
    141  1.1  joerg bool EditedSource::commitInsertFromRange(SourceLocation OrigLoc,
    142  1.1  joerg                                    FileOffset Offs,
    143  1.1  joerg                                    FileOffset InsertFromRangeOffs, unsigned Len,
    144  1.1  joerg                                    bool beforePreviousInsertions) {
    145  1.1  joerg   if (Len == 0)
    146  1.1  joerg     return true;
    147  1.1  joerg 
    148  1.1  joerg   SmallString<128> StrVec;
    149  1.1  joerg   FileOffset BeginOffs = InsertFromRangeOffs;
    150  1.1  joerg   FileOffset EndOffs = BeginOffs.getWithOffset(Len);
    151  1.1  joerg   FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs);
    152  1.1  joerg   if (I != FileEdits.begin())
    153  1.1  joerg     --I;
    154  1.1  joerg 
    155  1.1  joerg   for (; I != FileEdits.end(); ++I) {
    156  1.1  joerg     FileEdit &FA = I->second;
    157  1.1  joerg     FileOffset B = I->first;
    158  1.1  joerg     FileOffset E = B.getWithOffset(FA.RemoveLen);
    159  1.1  joerg 
    160  1.1  joerg     if (BeginOffs == B)
    161  1.1  joerg       break;
    162  1.1  joerg 
    163  1.1  joerg     if (BeginOffs < E) {
    164  1.1  joerg       if (BeginOffs > B) {
    165  1.1  joerg         BeginOffs = E;
    166  1.1  joerg         ++I;
    167  1.1  joerg       }
    168  1.1  joerg       break;
    169  1.1  joerg     }
    170  1.1  joerg   }
    171  1.1  joerg 
    172  1.1  joerg   for (; I != FileEdits.end() && EndOffs > I->first; ++I) {
    173  1.1  joerg     FileEdit &FA = I->second;
    174  1.1  joerg     FileOffset B = I->first;
    175  1.1  joerg     FileOffset E = B.getWithOffset(FA.RemoveLen);
    176  1.1  joerg 
    177  1.1  joerg     if (BeginOffs < B) {
    178  1.1  joerg       bool Invalid = false;
    179  1.1  joerg       StringRef text = getSourceText(BeginOffs, B, Invalid);
    180  1.1  joerg       if (Invalid)
    181  1.1  joerg         return false;
    182  1.1  joerg       StrVec += text;
    183  1.1  joerg     }
    184  1.1  joerg     StrVec += FA.Text;
    185  1.1  joerg     BeginOffs = E;
    186  1.1  joerg   }
    187  1.1  joerg 
    188  1.1  joerg   if (BeginOffs < EndOffs) {
    189  1.1  joerg     bool Invalid = false;
    190  1.1  joerg     StringRef text = getSourceText(BeginOffs, EndOffs, Invalid);
    191  1.1  joerg     if (Invalid)
    192  1.1  joerg       return false;
    193  1.1  joerg     StrVec += text;
    194  1.1  joerg   }
    195  1.1  joerg 
    196  1.1  joerg   return commitInsert(OrigLoc, Offs, StrVec, beforePreviousInsertions);
    197  1.1  joerg }
    198  1.1  joerg 
    199  1.1  joerg void EditedSource::commitRemove(SourceLocation OrigLoc,
    200  1.1  joerg                                 FileOffset BeginOffs, unsigned Len) {
    201  1.1  joerg   if (Len == 0)
    202  1.1  joerg     return;
    203  1.1  joerg 
    204  1.1  joerg   FileOffset EndOffs = BeginOffs.getWithOffset(Len);
    205  1.1  joerg   FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs);
    206  1.1  joerg   if (I != FileEdits.begin())
    207  1.1  joerg     --I;
    208  1.1  joerg 
    209  1.1  joerg   for (; I != FileEdits.end(); ++I) {
    210  1.1  joerg     FileEdit &FA = I->second;
    211  1.1  joerg     FileOffset B = I->first;
    212  1.1  joerg     FileOffset E = B.getWithOffset(FA.RemoveLen);
    213  1.1  joerg 
    214  1.1  joerg     if (BeginOffs < E)
    215  1.1  joerg       break;
    216  1.1  joerg   }
    217  1.1  joerg 
    218  1.1  joerg   FileOffset TopBegin, TopEnd;
    219  1.1  joerg   FileEdit *TopFA = nullptr;
    220  1.1  joerg 
    221  1.1  joerg   if (I == FileEdits.end()) {
    222  1.1  joerg     FileEditsTy::iterator
    223  1.1  joerg       NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit()));
    224  1.1  joerg     NewI->second.RemoveLen = Len;
    225  1.1  joerg     return;
    226  1.1  joerg   }
    227  1.1  joerg 
    228  1.1  joerg   FileEdit &FA = I->second;
    229  1.1  joerg   FileOffset B = I->first;
    230  1.1  joerg   FileOffset E = B.getWithOffset(FA.RemoveLen);
    231  1.1  joerg   if (BeginOffs < B) {
    232  1.1  joerg     FileEditsTy::iterator
    233  1.1  joerg       NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit()));
    234  1.1  joerg     TopBegin = BeginOffs;
    235  1.1  joerg     TopEnd = EndOffs;
    236  1.1  joerg     TopFA = &NewI->second;
    237  1.1  joerg     TopFA->RemoveLen = Len;
    238  1.1  joerg   } else {
    239  1.1  joerg     TopBegin = B;
    240  1.1  joerg     TopEnd = E;
    241  1.1  joerg     TopFA = &I->second;
    242  1.1  joerg     if (TopEnd >= EndOffs)
    243  1.1  joerg       return;
    244  1.1  joerg     unsigned diff = EndOffs.getOffset() - TopEnd.getOffset();
    245  1.1  joerg     TopEnd = EndOffs;
    246  1.1  joerg     TopFA->RemoveLen += diff;
    247  1.1  joerg     if (B == BeginOffs)
    248  1.1  joerg       TopFA->Text = StringRef();
    249  1.1  joerg     ++I;
    250  1.1  joerg   }
    251  1.1  joerg 
    252  1.1  joerg   while (I != FileEdits.end()) {
    253  1.1  joerg     FileEdit &FA = I->second;
    254  1.1  joerg     FileOffset B = I->first;
    255  1.1  joerg     FileOffset E = B.getWithOffset(FA.RemoveLen);
    256  1.1  joerg 
    257  1.1  joerg     if (B >= TopEnd)
    258  1.1  joerg       break;
    259  1.1  joerg 
    260  1.1  joerg     if (E <= TopEnd) {
    261  1.1  joerg       FileEdits.erase(I++);
    262  1.1  joerg       continue;
    263  1.1  joerg     }
    264  1.1  joerg 
    265  1.1  joerg     if (B < TopEnd) {
    266  1.1  joerg       unsigned diff = E.getOffset() - TopEnd.getOffset();
    267  1.1  joerg       TopEnd = E;
    268  1.1  joerg       TopFA->RemoveLen += diff;
    269  1.1  joerg       FileEdits.erase(I);
    270  1.1  joerg     }
    271  1.1  joerg 
    272  1.1  joerg     break;
    273  1.1  joerg   }
    274  1.1  joerg }
    275  1.1  joerg 
    276  1.1  joerg bool EditedSource::commit(const Commit &commit) {
    277  1.1  joerg   if (!commit.isCommitable())
    278  1.1  joerg     return false;
    279  1.1  joerg 
    280  1.1  joerg   struct CommitRAII {
    281  1.1  joerg     EditedSource &Editor;
    282  1.1  joerg 
    283  1.1  joerg     CommitRAII(EditedSource &Editor) : Editor(Editor) {
    284  1.1  joerg       Editor.startingCommit();
    285  1.1  joerg     }
    286  1.1  joerg 
    287  1.1  joerg     ~CommitRAII() {
    288  1.1  joerg       Editor.finishedCommit();
    289  1.1  joerg     }
    290  1.1  joerg   } CommitRAII(*this);
    291  1.1  joerg 
    292  1.1  joerg   for (edit::Commit::edit_iterator
    293  1.1  joerg          I = commit.edit_begin(), E = commit.edit_end(); I != E; ++I) {
    294  1.1  joerg     const edit::Commit::Edit &edit = *I;
    295  1.1  joerg     switch (edit.Kind) {
    296  1.1  joerg     case edit::Commit::Act_Insert:
    297  1.1  joerg       commitInsert(edit.OrigLoc, edit.Offset, edit.Text, edit.BeforePrev);
    298  1.1  joerg       break;
    299  1.1  joerg     case edit::Commit::Act_InsertFromRange:
    300  1.1  joerg       commitInsertFromRange(edit.OrigLoc, edit.Offset,
    301  1.1  joerg                             edit.InsertFromRangeOffs, edit.Length,
    302  1.1  joerg                             edit.BeforePrev);
    303  1.1  joerg       break;
    304  1.1  joerg     case edit::Commit::Act_Remove:
    305  1.1  joerg       commitRemove(edit.OrigLoc, edit.Offset, edit.Length);
    306  1.1  joerg       break;
    307  1.1  joerg     }
    308  1.1  joerg   }
    309  1.1  joerg 
    310  1.1  joerg   return true;
    311  1.1  joerg }
    312  1.1  joerg 
    313  1.1  joerg // Returns true if it is ok to make the two given characters adjacent.
    314  1.1  joerg static bool canBeJoined(char left, char right, const LangOptions &LangOpts) {
    315  1.1  joerg   // FIXME: Should use TokenConcatenation to make sure we don't allow stuff like
    316  1.1  joerg   // making two '<' adjacent.
    317  1.1  joerg   return !(Lexer::isIdentifierBodyChar(left, LangOpts) &&
    318  1.1  joerg            Lexer::isIdentifierBodyChar(right, LangOpts));
    319  1.1  joerg }
    320  1.1  joerg 
    321  1.1  joerg /// Returns true if it is ok to eliminate the trailing whitespace between
    322  1.1  joerg /// the given characters.
    323  1.1  joerg static bool canRemoveWhitespace(char left, char beforeWSpace, char right,
    324  1.1  joerg                                 const LangOptions &LangOpts) {
    325  1.1  joerg   if (!canBeJoined(left, right, LangOpts))
    326  1.1  joerg     return false;
    327  1.1  joerg   if (isWhitespace(left) || isWhitespace(right))
    328  1.1  joerg     return true;
    329  1.1  joerg   if (canBeJoined(beforeWSpace, right, LangOpts))
    330  1.1  joerg     return false; // the whitespace was intentional, keep it.
    331  1.1  joerg   return true;
    332  1.1  joerg }
    333  1.1  joerg 
    334  1.1  joerg /// Check the range that we are going to remove and:
    335  1.1  joerg /// -Remove any trailing whitespace if possible.
    336  1.1  joerg /// -Insert a space if removing the range is going to mess up the source tokens.
    337  1.1  joerg static void adjustRemoval(const SourceManager &SM, const LangOptions &LangOpts,
    338  1.1  joerg                           SourceLocation Loc, FileOffset offs,
    339  1.1  joerg                           unsigned &len, StringRef &text) {
    340  1.1  joerg   assert(len && text.empty());
    341  1.1  joerg   SourceLocation BeginTokLoc = Lexer::GetBeginningOfToken(Loc, SM, LangOpts);
    342  1.1  joerg   if (BeginTokLoc != Loc)
    343  1.1  joerg     return; // the range is not at the beginning of a token, keep the range.
    344  1.1  joerg 
    345  1.1  joerg   bool Invalid = false;
    346  1.1  joerg   StringRef buffer = SM.getBufferData(offs.getFID(), &Invalid);
    347  1.1  joerg   if (Invalid)
    348  1.1  joerg     return;
    349  1.1  joerg 
    350  1.1  joerg   unsigned begin = offs.getOffset();
    351  1.1  joerg   unsigned end = begin + len;
    352  1.1  joerg 
    353  1.1  joerg   // Do not try to extend the removal if we're at the end of the buffer already.
    354  1.1  joerg   if (end == buffer.size())
    355  1.1  joerg     return;
    356  1.1  joerg 
    357  1.1  joerg   assert(begin < buffer.size() && end < buffer.size() && "Invalid range!");
    358  1.1  joerg 
    359  1.1  joerg   // FIXME: Remove newline.
    360  1.1  joerg 
    361  1.1  joerg   if (begin == 0) {
    362  1.1  joerg     if (buffer[end] == ' ')
    363  1.1  joerg       ++len;
    364  1.1  joerg     return;
    365  1.1  joerg   }
    366  1.1  joerg 
    367  1.1  joerg   if (buffer[end] == ' ') {
    368  1.1  joerg     assert((end + 1 != buffer.size() || buffer.data()[end + 1] == 0) &&
    369  1.1  joerg            "buffer not zero-terminated!");
    370  1.1  joerg     if (canRemoveWhitespace(/*left=*/buffer[begin-1],
    371  1.1  joerg                             /*beforeWSpace=*/buffer[end-1],
    372  1.1  joerg                             /*right=*/buffer.data()[end + 1], // zero-terminated
    373  1.1  joerg                             LangOpts))
    374  1.1  joerg       ++len;
    375  1.1  joerg     return;
    376  1.1  joerg   }
    377  1.1  joerg 
    378  1.1  joerg   if (!canBeJoined(buffer[begin-1], buffer[end], LangOpts))
    379  1.1  joerg     text = " ";
    380  1.1  joerg }
    381  1.1  joerg 
    382  1.1  joerg static void applyRewrite(EditsReceiver &receiver,
    383  1.1  joerg                          StringRef text, FileOffset offs, unsigned len,
    384  1.1  joerg                          const SourceManager &SM, const LangOptions &LangOpts,
    385  1.1  joerg                          bool shouldAdjustRemovals) {
    386  1.1  joerg   assert(offs.getFID().isValid());
    387  1.1  joerg   SourceLocation Loc = SM.getLocForStartOfFile(offs.getFID());
    388  1.1  joerg   Loc = Loc.getLocWithOffset(offs.getOffset());
    389  1.1  joerg   assert(Loc.isFileID());
    390  1.1  joerg 
    391  1.1  joerg   if (text.empty() && shouldAdjustRemovals)
    392  1.1  joerg     adjustRemoval(SM, LangOpts, Loc, offs, len, text);
    393  1.1  joerg 
    394  1.1  joerg   CharSourceRange range = CharSourceRange::getCharRange(Loc,
    395  1.1  joerg                                                      Loc.getLocWithOffset(len));
    396  1.1  joerg 
    397  1.1  joerg   if (text.empty()) {
    398  1.1  joerg     assert(len);
    399  1.1  joerg     receiver.remove(range);
    400  1.1  joerg     return;
    401  1.1  joerg   }
    402  1.1  joerg 
    403  1.1  joerg   if (len)
    404  1.1  joerg     receiver.replace(range, text);
    405  1.1  joerg   else
    406  1.1  joerg     receiver.insert(Loc, text);
    407  1.1  joerg }
    408  1.1  joerg 
    409  1.1  joerg void EditedSource::applyRewrites(EditsReceiver &receiver,
    410  1.1  joerg                                  bool shouldAdjustRemovals) {
    411  1.1  joerg   SmallString<128> StrVec;
    412  1.1  joerg   FileOffset CurOffs, CurEnd;
    413  1.1  joerg   unsigned CurLen;
    414  1.1  joerg 
    415  1.1  joerg   if (FileEdits.empty())
    416  1.1  joerg     return;
    417  1.1  joerg 
    418  1.1  joerg   FileEditsTy::iterator I = FileEdits.begin();
    419  1.1  joerg   CurOffs = I->first;
    420  1.1  joerg   StrVec = I->second.Text;
    421  1.1  joerg   CurLen = I->second.RemoveLen;
    422  1.1  joerg   CurEnd = CurOffs.getWithOffset(CurLen);
    423  1.1  joerg   ++I;
    424  1.1  joerg 
    425  1.1  joerg   for (FileEditsTy::iterator E = FileEdits.end(); I != E; ++I) {
    426  1.1  joerg     FileOffset offs = I->first;
    427  1.1  joerg     FileEdit act = I->second;
    428  1.1  joerg     assert(offs >= CurEnd);
    429  1.1  joerg 
    430  1.1  joerg     if (offs == CurEnd) {
    431  1.1  joerg       StrVec += act.Text;
    432  1.1  joerg       CurLen += act.RemoveLen;
    433  1.1  joerg       CurEnd.getWithOffset(act.RemoveLen);
    434  1.1  joerg       continue;
    435  1.1  joerg     }
    436  1.1  joerg 
    437  1.1  joerg     applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts,
    438  1.1  joerg                  shouldAdjustRemovals);
    439  1.1  joerg     CurOffs = offs;
    440  1.1  joerg     StrVec = act.Text;
    441  1.1  joerg     CurLen = act.RemoveLen;
    442  1.1  joerg     CurEnd = CurOffs.getWithOffset(CurLen);
    443  1.1  joerg   }
    444  1.1  joerg 
    445  1.1  joerg   applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts,
    446  1.1  joerg                shouldAdjustRemovals);
    447  1.1  joerg }
    448  1.1  joerg 
    449  1.1  joerg void EditedSource::clearRewrites() {
    450  1.1  joerg   FileEdits.clear();
    451  1.1  joerg   StrAlloc.Reset();
    452  1.1  joerg }
    453  1.1  joerg 
    454  1.1  joerg StringRef EditedSource::getSourceText(FileOffset BeginOffs, FileOffset EndOffs,
    455  1.1  joerg                                       bool &Invalid) {
    456  1.1  joerg   assert(BeginOffs.getFID() == EndOffs.getFID());
    457  1.1  joerg   assert(BeginOffs <= EndOffs);
    458  1.1  joerg   SourceLocation BLoc = SourceMgr.getLocForStartOfFile(BeginOffs.getFID());
    459  1.1  joerg   BLoc = BLoc.getLocWithOffset(BeginOffs.getOffset());
    460  1.1  joerg   assert(BLoc.isFileID());
    461  1.1  joerg   SourceLocation
    462  1.1  joerg     ELoc = BLoc.getLocWithOffset(EndOffs.getOffset() - BeginOffs.getOffset());
    463  1.1  joerg   return Lexer::getSourceText(CharSourceRange::getCharRange(BLoc, ELoc),
    464  1.1  joerg                               SourceMgr, LangOpts, &Invalid);
    465  1.1  joerg }
    466  1.1  joerg 
    467  1.1  joerg EditedSource::FileEditsTy::iterator
    468  1.1  joerg EditedSource::getActionForOffset(FileOffset Offs) {
    469  1.1  joerg   FileEditsTy::iterator I = FileEdits.upper_bound(Offs);
    470  1.1  joerg   if (I == FileEdits.begin())
    471  1.1  joerg     return FileEdits.end();
    472  1.1  joerg   --I;
    473  1.1  joerg   FileEdit &FA = I->second;
    474  1.1  joerg   FileOffset B = I->first;
    475  1.1  joerg   FileOffset E = B.getWithOffset(FA.RemoveLen);
    476  1.1  joerg   if (Offs >= B && Offs < E)
    477  1.1  joerg     return I;
    478  1.1  joerg 
    479  1.1  joerg   return FileEdits.end();
    480  1.1  joerg }
    481