24 #include "llvm/ADT/IntrusiveRefCntPtr.h"
25 #include "llvm/ADT/SmallPtrSet.h"
26 #include "llvm/ADT/StringRef.h"
27 #include "llvm/Support/Error.h"
28 #include "llvm/Support/ErrorHandling.h"
29 #include "llvm/Support/MemoryBuffer.h"
30 #include "llvm/Support/VirtualFileSystem.h"
31 #include "llvm/Support/raw_ostream.h"
40 using namespace clang;
41 using namespace tooling;
48 StringRef ReplacementText)
50 ReplacementText(
std::
string(ReplacementText)) {}
53 unsigned Length, StringRef ReplacementText) {
54 setFromSourceLocation(Sources, Start, Length, ReplacementText);
59 StringRef ReplacementText,
61 setFromSourceRange(Sources,
Range, ReplacementText, LangOpts);
70 auto Entry =
SM.getFileManager().getFile(FilePath);
76 SM.getLocForStartOfFile(
ID).
77 getLocWithOffset(ReplacementRange.
getOffset());
81 bool RewriteSucceeded = !
Rewrite.ReplaceText(
82 Start, ReplacementRange.
getLength(), ReplacementText);
83 assert(RewriteSucceeded);
84 return RewriteSucceeded;
89 llvm::raw_string_ostream Stream(Result);
90 Stream << FilePath <<
": " << ReplacementRange.
getOffset() <<
":+"
91 << ReplacementRange.
getLength() <<
":\"" << ReplacementText <<
"\"";
120 void Replacement::setFromSourceLocation(
const SourceManager &Sources,
122 StringRef ReplacementText) {
123 const std::pair<FileID, unsigned> DecomposedLocation =
127 this->ReplacementRange =
Range(DecomposedLocation.second, Length);
128 this->ReplacementText =
std::string(ReplacementText);
139 std::pair<FileID, unsigned> Start = Sources.
getDecomposedLoc(SpellingBegin);
141 if (Start.first !=
End.first)
return -1;
142 if (Range.isTokenRange())
144 return End.second - Start.second;
147 void Replacement::setFromSourceRange(
const SourceManager &Sources,
149 StringRef ReplacementText,
157 Replacements::getReplacementInChangedCode(
const Replacement &R)
const {
160 return Replacement(R.getFilePath(), NewStart, NewEnd - NewStart,
161 R.getReplacementText());
167 return "Failed to apply a replacement.";
169 return "The new replacement's file path is different from the file path of "
170 "existing replacements";
172 return "The new replacement overlaps with an existing replacement.";
174 return "The new insertion has the same insert location as an existing "
177 llvm_unreachable(
"A value of replacement_error has no message.");
182 if (NewReplacement.hasValue())
183 Message +=
"\nNew replacement: " + NewReplacement->toString();
184 if (ExistingReplacement.hasValue())
185 Message +=
"\nExisting replacement: " + ExistingReplacement->toString();
191 Replacements Replacements::getCanonicalReplacements()
const {
192 std::vector<Replacement> NewReplaces;
194 for (
const auto &R : Replaces) {
195 if (NewReplaces.empty()) {
196 NewReplaces.push_back(R);
199 auto &Prev = NewReplaces.back();
200 unsigned PrevEnd = Prev.getOffset() + Prev.getLength();
201 if (PrevEnd < R.getOffset()) {
202 NewReplaces.push_back(R);
204 assert(PrevEnd == R.getOffset() &&
205 "Existing replacements must not overlap.");
207 R.getFilePath(), Prev.getOffset(), Prev.getLength() + R.getLength(),
208 (Prev.getReplacementText() + R.getReplacementText()).str());
212 ReplacementsImpl NewReplacesImpl(NewReplaces.begin(), NewReplaces.end());
213 return Replacements(NewReplacesImpl.begin(), NewReplacesImpl.end());
220 Replacements::mergeIfOrderIndependent(
const Replacement &R)
const {
224 Replacements RsShiftedByReplaces(getReplacementInChangedCode(R));
228 for (
const auto &Replace : Replaces)
229 ReplacesShiftedByRs.Replaces.insert(
230 Rs.getReplacementInChangedCode(Replace));
232 auto MergeShiftedRs =
merge(RsShiftedByReplaces);
234 auto MergeShiftedReplaces = Rs.merge(ReplacesShiftedByRs);
238 if (MergeShiftedRs.getCanonicalReplacements() ==
239 MergeShiftedReplaces.getCanonicalReplacements())
240 return MergeShiftedRs;
242 R, *Replaces.begin());
247 if (!Replaces.empty() && R.
getFilePath() != Replaces.begin()->getFilePath())
248 return llvm::make_error<ReplacementError>(
254 return llvm::Error::success();
267 auto I = Replaces.lower_bound(AtEnd);
269 if (I != Replaces.end() && R.
getOffset() == I->getOffset()) {
272 if (I->getLength() == 0) {
277 return llvm::make_error<ReplacementError>(
284 Replaces.insert(std::move(NewR));
285 return llvm::Error::success();
295 return llvm::Error::success();
300 if (I == Replaces.begin()) {
302 return llvm::Error::success();
311 if (!Overlap(R, *I)) {
325 auto MergeEnd = std::next(I);
326 while (I != Replaces.begin()) {
335 OverlapReplaces.mergeIfOrderIndependent(R);
337 return Merged.takeError();
338 Replaces.erase(MergeBegin, MergeEnd);
339 Replaces.insert(Merged->begin(), Merged->end());
341 return llvm::Error::success();
366 class MergedReplacement {
368 MergedReplacement(
const Replacement &R,
bool MergeSecond,
int D)
369 : MergeSecond(MergeSecond), Delta(D), FilePath(R.getFilePath()),
370 Offset(R.getOffset() + (MergeSecond ? 0 : Delta)),
371 Length(R.getLength()),
Text(
std::
string(R.getReplacementText())) {
372 Delta += MergeSecond ? 0 :
Text.size() - Length;
373 DeltaFirst = MergeSecond ?
Text.size() - Length : 0;
379 void merge(
const Replacement &R) {
381 unsigned REnd = R.getOffset() + Delta + R.getLength();
384 Length += REnd -
End;
387 StringRef TextRef =
Text;
388 StringRef Head = TextRef.substr(0, R.getOffset() + Delta -
Offset);
389 StringRef Tail = TextRef.substr(REnd -
Offset);
390 Text = (Head + R.getReplacementText() + Tail).str();
391 Delta += R.getReplacementText().size() - R.getLength();
394 StringRef RText = R.getReplacementText();
395 StringRef Tail = RText.substr(
End - R.getOffset());
397 if (R.getOffset() + RText.size() >
End) {
398 Length = R.getOffset() + R.getLength() -
Offset;
401 Length += R.getLength() - RText.size();
403 DeltaFirst += RText.size() - R.getLength();
409 bool endsBefore(
const Replacement &R)
const {
411 return Offset +
Text.size() < R.getOffset() + Delta;
412 return Offset + Length < R.getOffset();
416 bool mergeSecond()
const {
return MergeSecond; }
418 int deltaFirst()
const {
return DeltaFirst; }
419 Replacement asReplacement()
const {
return {FilePath,
Offset, Length,
Text}; }
435 const StringRef FilePath;
445 return empty() ? ReplacesToMerge : *
this;
447 auto &
First = Replaces;
448 auto &Second = ReplacesToMerge.Replaces;
452 ReplacementsImpl Result;
458 for (
auto FirstI =
First.begin(), SecondI = Second.begin();
459 FirstI !=
First.end() || SecondI != Second.end();) {
460 bool NextIsFirst = SecondI == Second.end() ||
461 (FirstI !=
First.end() &&
462 FirstI->getOffset() < SecondI->getOffset() + Delta);
463 MergedReplacement Merged(NextIsFirst ? *FirstI : *SecondI, NextIsFirst,
465 ++(NextIsFirst ? FirstI : SecondI);
467 while ((Merged.mergeSecond() && SecondI != Second.end()) ||
468 (!Merged.mergeSecond() && FirstI !=
First.end())) {
469 auto &I = Merged.mergeSecond() ? SecondI : FirstI;
470 if (Merged.endsBefore(*I))
475 Delta -= Merged.deltaFirst();
476 Result.insert(Merged.asReplacement());
485 llvm::sort(Ranges, [](
const Range &LHS,
const Range &RHS) {
486 if (LHS.getOffset() != RHS.getOffset())
487 return LHS.getOffset() < RHS.getOffset();
488 return LHS.getLength() < RHS.getLength();
490 std::vector<Range> Result;
491 for (
const auto &R : Ranges) {
492 if (Result.empty() ||
493 Result.back().getOffset() + Result.back().getLength() < R.getOffset()) {
497 std::max(Result.back().getOffset() + Result.back().getLength(),
498 R.getOffset() + R.getLength());
499 Result[Result.size() - 1] =
500 Range(Result.back().getOffset(), NewEnd - Result.back().getOffset());
511 const std::vector<Range> &Ranges) {
518 if (Replaces.
empty())
521 for (
const auto &R : MergedRanges) {
524 R.getOffset(), R.getLength(),
526 "Replacements must not conflict since ranges have been merged.");
535 std::vector<Range> ChangedRanges;
537 for (
const auto &R : Replaces) {
539 unsigned Length = R.getReplacementText().size();
540 Shift += Length - R.getLength();
548 for (
const auto &R : Replaces) {
549 if (R.getOffset() + R.getLength() <= Position) {
550 Offset += R.getReplacementText().size() - R.getLength();
553 if (R.getOffset() < Position &&
554 R.getOffset() + R.getReplacementText().size() <= Position) {
555 Position = R.getOffset() + R.getReplacementText().size();
556 if (!R.getReplacementText().empty())
569 for (
auto I = Replaces.
rbegin(), E = Replaces.
rend(); I != E; ++I) {
570 if (I->isApplicable()) {
571 Result = I->apply(
Rewrite) && Result;
581 if (Replaces.
empty())
585 new llvm::vfs::InMemoryFileSystem);
592 InMemoryFileSystem->addFile(
593 "<stdin>", 0, llvm::MemoryBuffer::getMemBuffer(Code,
"<stdin>"));
597 for (
auto I = Replaces.
rbegin(), E = Replaces.
rend(); I != E; ++I) {
598 Replacement Replace(
"<stdin>", I->getOffset(), I->getLength(),
599 I->getReplacementText());
601 return llvm::make_error<ReplacementError>(
605 llvm::raw_string_ostream OS(Result);
613 const std::map<std::string, Replacements> &FileToReplaces) {
614 std::map<std::string, Replacements> Result;
616 for (
const auto &Entry : FileToReplaces) {
617 auto FE = FileMgr.
getFile(Entry.first);
619 llvm::errs() <<
"File path " << Entry.first <<
" is invalid.\n";
620 else if (ProcessedFileEntries.insert(*FE).second)
621 Result[Entry.first] = std::move(Entry.second);