18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/StringRef.h"
20#include "llvm/ADT/Twine.h"
34 MacroArgUse &ArgUse) {
35 assert(SourceMgr.isMacroArgExpansion(Loc));
37 SourceMgr.getImmediateExpansionRange(Loc).getBegin();
39 SourceMgr.getImmediateExpansionRange(DefArgLoc).getBegin();
40 ExpansionLoc = ImmediateExpansionLoc;
41 while (SourceMgr.isMacroBodyExpansion(ExpansionLoc))
43 SourceMgr.getImmediateExpansionRange(ExpansionLoc).getBegin();
46 Buf, SourceMgr, LangOpts);
49 ArgUse = {&IdentTable.
get(ArgName), ImmediateExpansionLoc,
50 SourceMgr.getSpellingLoc(DefArgLoc)};
53void EditedSource::startingCommit() {}
55void EditedSource::finishedCommit() {
56 for (
auto &ExpArg : CurrCommitMacroArgExps) {
57 SourceLocation ExpLoc;
59 std::tie(ExpLoc, ArgUse) = ExpArg;
60 auto &ArgUses = ExpansionToArgMap[ExpLoc];
61 if (!llvm::is_contained(ArgUses, ArgUse))
62 ArgUses.push_back(ArgUse);
64 CurrCommitMacroArgExps.clear();
73 FileEditsTy::iterator FA = getActionForOffset(Offs);
74 if (FA != FileEdits.end()) {
75 if (FA->first != Offs)
79 if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
82 deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
83 auto I = ExpansionToArgMap.find(ExpLoc);
84 if (I != ExpansionToArgMap.end() &&
85 llvm::any_of(I->second, [&](
const MacroArgUse &
U) {
86 return ArgUse.Identifier == U.Identifier &&
87 std::tie(ArgUse.ImmediateExpansionLoc, ArgUse.UseLoc) !=
88 std::tie(U.ImmediateExpansionLoc, U.UseLoc);
111 bool beforePreviousInsertions) {
117 if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
120 deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
121 if (ArgUse.Identifier)
122 CurrCommitMacroArgExps.emplace_back(ExpLoc, ArgUse);
125 FileEdit &FA = FileEdits[Offs];
126 if (FA.Text.empty()) {
131 if (beforePreviousInsertions)
139bool EditedSource::commitInsertFromRange(SourceLocation OrigLoc,
142 bool beforePreviousInsertions) {
146 SmallString<128> StrVec;
147 FileOffset BeginOffs = InsertFromRangeOffs;
149 FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs);
150 if (I != FileEdits.begin())
153 for (; I != FileEdits.end(); ++I) {
154 FileEdit &FA = I->second;
155 FileOffset B = I->first;
170 for (; I != FileEdits.end() && EndOffs > I->first; ++I) {
171 FileEdit &FA = I->second;
172 FileOffset B = I->first;
177 StringRef
text = getSourceText(BeginOffs, B,
Invalid);
186 if (BeginOffs < EndOffs) {
188 StringRef
text = getSourceText(BeginOffs, EndOffs,
Invalid);
194 return commitInsert(OrigLoc, Offs, StrVec, beforePreviousInsertions);
197void EditedSource::commitRemove(SourceLocation OrigLoc,
203 FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs);
204 if (I != FileEdits.begin())
207 for (; I != FileEdits.end(); ++I) {
208 FileEdit &FA = I->second;
209 FileOffset B = I->first;
216 FileOffset TopBegin, TopEnd;
217 FileEdit *TopFA =
nullptr;
219 if (I == FileEdits.end()) {
220 FileEditsTy::iterator
221 NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit()));
222 NewI->second.RemoveLen = Len;
226 FileEdit &FA = I->second;
227 FileOffset B = I->first;
230 FileEditsTy::iterator
231 NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit()));
232 TopBegin = BeginOffs;
234 TopFA = &NewI->second;
235 TopFA->RemoveLen = Len;
240 if (TopEnd >= EndOffs)
244 TopFA->RemoveLen += diff;
246 TopFA->Text = StringRef();
250 while (I != FileEdits.end()) {
251 FileEdit &FA = I->second;
252 FileOffset B = I->first;
259 FileEdits.erase(I++);
266 TopFA->RemoveLen += diff;
275 if (!
commit.isCommitable())
282 Editor.startingCommit();
286 Editor.finishedCommit();
291 I =
commit.edit_begin(), E =
commit.edit_end(); I != E; ++I) {
298 commitInsertFromRange(
edit.OrigLoc,
edit.Offset,
299 edit.InsertFromRangeOffs,
edit.Length,
337 unsigned &len, StringRef &text) {
338 assert(len && text.empty());
340 if (BeginTokLoc != Loc)
349 unsigned end = begin + len;
352 if (end == buffer.size())
355 assert(begin < buffer.size() && end < buffer.size() &&
"Invalid range!");
360 if (buffer[end] ==
' ')
365 if (buffer[end] ==
' ') {
366 assert((end + 1 != buffer.size() || buffer.data()[end + 1] == 0) &&
367 "buffer not zero-terminated!");
370 buffer.data()[end + 1],
376 if (!
canBeJoined(buffer[begin-1], buffer[end], LangOpts))
381 StringRef text,
FileOffset offs,
unsigned len,
383 bool shouldAdjustRemovals) {
389 if (text.empty() && shouldAdjustRemovals)
404 receiver.
insert(Loc, text);
408 bool shouldAdjustRemovals) {
413 if (FileEdits.empty())
416 FileEditsTy::iterator I = FileEdits.begin();
418 StrVec = I->second.Text;
419 CurLen = I->second.RemoveLen;
423 for (FileEditsTy::iterator E = FileEdits.end(); I != E; ++I) {
425 FileEdit act = I->second;
426 assert(offs >= CurEnd);
428 if (offs == CurEnd) {
430 CurLen += act.RemoveLen;
435 applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts,
436 shouldAdjustRemovals);
439 CurLen = act.RemoveLen;
443 applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts,
444 shouldAdjustRemovals);
455 assert(BeginOffs <= EndOffs);
462 SourceMgr, LangOpts, &
Invalid);
465EditedSource::FileEditsTy::iterator
466EditedSource::getActionForOffset(
FileOffset Offs) {
467 FileEditsTy::iterator I = FileEdits.upper_bound(Offs);
468 if (I == FileEdits.begin())
469 return FileEdits.end();
471 FileEdit &FA = I->second;
474 if (Offs >= B && Offs < E)
477 return FileEdits.end();
static bool canBeJoined(char left, char right, const LangOptions &LangOpts)
static void applyRewrite(EditsReceiver &receiver, StringRef text, FileOffset offs, unsigned len, const SourceManager &SM, const LangOptions &LangOpts, bool shouldAdjustRemovals)
static void adjustRemoval(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation Loc, FileOffset offs, unsigned &len, StringRef &text)
Check the range that we are going to remove and: -Remove any trailing whitespace if possible.
static bool canRemoveWhitespace(char left, char beforeWSpace, char right, const LangOptions &LangOpts)
Returns true if it is ok to eliminate the trailing whitespace between the given characters.
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)
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
static unsigned getSpelling(const Token &Tok, const char *&Buffer, const SourceManager &SourceMgr, const LangOptions &LangOpts, bool *Invalid=nullptr)
getSpelling - This method is used to get the spelling of a token into a preallocated buffer,...
static bool isAsciiIdentifierContinueChar(char c, const LangOptions &LangOpts)
Returns true if the given character could appear in an identifier.
static SourceLocation GetBeginningOfToken(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
Given a location any where in a source buffer, find the location that corresponds to the beginning of...
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.
SmallVectorImpl< Edit >::const_iterator edit_iterator
StringRef copyString(StringRef str)
bool canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs)
void applyRewrites(EditsReceiver &receiver, bool adjustRemovals=true)
bool commit(const Commit &commit)
EditedSource(const SourceManager &SM, const LangOptions &LangOpts, const PPConditionalDirectiveRecord *PPRec=nullptr)
virtual void insert(SourceLocation loc, StringRef text)=0
virtual void remove(CharSourceRange range)
By default it calls replace with an empty string.
virtual void replace(CharSourceRange range, StringRef text)=0
FileOffset getWithOffset(unsigned offset) const
unsigned getOffset() const
The JSON file list parser is used to communicate input to InstallAPI.
LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t',...