Home | History | Annotate | Line # | Download | only in Edit
      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.1.2  joerg     auto &ArgUses = ExpansionToArgMap[ExpLoc];
     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.1.2  joerg     auto I = ExpansionToArgMap.find(ExpLoc);
     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