16 #include "llvm/ADT/SmallString.h"
17 #include "llvm/ADT/Twine.h"
19 using namespace clang;
28 MacroArgUse &ArgUse) {
33 ExpansionLoc = ImmediateExpansionLoc;
38 Buf, SourceMgr, LangOpts);
41 ArgUse = {&IdentTable.
get(ArgName), ImmediateExpansionLoc,
42 SourceMgr.getSpellingLoc(DefArgLoc)};
45 void EditedSource::startingCommit() {}
47 void EditedSource::finishedCommit() {
48 for (
auto &ExpArg : CurrCommitMacroArgExps) {
51 std::tie(ExpLoc, ArgUse) = ExpArg;
53 if (std::find(ArgUses.begin(), ArgUses.end(), ArgUse) == ArgUses.end())
54 ArgUses.push_back(ArgUse);
56 CurrCommitMacroArgExps.clear();
65 FileEditsTy::iterator FA = getActionForOffset(Offs);
66 if (FA != FileEdits.end()) {
67 if (FA->first != Offs)
71 if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
74 deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
76 if (
I != ExpansionToArgMap.end() &&
77 find_if(
I->second, [&](
const MacroArgUse &U) {
78 return ArgUse.Identifier == U.Identifier &&
79 std::tie(ArgUse.ImmediateExpansionLoc, ArgUse.UseLoc) !=
80 std::tie(U.ImmediateExpansionLoc, U.UseLoc);
81 }) !=
I->second.end()) {
103 bool beforePreviousInsertions) {
104 if (!canInsertInOffset(OrigLoc, Offs))
109 if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
112 deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
113 if (ArgUse.Identifier)
114 CurrCommitMacroArgExps.emplace_back(ExpLoc, ArgUse);
117 FileEdit &FA = FileEdits[Offs];
118 if (FA.Text.empty()) {
123 if (beforePreviousInsertions)
134 bool beforePreviousInsertions) {
141 FileEditsTy::iterator
I = FileEdits.upper_bound(BeginOffs);
142 if (I != FileEdits.begin())
145 for (; I != FileEdits.end(); ++
I) {
146 FileEdit &FA = I->second;
162 for (; I != FileEdits.end() && EndOffs > I->first; ++
I) {
163 FileEdit &FA = I->second;
169 StringRef text = getSourceText(BeginOffs, B, Invalid);
178 if (BeginOffs < EndOffs) {
180 StringRef text = getSourceText(BeginOffs, EndOffs, Invalid);
186 return commitInsert(OrigLoc, Offs, StrVec, beforePreviousInsertions);
195 FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs);
196 if (I != FileEdits.begin())
199 for (; I != FileEdits.end(); ++
I) {
200 FileEdit &FA = I->second;
209 FileEdit *TopFA =
nullptr;
211 if (I == FileEdits.end()) {
212 FileEditsTy::iterator
213 NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit()));
214 NewI->second.RemoveLen = Len;
218 FileEdit &FA = I->second;
222 FileEditsTy::iterator
223 NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit()));
224 TopBegin = BeginOffs;
226 TopFA = &NewI->second;
227 TopFA->RemoveLen = Len;
232 if (TopEnd >= EndOffs)
236 TopFA->RemoveLen += diff;
238 TopFA->Text = StringRef();
242 while (I != FileEdits.end()) {
243 FileEdit &FA = I->second;
251 FileEdits.erase(I++);
258 TopFA->RemoveLen += diff;
266 bool EditedSource::commit(
const Commit &commit) {
273 Editor.startingCommit();
276 Editor.finishedCommit();
327 unsigned &len, StringRef &text) {
328 assert(len && text.empty());
330 if (BeginTokLoc != Loc)
333 bool Invalid =
false;
339 unsigned end = begin + len;
342 if (end == buffer.size())
345 assert(begin < buffer.size() && end < buffer.size() &&
"Invalid range!");
350 if (buffer[end] ==
' ')
355 if (buffer[end] ==
' ') {
356 assert((end + 1 != buffer.size() || buffer.data()[end + 1] == 0) &&
357 "buffer not zero-terminated!");
360 buffer.data()[end + 1],
366 if (!
canBeJoined(buffer[begin-1], buffer[end], LangOpts))
371 StringRef text,
FileOffset offs,
unsigned len,
373 bool shouldAdjustRemovals) {
377 assert(Loc.isFileID());
379 if (text.empty() && shouldAdjustRemovals)
383 Loc.getLocWithOffset(len));
394 receiver.
insert(Loc, text);
398 bool shouldAdjustRemovals) {
403 if (FileEdits.empty())
406 FileEditsTy::iterator I = FileEdits.begin();
408 StrVec = I->second.Text;
409 CurLen = I->second.RemoveLen;
413 for (FileEditsTy::iterator E = FileEdits.end(); I !=
E; ++
I) {
415 FileEdit act = I->second;
416 assert(offs >= CurEnd);
418 if (offs == CurEnd) {
420 CurLen += act.RemoveLen;
425 applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts,
426 shouldAdjustRemovals);
429 CurLen = act.RemoveLen;
433 applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts,
434 shouldAdjustRemovals);
437 void EditedSource::clearRewrites() {
445 assert(BeginOffs <= EndOffs);
452 SourceMgr, LangOpts, &Invalid);
455 EditedSource::FileEditsTy::iterator
456 EditedSource::getActionForOffset(
FileOffset Offs) {
457 FileEditsTy::iterator I = FileEdits.upper_bound(Offs);
458 if (I == FileEdits.begin())
459 return FileEdits.end();
461 FileEdit &FA = I->second;
464 if (Offs >= B && Offs < E)
467 return FileEdits.end();
bool isMacroArgExpansion(SourceLocation Loc, SourceLocation *StartLoc=nullptr) const
Tests whether the given source location represents a macro argument's expansion into the function-lik...
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 LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t', '\f', '\v', '\n', '\r'.
SourceLocation getSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID. ...
Defines the SourceManager interface.
unsigned getRawEncoding() const
When a SourceLocation itself cannot be used, this returns an (opaque) 32-bit integer encoding for it...
unsigned getOffset() const
FileOffset getWithOffset(unsigned offset) const
StringRef getBufferData(FileID FID, bool *Invalid=nullptr) const
Return a StringRef to the source buffer data for the specified FileID.
bool isCommitable() const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
bool isMacroBodyExpansion(SourceLocation Loc) const
Tests whether the given source location represents the expansion of a macro body. ...
detail::InMemoryDirectory::const_iterator I
edit_iterator edit_begin() const
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
Represents a character-granular source range.
virtual void replace(CharSourceRange range, StringRef text)=0
FileOffset InsertFromRangeOffs
virtual void remove(CharSourceRange range)
By default it calls replace with an empty string.
edit_iterator edit_end() const
static CharSourceRange getCharRange(SourceRange R)
Encodes a location in the source.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
static bool canBeJoined(char left, char right, const LangOptions &LangOpts)
SmallVectorImpl< Edit >::const_iterator edit_iterator
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...
StringRef copyString(StringRef str)
std::pair< SourceLocation, SourceLocation > getImmediateExpansionRange(SourceLocation Loc) const
Return the start/end of the expansion information for an expansion location.
detail::InMemoryDirectory::const_iterator E
static bool isIdentifierBodyChar(char c, const LangOptions &LangOpts)
Returns true if the given character could appear in an identifier.
bool canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs)
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.
virtual void insert(SourceLocation loc, StringRef text)=0
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...
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file. ...
static void applyRewrite(EditsReceiver &receiver, StringRef text, FileOffset offs, unsigned len, const SourceManager &SM, const LangOptions &LangOpts, bool shouldAdjustRemovals)
This class handles loading and caching of source files into memory.