EditedSource.cpp revision 1.1.1.2 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