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