bool Commit::replaceWithInner(CharSourceRange range, CharSourceRange replacementRange) { FileOffset OuterBegin; unsigned OuterLen; if (!canRemoveRange(range, OuterBegin, OuterLen)) { IsCommitable = false; return false; } FileOffset InnerBegin; unsigned InnerLen; if (!canRemoveRange(replacementRange, InnerBegin, InnerLen)) { IsCommitable = false; return false; } FileOffset OuterEnd = OuterBegin.getWithOffset(OuterLen); FileOffset InnerEnd = InnerBegin.getWithOffset(InnerLen); if (OuterBegin.getFID() != InnerBegin.getFID() || InnerBegin < OuterBegin || InnerBegin > OuterEnd || InnerEnd > OuterEnd) { IsCommitable = false; return false; } addRemove(range.getBegin(), OuterBegin, InnerBegin.getOffset() - OuterBegin.getOffset()); addRemove(replacementRange.getEnd(), InnerEnd, OuterEnd.getOffset() - InnerEnd.getOffset()); return true; }
StringRef EditedSource::getSourceText(FileOffset BeginOffs, FileOffset EndOffs, bool &Invalid) { assert(BeginOffs.getFID() == EndOffs.getFID()); assert(BeginOffs <= EndOffs); SourceLocation BLoc = SourceMgr.getLocForStartOfFile(BeginOffs.getFID()); BLoc = BLoc.getLocWithOffset(BeginOffs.getOffset()); assert(BLoc.isFileID()); SourceLocation ELoc = BLoc.getLocWithOffset(EndOffs.getOffset() - BeginOffs.getOffset()); return Lexer::getSourceText(CharSourceRange::getCharRange(BLoc, ELoc), SourceMgr, LangOpts, &Invalid); }
static void applyRewrite(EditsReceiver &receiver, StringRef text, FileOffset offs, unsigned len, const SourceManager &SM, const LangOptions &LangOpts) { assert(!offs.getFID().isInvalid()); SourceLocation Loc = SM.getLocForStartOfFile(offs.getFID()); Loc = Loc.getLocWithOffset(offs.getOffset()); assert(Loc.isFileID()); if (text.empty()) adjustRemoval(SM, LangOpts, Loc, offs, len, text); CharSourceRange range = CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(len)); if (text.empty()) { assert(len); receiver.remove(range); return; } if (len) receiver.replace(range, text); else receiver.insert(Loc, text); }
bool Commit::canReplaceText(SourceLocation loc, StringRef text, FileOffset &Offs, unsigned &Len) { assert(!text.empty()); if (!canInsert(loc, Offs)) return false; // Try to load the file buffer. bool invalidTemp = false; StringRef file = SourceMgr.getBufferData(Offs.getFID(), &invalidTemp); if (invalidTemp) return false; Len = text.size(); return file.substr(Offs.getOffset()).startswith(text); }
/// \brief Check the range that we are going to remove and: /// -Remove any trailing whitespace if possible. /// -Insert a space if removing the range is going to mess up the source tokens. static void adjustRemoval(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation Loc, FileOffset offs, unsigned &len, StringRef &text) { assert(len && text.empty()); SourceLocation BeginTokLoc = Lexer::GetBeginningOfToken(Loc, SM, LangOpts); if (BeginTokLoc != Loc) return; // the range is not at the beginning of a token, keep the range. bool Invalid = false; StringRef buffer = SM.getBufferData(offs.getFID(), &Invalid); if (Invalid) return; unsigned begin = offs.getOffset(); unsigned end = begin + len; // Do not try to extend the removal if we're at the end of the buffer already. if (end == buffer.size()) return; assert(begin < buffer.size() && end < buffer.size() && "Invalid range!"); // FIXME: Remove newline. if (begin == 0) { if (buffer[end] == ' ') ++len; return; } if (buffer[end] == ' ') { assert((end + 1 != buffer.size() || buffer.data()[end + 1] == 0) && "buffer not zero-terminated!"); if (canRemoveWhitespace(/*left=*/buffer[begin-1], /*beforeWSpace=*/buffer[end-1], /*right=*/buffer.data()[end + 1], // zero-terminated LangOpts)) ++len; return; } if (!canBeJoined(buffer[begin-1], buffer[end], LangOpts)) text = " "; }
/// \brief Check the range that we are going to remove and: /// -Remove any trailing whitespace if possible. /// -Insert a space if removing the range is going to mess up the source tokens. static void adjustRemoval(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation Loc, FileOffset offs, unsigned &len, StringRef &text) { assert(len && text.empty()); SourceLocation BeginTokLoc = Lexer::GetBeginningOfToken(Loc, SM, LangOpts); if (BeginTokLoc != Loc) return; // the range is not at the beginning of a token, keep the range. bool Invalid = false; StringRef buffer = SM.getBufferData(offs.getFID(), &Invalid); if (Invalid) return; unsigned begin = offs.getOffset(); unsigned end = begin + len; // FIXME: Remove newline. if (begin == 0) { if (buffer[end] == ' ') ++len; return; } if (buffer[end] == ' ') { if (canRemoveWhitespace(/*left=*/buffer[begin-1], /*beforeWSpace=*/buffer[end-1], /*right=*/buffer[end+1], LangOpts)) ++len; return; } if (!canBeJoined(buffer[begin-1], buffer[end], LangOpts)) text = " "; }
void EditedSource::commitRemove(SourceLocation OrigLoc, FileOffset BeginOffs, unsigned Len) { if (Len == 0) return; FileOffset EndOffs = BeginOffs.getWithOffset(Len); FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs); if (I != FileEdits.begin()) --I; for (; I != FileEdits.end(); ++I) { FileEdit &FA = I->second; FileOffset B = I->first; FileOffset E = B.getWithOffset(FA.RemoveLen); if (BeginOffs < E) break; } FileOffset TopBegin, TopEnd; FileEdit *TopFA = nullptr; if (I == FileEdits.end()) { FileEditsTy::iterator NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit())); NewI->second.RemoveLen = Len; return; } FileEdit &FA = I->second; FileOffset B = I->first; FileOffset E = B.getWithOffset(FA.RemoveLen); if (BeginOffs < B) { FileEditsTy::iterator NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit())); TopBegin = BeginOffs; TopEnd = EndOffs; TopFA = &NewI->second; TopFA->RemoveLen = Len; } else { TopBegin = B; TopEnd = E; TopFA = &I->second; if (TopEnd >= EndOffs) return; unsigned diff = EndOffs.getOffset() - TopEnd.getOffset(); TopEnd = EndOffs; TopFA->RemoveLen += diff; if (B == BeginOffs) TopFA->Text = StringRef(); ++I; } while (I != FileEdits.end()) { FileEdit &FA = I->second; FileOffset B = I->first; FileOffset E = B.getWithOffset(FA.RemoveLen); if (B >= TopEnd) break; if (E <= TopEnd) { FileEdits.erase(I++); continue; } if (B < TopEnd) { unsigned diff = E.getOffset() - TopEnd.getOffset(); TopEnd = E; TopFA->RemoveLen += diff; FileEdits.erase(I); } break; } }