17#include "llvm/ADT/StringRef.h"
43 : SourceMgr(Editor.getSourceManager()), LangOpts(Editor.getLangOpts()),
44 PPRec(Editor.getPPCondDirectiveRecord()),
48 bool afterToken,
bool beforePreviousInsertions) {
53 if ((!afterToken && !canInsert(loc, Offs)) ||
54 ( afterToken && !canInsertAfterToken(loc, Offs, loc))) {
59 addInsert(loc, Offs, text, beforePreviousInsertions);
65 bool afterToken,
bool beforePreviousInsertions) {
68 if (!canRemoveRange(range, RangeOffs, RangeLen)) {
74 if ((!afterToken && !canInsert(loc, Offs)) ||
75 ( afterToken && !canInsertAfterToken(loc, Offs, loc))) {
81 PPRec->areInDifferentConditionalDirectiveRegion(loc, range.getBegin())) {
86 addInsertFromRange(loc, Offs, RangeOffs, RangeLen, beforePreviousInsertions);
93 if (!canRemoveRange(range, Offs, Len)) {
98 addRemove(range.getBegin(), Offs, Len);
104 bool commitableBefore =
insert(range.getBegin(), before,
false,
106 bool commitableAfter;
107 if (range.isTokenRange())
110 commitableAfter =
insert(range.getEnd(), after);
112 return commitableBefore && commitableAfter;
121 if (!canInsert(range.getBegin(), Offs) || !canRemoveRange(range, Offs, Len)) {
122 IsCommitable =
false;
126 addRemove(range.getBegin(), Offs, Len);
127 addInsert(range.getBegin(), Offs, text,
false);
135 if (!canRemoveRange(range, OuterBegin, OuterLen)) {
136 IsCommitable =
false;
142 if (!canRemoveRange(replacementRange, InnerBegin, InnerLen)) {
143 IsCommitable =
false;
150 InnerBegin < OuterBegin ||
151 InnerBegin > OuterEnd ||
152 InnerEnd > OuterEnd) {
153 IsCommitable =
false;
157 addRemove(range.getBegin(),
159 addRemove(replacementRange.
getEnd(),
165 StringRef replacementText) {
166 if (text.empty() || replacementText.empty())
171 if (!canReplaceText(loc, replacementText, Offs, Len)) {
172 IsCommitable =
false;
176 addRemove(loc, Offs, Len);
177 addInsert(loc, Offs, text,
false);
182 bool beforePreviousInsertions) {
188 data.OrigLoc = OrigLoc;
190 data.Text = text.copy(StrAlloc);
191 data.BeforePrev = beforePreviousInsertions;
192 CachedEdits.push_back(data);
197 bool beforePreviousInsertions) {
203 data.OrigLoc = OrigLoc;
205 data.InsertFromRangeOffs = RangeOffs;
206 data.Length = RangeLen;
207 data.BeforePrev = beforePreviousInsertions;
208 CachedEdits.push_back(data);
218 data.OrigLoc = OrigLoc;
221 CachedEdits.push_back(data);
224bool Commit::canInsert(SourceLocation loc,
FileOffset &offs) {
229 isAtStartOfMacroExpansion(loc, &loc);
231 const SourceManager &
SM = SourceMgr;
232 loc =
SM.getTopMacroCallerLoc(loc);
235 if (!isAtStartOfMacroExpansion(loc, &loc))
238 if (
SM.isInSystemHeader(loc))
242 if (locInfo.first.isInvalid())
244 offs = FileOffset(locInfo.first, locInfo.second);
245 return canInsertInOffset(loc, offs);
248bool Commit::canInsertAfterToken(SourceLocation loc,
FileOffset &offs,
249 SourceLocation &AfterLoc) {
254 SourceLocation spellLoc = SourceMgr.getSpellingLoc(loc);
259 isAtEndOfMacroExpansion(loc, &loc);
261 const SourceManager &
SM = SourceMgr;
262 loc =
SM.getTopMacroCallerLoc(loc);
265 if (!isAtEndOfMacroExpansion(loc, &loc))
268 if (
SM.isInSystemHeader(loc))
276 if (locInfo.first.isInvalid())
278 offs = FileOffset(locInfo.first, locInfo.second);
279 return canInsertInOffset(loc, offs);
282bool Commit::canInsertInOffset(SourceLocation OrigLoc,
FileOffset Offs) {
283 for (
const auto &act : CachedEdits)
285 if (act.Offset.getFID() == Offs.
getFID() &&
286 Offs > act.Offset && Offs < act.Offset.getWithOffset(act.Length))
292 return Editor->canInsertInOffset(OrigLoc, Offs);
295bool Commit::canRemoveRange(CharSourceRange range,
297 const SourceManager &
SM = SourceMgr;
299 if (
range.isInvalid())
302 if (
range.getBegin().isMacroID() ||
range.getEnd().isMacroID())
304 if (
SM.isInSystemHeader(
range.getBegin()) ||
305 SM.isInSystemHeader(
range.getEnd()))
308 if (PPRec && PPRec->rangeIntersectsConditionalDirective(
range.getAsRange()))
313 if (beginInfo.first != endInfo.first ||
314 beginInfo.second > endInfo.second)
317 Offs = FileOffset(beginInfo.first, beginInfo.second);
318 Len = endInfo.second - beginInfo.second;
322bool Commit::canReplaceText(SourceLocation loc, StringRef text,
324 assert(!
text.empty());
326 if (!canInsert(loc, Offs))
330 bool invalidTemp =
false;
331 StringRef file = SourceMgr.getBufferData(Offs.
getFID(), &invalidTemp);
336 return file.substr(Offs.
getOffset()).starts_with(text);
339bool Commit::isAtStartOfMacroExpansion(SourceLocation loc,
340 SourceLocation *MacroBegin)
const {
344bool Commit::isAtEndOfMacroExpansion(SourceLocation loc,
345 SourceLocation *MacroEnd)
const {
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Represents a character-granular source range.
static CharSourceRange getCharRange(SourceRange R)
SourceLocation getEnd() const
static bool isAtStartOfMacroExpansion(SourceLocation loc, const SourceManager &SM, const LangOptions &LangOpts, SourceLocation *MacroBegin=nullptr)
Returns true if the given MacroID location points at the first token of the macro expansion.
static bool isAtEndOfMacroExpansion(SourceLocation loc, const SourceManager &SM, const LangOptions &LangOpts, SourceLocation *MacroEnd=nullptr)
Returns true if the given MacroID location points at the last token of the macro expansion.
static CharSourceRange makeFileCharRange(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts)
Accepts a range and returns a character range with file locations.
static unsigned MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
MeasureTokenLength - Relex the token at the specified location and return its length in bytes in the ...
static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts)
Computes the source location just past the end of the token at this source location.
Encodes a location in the source.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
bool replaceWithInner(CharSourceRange range, CharSourceRange innerRange)
bool insertWrap(StringRef before, CharSourceRange range, StringRef after)
bool insertFromRange(SourceLocation loc, CharSourceRange range, bool afterToken=false, bool beforePreviousInsertions=false)
bool insert(SourceLocation loc, StringRef text, bool afterToken=false, bool beforePreviousInsertions=false)
Commit(EditedSource &Editor)
bool insertAfterToken(SourceLocation loc, StringRef text, bool beforePreviousInsertions=false)
bool remove(CharSourceRange range)
bool replace(CharSourceRange range, StringRef text)
bool replaceText(SourceLocation loc, StringRef text, StringRef replacementText)
FileOffset getWithOffset(unsigned offset) const
unsigned getOffset() const
The JSON file list parser is used to communicate input to InstallAPI.
std::pair< FileID, unsigned > FileIDAndOffset
SourceLocation getFileLocation(SourceManager &SM) const
CharSourceRange getFileRange(SourceManager &SM) const
FileOffset InsertFromRangeOffs
CharSourceRange getInsertFromRange(SourceManager &SM) const