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