xref: /minix3/external/bsd/llvm/dist/clang/lib/Edit/EditedSource.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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