23 #include "llvm/ADT/SmallPtrSet.h" 24 #include "llvm/Support/FileSystem.h" 25 #include "llvm/Support/Path.h" 26 #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 <<
"\"";
102 void Replacement::setFromSourceLocation(
const SourceManager &Sources,
104 StringRef ReplacementText) {
105 const std::pair<FileID, unsigned> DecomposedLocation =
109 this->ReplacementRange =
Range(DecomposedLocation.second, Length);
110 this->ReplacementText = ReplacementText;
121 std::pair<FileID, unsigned> Start = Sources.
getDecomposedLoc(SpellingBegin);
123 if (Start.first != End.first)
return -1;
126 return End.second - Start.second;
129 void Replacement::setFromSourceRange(
const SourceManager &Sources,
131 StringRef ReplacementText,
139 Replacements::getReplacementInChangedCode(
const Replacement &R)
const {
140 unsigned NewStart = getShiftedCodePosition(R.
getOffset());
149 return "Failed to apply a replacement.";
151 return "The new replacement's file path is different from the file path of " 152 "existing replacements";
154 return "The new replacement overlaps with an existing replacement.";
156 return "The new insertion has the same insert location as an existing " 159 llvm_unreachable(
"A value of replacement_error has no message.");
164 if (NewReplacement.hasValue())
165 Message +=
"\nNew replacement: " + NewReplacement->toString();
166 if (ExistingReplacement.hasValue())
167 Message +=
"\nExisting replacement: " + ExistingReplacement->toString();
173 Replacements Replacements::getCanonicalReplacements()
const {
174 std::vector<Replacement> NewReplaces;
176 for (
const auto &R : Replaces) {
177 if (NewReplaces.empty()) {
178 NewReplaces.push_back(R);
181 auto &Prev = NewReplaces.back();
182 unsigned PrevEnd = Prev.getOffset() + Prev.getLength();
184 NewReplaces.push_back(R);
187 "Existing replacements must not overlap.");
194 ReplacementsImpl NewReplacesImpl(NewReplaces.begin(), NewReplaces.end());
195 return Replacements(NewReplacesImpl.begin(), NewReplacesImpl.end());
202 Replacements::mergeIfOrderIndependent(
const Replacement &R)
const {
206 Replacements RsShiftedByReplaces(getReplacementInChangedCode(R));
210 for (
const auto &Replace : Replaces)
211 ReplacesShiftedByRs.Replaces.insert(
212 Rs.getReplacementInChangedCode(Replace));
214 auto MergeShiftedRs = merge(RsShiftedByReplaces);
216 auto MergeShiftedReplaces = Rs.
merge(ReplacesShiftedByRs);
220 if (MergeShiftedRs.getCanonicalReplacements() ==
221 MergeShiftedReplaces.getCanonicalReplacements())
222 return MergeShiftedRs;
224 R, *Replaces.begin());
229 if (!Replaces.empty() && R.
getFilePath() != Replaces.begin()->getFilePath())
230 return llvm::make_error<ReplacementError>(
236 return llvm::Error::success();
249 auto I = Replaces.lower_bound(AtEnd);
251 if (I != Replaces.end() && R.
getOffset() == I->getOffset()) {
254 if (I->getLength() == 0) {
259 return llvm::make_error<ReplacementError>(
266 Replaces.insert(std::move(NewR));
267 return llvm::Error::success();
277 return llvm::Error::success();
282 if (I == Replaces.begin()) {
284 return llvm::Error::success();
289 .overlapsWith(Range(R2.getOffset(), R2.getLength()));
293 if (!Overlap(R, *I)) {
307 auto MergeEnd = std::next(I);
308 while (I != Replaces.begin()) {
317 OverlapReplaces.mergeIfOrderIndependent(R);
319 return Merged.takeError();
320 Replaces.erase(MergeBegin, MergeEnd);
321 Replaces.insert(Merged->begin(), Merged->end());
323 return llvm::Error::success();
348 class MergedReplacement {
350 MergedReplacement(
const Replacement &R,
bool MergeSecond,
int D)
351 : MergeSecond(MergeSecond), Delta(D), FilePath(R.
getFilePath()),
354 Delta += MergeSecond ? 0 :
Text.size() - Length;
355 DeltaFirst = MergeSecond ?
Text.size() - Length : 0;
366 Length += REnd -
End;
369 StringRef TextRef =
Text;
371 StringRef Tail = TextRef.substr(REnd -
Offset);
377 StringRef Tail = RText.substr(End - R.
getOffset());
385 DeltaFirst += RText.size() - R.
getLength();
398 bool mergeSecond()
const {
return MergeSecond; }
399 int deltaFirst()
const {
return DeltaFirst; }
416 const StringRef FilePath;
425 if (empty() || ReplacesToMerge.
empty())
426 return empty() ? ReplacesToMerge : *
this;
428 auto &First = Replaces;
429 auto &Second = ReplacesToMerge.Replaces;
433 ReplacementsImpl Result;
439 for (
auto FirstI = First.begin(), SecondI = Second.begin();
440 FirstI != First.end() || SecondI != Second.end();) {
441 bool NextIsFirst = SecondI == Second.end() ||
442 (FirstI != First.end() &&
443 FirstI->getOffset() < SecondI->getOffset() + Delta);
444 MergedReplacement Merged(NextIsFirst ? *FirstI : *SecondI, NextIsFirst,
446 ++(NextIsFirst ? FirstI : SecondI);
448 while ((Merged.mergeSecond() && SecondI != Second.end()) ||
449 (!Merged.mergeSecond() && FirstI != First.end())) {
450 auto &I = Merged.mergeSecond() ? SecondI : FirstI;
451 if (Merged.endsBefore(*I))
456 Delta -= Merged.deltaFirst();
457 Result.insert(Merged.asReplacement());
466 std::sort(Ranges.begin(), Ranges.end(),
467 [](
const Range &LHS,
const Range &RHS) {
469 return LHS.
getOffset() < RHS.getOffset();
470 return LHS.
getLength() < RHS.getLength();
472 std::vector<Range> Result;
473 for (
const auto &R : Ranges) {
474 if (Result.empty() ||
475 Result.back().getOffset() + Result.back().getLength() < R.
getOffset()) {
479 std::max(Result.back().getOffset() + Result.back().getLength(),
481 Result[Result.size() - 1] =
482 Range(Result.back().getOffset(), NewEnd - Result.back().getOffset());
490 const std::vector<Range> &Ranges) {
497 if (Replaces.
empty())
500 for (
const auto &R : MergedRanges) {
505 "Replacements must not conflict since ranges have been merged.");
506 llvm::consumeError(std::move(Err));
512 std::vector<Range> ChangedRanges;
518 ChangedRanges.push_back(Range(Offset, Length));
525 for (
const auto& R : Replaces) {
538 return Position + Offset;
543 for (
auto I = Replaces.
rbegin(), E = Replaces.
rend(); I != E; ++I) {
544 if (I->isApplicable()) {
545 Result = I->apply(Rewrite) && Result;
555 if (Replaces.
empty())
566 InMemoryFileSystem->addFile(
567 "<stdin>", 0, llvm::MemoryBuffer::getMemBuffer(Code,
"<stdin>"));
570 for (
auto I = Replaces.
rbegin(), E = Replaces.
rend(); I != E; ++I) {
571 Replacement Replace(
"<stdin>", I->getOffset(), I->getLength(),
572 I->getReplacementText());
573 if (!Replace.apply(Rewrite))
574 return llvm::make_error<ReplacementError>(
578 llvm::raw_string_ostream OS(Result);
586 const std::map<std::string, Replacements> &FileToReplaces) {
587 std::map<std::string, Replacements> Result;
588 llvm::SmallPtrSet<const FileEntry *, 16> ProcessedFileEntries;
589 for (
const auto &Entry : FileToReplaces) {
592 llvm::errs() <<
"File path " << Entry.first <<
" is invalid.\n";
593 else if (ProcessedFileEntries.insert(FE).second)
594 Result[Entry.first] = std::move(Entry.second);
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file. ...
Implements support for file system lookup, file system caching, and directory search management...
Defines the clang::FileManager interface and associated types.
Defines the SourceManager interface.
RewriteBuffer & getEditBuffer(FileID FID)
getEditBuffer - This is like getRewriteBufferFor, but always returns a buffer, and allows you to writ...
FileManager & getFileManager() const
SourceLocation getBegin() const
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.
SourceManager & getSourceMgr() const
Concrete class used by the front-end to report problems and issues.
Defines the Diagnostic-related interfaces.
SourceLocation getSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID. ...
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.
Represents a character-granular source range.
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 ...
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
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...
Encodes a location in the source.
raw_ostream & write(raw_ostream &Stream) const
Write to Stream the result of applying all changes to the original buffer.
StringRef getName() const
Options for controlling the compiler diagnostics engine.
Cached information about one file (either on disk or in the virtual file system). ...
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Dataflow Directional Tag Classes.
Used for handling and querying diagnostic IDs.
SourceLocation getEnd() const
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.
This class handles loading and caching of source files into memory.
std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.