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