23 #include "llvm/Support/FileSystem.h"
24 #include "llvm/Support/Path.h"
25 #include "llvm/Support/raw_os_ostream.h"
36 StringRef ReplacementText)
37 : FilePath(FilePath), ReplacementRange(Offset, Length),
38 ReplacementText(ReplacementText) {}
41 unsigned Length, StringRef ReplacementText) {
42 setFromSourceLocation(Sources, Start, Length, ReplacementText);
47 StringRef ReplacementText,
49 setFromSourceRange(Sources, Range, ReplacementText, LangOpts);
65 getLocWithOffset(ReplacementRange.
getOffset());
70 Start, ReplacementRange.
getLength(), ReplacementText);
71 assert(RewriteSucceeded);
72 return RewriteSucceeded;
77 llvm::raw_string_ostream Stream(Result);
78 Stream << FilePath <<
": " << ReplacementRange.
getOffset() <<
":+"
79 << ReplacementRange.
getLength() <<
":\"" << ReplacementText <<
"\"";
105 void Replacement::setFromSourceLocation(
const SourceManager &Sources,
107 StringRef ReplacementText) {
108 const std::pair<FileID, unsigned> DecomposedLocation =
112 this->ReplacementRange = Range(DecomposedLocation.second, Length);
113 this->ReplacementText = ReplacementText;
124 std::pair<FileID, unsigned> Start = Sources.
getDecomposedLoc(SpellingBegin);
126 if (Start.first != End.first)
return -1;
129 return End.second - Start.second;
132 void Replacement::setFromSourceRange(
const SourceManager &Sources,
134 StringRef ReplacementText,
141 template <
typename T>
144 for (
const auto& R : Replaces) {
145 if (R.getOffset() + R.getLength() <=
Position) {
146 Offset += R.getReplacementText().size() - R.getLength();
149 if (R.getOffset() < Position &&
150 R.getOffset() + R.getReplacementText().size() <=
Position) {
151 Position = R.getOffset() + R.getReplacementText().size() - 1;
170 std::vector<Range> &Conflicts) {
171 if (Replaces.empty())
176 return LHS.
getOffset() < RHS.getOffset();
178 return LHS.
getLength() < RHS.getLength();
183 return LHS.
getOffset() == RHS.getOffset() &&
190 std::sort(Replaces.begin(), Replaces.end(), LessNoPath);
191 Replaces.erase(std::unique(Replaces.begin(), Replaces.end(), EqualNoPath),
195 Range ConflictRange(Replaces.front().getOffset(),
196 Replaces.front().getLength());
197 unsigned ConflictStart = 0;
198 unsigned ConflictLength = 1;
199 for (
unsigned i = 1; i < Replaces.size(); ++i) {
200 Range
Current(Replaces[i].getOffset(), Replaces[i].getLength());
201 if (ConflictRange.overlapsWith(Current)) {
203 ConflictRange = Range(ConflictRange.getOffset(),
206 ConflictRange.getOffset()));
209 if (ConflictLength > 1)
210 Conflicts.push_back(Range(ConflictStart, ConflictLength));
217 if (ConflictLength > 1)
218 Conflicts.push_back(Range(ConflictStart, ConflictLength));
223 for (Replacements::const_iterator
I = Replaces.begin(),
226 if (
I->isApplicable()) {
227 Result =
I->apply(Rewrite) && Result;
240 for (std::vector<Replacement>::const_iterator
I = Replaces.begin(),
243 if (
I->isApplicable()) {
244 Result =
I->apply(Rewrite) && Result;
254 if (Replaces.empty())
265 InMemoryFileSystem->addFile(
266 "<stdin>", 0, llvm::MemoryBuffer::getMemBuffer(Code,
"<stdin>"));
269 for (Replacements::const_iterator
I = Replaces.begin(),
E = Replaces.end();
271 Replacement Replace(
"<stdin>",
I->getOffset(),
I->getLength(),
272 I->getReplacementText());
273 if (!Replace.apply(Rewrite))
274 return llvm::make_error<llvm::StringError>(
275 "Failed to apply replacement: " + Replace.toString(),
276 llvm::inconvertibleErrorCode());
279 llvm::raw_string_ostream OS(Result);
287 std::sort(Ranges.begin(), Ranges.end(),
288 [](
const Range &LHS,
const Range &RHS) {
290 return LHS.
getOffset() < RHS.getOffset();
291 return LHS.
getLength() < RHS.getLength();
293 std::vector<Range>
Result;
294 for (
const auto &R : Ranges) {
295 if (Result.empty() ||
296 Result.back().getOffset() + Result.back().getLength() < R.getOffset()) {
300 std::max(Result.back().getOffset() + Result.back().getLength(),
301 R.getOffset() + R.getLength());
302 Result[Result.size() - 1] =
303 Range(Result.back().getOffset(), NewEnd - Result.back().getOffset());
310 std::vector<Range> ChangedRanges;
314 unsigned Length = R.getReplacementText().size();
315 Shift += Length - R.getLength();
316 ChangedRanges.push_back(Range(Offset, Length));
323 const std::vector<Range> &Ranges) {
326 for (
const auto &R : MergedRanges)
327 FakeReplaces.insert(
Replacement(Replaces.begin()->getFilePath(),
328 R.getOffset(), R.getLength(),
329 std::string(R.getLength(),
' ')));
355 class MergedReplacement {
358 : MergeSecond(MergeSecond),
Delta(D),
FilePath(R.getFilePath()),
359 Offset(R.getOffset() + (MergeSecond ? 0 :
Delta)), Length(R.getLength()),
360 Text(R.getReplacementText()) {
370 unsigned REnd = R.getOffset() +
Delta + R.getLength();
373 Length += REnd -
End;
376 StringRef TextRef =
Text;
377 StringRef Head = TextRef.substr(0, R.getOffset() +
Delta -
Offset);
378 StringRef Tail = TextRef.substr(REnd -
Offset);
379 Text = (Head + R.getReplacementText() + Tail).str();
380 Delta += R.getReplacementText().size() - R.getLength();
383 StringRef RText = R.getReplacementText();
384 StringRef Tail = RText.substr(End - R.getOffset());
386 if (R.getOffset() + RText.size() >
End) {
387 Length = R.getOffset() + R.getLength() -
Offset;
390 Length += R.getLength() - RText.size();
401 return Offset + Length < R.getOffset();
430 std::map<std::string, Replacements>
432 std::map<std::string, Replacements> FileToReplaces;
433 for (
const auto &Replace : Replaces) {
434 FileToReplaces[Replace.getFilePath()].insert(Replace);
436 return FileToReplaces;
441 if (First.empty() || Second.empty())
442 return First.empty() ? Second : First;
453 for (
auto FirstI = First.begin(), SecondI = Second.begin();
454 FirstI != First.end() || SecondI != Second.end();) {
455 bool NextIsFirst = SecondI == Second.end() ||
456 (FirstI != First.end() &&
457 FirstI->getOffset() < SecondI->getOffset() +
Delta);
458 MergedReplacement Merged(NextIsFirst ? *FirstI : *SecondI, NextIsFirst,
460 ++(NextIsFirst ? FirstI : SecondI);
462 while ((Merged.mergeSecond() && SecondI != Second.end()) ||
463 (!Merged.mergeSecond() && FirstI != First.end())) {
464 auto &
I = Merged.mergeSecond() ? SecondI : FirstI;
465 if (Merged.endsBefore(*
I))
470 Delta -= Merged.deltaFirst();
471 Result.insert(Merged.asReplacement());
SourceLocation getBegin() const
Implements support for file system lookup, file system caching, and directory search management...
SourceManager & getSourceMgr() const
Defines the clang::FileManager interface and associated types.
SourceLocation getSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID. ...
Defines the SourceManager interface.
RewriteBuffer & getEditBuffer(FileID FID)
getEditBuffer - This is like getRewriteBufferFor, but always returns a buffer, and allows you to writ...
bool ReplaceText(SourceLocation Start, unsigned OrigLength, StringRef NewStr)
ReplaceText - This method replaces a range of characters in the input buffer with a new string...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
An in-memory file system.
Concrete class used by the front-end to report problems and issues.
detail::InMemoryDirectory::const_iterator I
const FileEntry * getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
FileID getOrCreateFileID(const FileEntry *SourceFile, SrcMgr::CharacteristicKind FileCharacter)
Get the FileID for SourceFile if it exists.
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
Represents a character-granular source range.
SourceLocation getEnd() const
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 ...
FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos, SrcMgr::CharacteristicKind FileCharacter, int LoadedID=0, unsigned LoadedOffset=0)
Create a new FileID that represents the specified file being #included from the specified IncludePosi...
FileManager & getFileManager() const
The result type of a method or function.
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token.
const char * getName() const
Encodes a location in the source.
Options for controlling the compiler diagnostics engine.
Cached information about one file (either on disk or in the virtual file system). ...
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Used for handling and querying diagnostic IDs.
detail::InMemoryDirectory::const_iterator E
Defines the Diagnostic-related interfaces.
raw_ostream & write(raw_ostream &Stream) const
Write to Stream the result of applying all changes to the original buffer.
char __ovld __cnfn max(char x, char y)
Returns y if x < y, otherwise it returns x.
Keeps track of options that affect how file operations are performed.
Rewriter - This is the main interface to the rewrite buffers.
Defines the Diagnostic IDs-related interfaces.
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file. ...
std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
This class handles loading and caching of source files into memory.