Replacement.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. //===- Replacement.cpp - Framework for clang refactoring tools ------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // Implements classes to support/store refactorings.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "clang/Tooling/Core/Replacement.h"
  13. #include "clang/Basic/Diagnostic.h"
  14. #include "clang/Basic/DiagnosticIDs.h"
  15. #include "clang/Basic/DiagnosticOptions.h"
  16. #include "clang/Basic/FileManager.h"
  17. #include "clang/Basic/FileSystemOptions.h"
  18. #include "clang/Basic/SourceLocation.h"
  19. #include "clang/Basic/SourceManager.h"
  20. #include "clang/Lex/Lexer.h"
  21. #include "clang/Rewrite/Core/RewriteBuffer.h"
  22. #include "clang/Rewrite/Core/Rewriter.h"
  23. #include "llvm/ADT/IntrusiveRefCntPtr.h"
  24. #include "llvm/ADT/SmallPtrSet.h"
  25. #include "llvm/ADT/StringRef.h"
  26. #include "llvm/Support/Error.h"
  27. #include "llvm/Support/ErrorHandling.h"
  28. #include "llvm/Support/MemoryBuffer.h"
  29. #include "llvm/Support/VirtualFileSystem.h"
  30. #include "llvm/Support/raw_ostream.h"
  31. #include <algorithm>
  32. #include <cassert>
  33. #include <limits>
  34. #include <map>
  35. #include <string>
  36. #include <utility>
  37. #include <vector>
  38. using namespace clang;
  39. using namespace tooling;
  40. static const char * const InvalidLocation = "";
  41. Replacement::Replacement() : FilePath(InvalidLocation) {}
  42. Replacement::Replacement(StringRef FilePath, unsigned Offset, unsigned Length,
  43. StringRef ReplacementText)
  44. : FilePath(std::string(FilePath)), ReplacementRange(Offset, Length),
  45. ReplacementText(std::string(ReplacementText)) {}
  46. Replacement::Replacement(const SourceManager &Sources, SourceLocation Start,
  47. unsigned Length, StringRef ReplacementText) {
  48. setFromSourceLocation(Sources, Start, Length, ReplacementText);
  49. }
  50. Replacement::Replacement(const SourceManager &Sources,
  51. const CharSourceRange &Range,
  52. StringRef ReplacementText,
  53. const LangOptions &LangOpts) {
  54. setFromSourceRange(Sources, Range, ReplacementText, LangOpts);
  55. }
  56. bool Replacement::isApplicable() const {
  57. return FilePath != InvalidLocation;
  58. }
  59. bool Replacement::apply(Rewriter &Rewrite) const {
  60. SourceManager &SM = Rewrite.getSourceMgr();
  61. auto Entry = SM.getFileManager().getFile(FilePath);
  62. if (!Entry)
  63. return false;
  64. FileID ID = SM.getOrCreateFileID(*Entry, SrcMgr::C_User);
  65. const SourceLocation Start =
  66. SM.getLocForStartOfFile(ID).
  67. getLocWithOffset(ReplacementRange.getOffset());
  68. // ReplaceText returns false on success.
  69. // ReplaceText only fails if the source location is not a file location, in
  70. // which case we already returned false earlier.
  71. bool RewriteSucceeded = !Rewrite.ReplaceText(
  72. Start, ReplacementRange.getLength(), ReplacementText);
  73. assert(RewriteSucceeded);
  74. return RewriteSucceeded;
  75. }
  76. std::string Replacement::toString() const {
  77. std::string Result;
  78. llvm::raw_string_ostream Stream(Result);
  79. Stream << FilePath << ": " << ReplacementRange.getOffset() << ":+"
  80. << ReplacementRange.getLength() << ":\"" << ReplacementText << "\"";
  81. return Stream.str();
  82. }
  83. namespace clang {
  84. namespace tooling {
  85. bool operator<(const Replacement &LHS, const Replacement &RHS) {
  86. if (LHS.getOffset() != RHS.getOffset())
  87. return LHS.getOffset() < RHS.getOffset();
  88. if (LHS.getLength() != RHS.getLength())
  89. return LHS.getLength() < RHS.getLength();
  90. if (LHS.getFilePath() != RHS.getFilePath())
  91. return LHS.getFilePath() < RHS.getFilePath();
  92. return LHS.getReplacementText() < RHS.getReplacementText();
  93. }
  94. bool operator==(const Replacement &LHS, const Replacement &RHS) {
  95. return LHS.getOffset() == RHS.getOffset() &&
  96. LHS.getLength() == RHS.getLength() &&
  97. LHS.getFilePath() == RHS.getFilePath() &&
  98. LHS.getReplacementText() == RHS.getReplacementText();
  99. }
  100. } // namespace tooling
  101. } // namespace clang
  102. void Replacement::setFromSourceLocation(const SourceManager &Sources,
  103. SourceLocation Start, unsigned Length,
  104. StringRef ReplacementText) {
  105. const std::pair<FileID, unsigned> DecomposedLocation =
  106. Sources.getDecomposedLoc(Start);
  107. const FileEntry *Entry = Sources.getFileEntryForID(DecomposedLocation.first);
  108. this->FilePath = std::string(Entry ? Entry->getName() : InvalidLocation);
  109. this->ReplacementRange = Range(DecomposedLocation.second, Length);
  110. this->ReplacementText = std::string(ReplacementText);
  111. }
  112. // FIXME: This should go into the Lexer, but we need to figure out how
  113. // to handle ranges for refactoring in general first - there is no obvious
  114. // good way how to integrate this into the Lexer yet.
  115. static int getRangeSize(const SourceManager &Sources,
  116. const CharSourceRange &Range,
  117. const LangOptions &LangOpts) {
  118. SourceLocation SpellingBegin = Sources.getSpellingLoc(Range.getBegin());
  119. SourceLocation SpellingEnd = Sources.getSpellingLoc(Range.getEnd());
  120. std::pair<FileID, unsigned> Start = Sources.getDecomposedLoc(SpellingBegin);
  121. std::pair<FileID, unsigned> End = Sources.getDecomposedLoc(SpellingEnd);
  122. if (Start.first != End.first) return -1;
  123. if (Range.isTokenRange())
  124. End.second += Lexer::MeasureTokenLength(SpellingEnd, Sources, LangOpts);
  125. return End.second - Start.second;
  126. }
  127. void Replacement::setFromSourceRange(const SourceManager &Sources,
  128. const CharSourceRange &Range,
  129. StringRef ReplacementText,
  130. const LangOptions &LangOpts) {
  131. setFromSourceLocation(Sources, Sources.getSpellingLoc(Range.getBegin()),
  132. getRangeSize(Sources, Range, LangOpts),
  133. ReplacementText);
  134. }
  135. Replacement
  136. Replacements::getReplacementInChangedCode(const Replacement &R) const {
  137. unsigned NewStart = getShiftedCodePosition(R.getOffset());
  138. unsigned NewEnd = getShiftedCodePosition(R.getOffset() + R.getLength());
  139. return Replacement(R.getFilePath(), NewStart, NewEnd - NewStart,
  140. R.getReplacementText());
  141. }
  142. static std::string getReplacementErrString(replacement_error Err) {
  143. switch (Err) {
  144. case replacement_error::fail_to_apply:
  145. return "Failed to apply a replacement.";
  146. case replacement_error::wrong_file_path:
  147. return "The new replacement's file path is different from the file path of "
  148. "existing replacements";
  149. case replacement_error::overlap_conflict:
  150. return "The new replacement overlaps with an existing replacement.";
  151. case replacement_error::insert_conflict:
  152. return "The new insertion has the same insert location as an existing "
  153. "replacement.";
  154. }
  155. llvm_unreachable("A value of replacement_error has no message.");
  156. }
  157. std::string ReplacementError::message() const {
  158. std::string Message = getReplacementErrString(Err);
  159. if (NewReplacement.hasValue())
  160. Message += "\nNew replacement: " + NewReplacement->toString();
  161. if (ExistingReplacement.hasValue())
  162. Message += "\nExisting replacement: " + ExistingReplacement->toString();
  163. return Message;
  164. }
  165. char ReplacementError::ID = 0;
  166. Replacements Replacements::getCanonicalReplacements() const {
  167. std::vector<Replacement> NewReplaces;
  168. // Merge adjacent replacements.
  169. for (const auto &R : Replaces) {
  170. if (NewReplaces.empty()) {
  171. NewReplaces.push_back(R);
  172. continue;
  173. }
  174. auto &Prev = NewReplaces.back();
  175. unsigned PrevEnd = Prev.getOffset() + Prev.getLength();
  176. if (PrevEnd < R.getOffset()) {
  177. NewReplaces.push_back(R);
  178. } else {
  179. assert(PrevEnd == R.getOffset() &&
  180. "Existing replacements must not overlap.");
  181. Replacement NewR(
  182. R.getFilePath(), Prev.getOffset(), Prev.getLength() + R.getLength(),
  183. (Prev.getReplacementText() + R.getReplacementText()).str());
  184. Prev = NewR;
  185. }
  186. }
  187. ReplacementsImpl NewReplacesImpl(NewReplaces.begin(), NewReplaces.end());
  188. return Replacements(NewReplacesImpl.begin(), NewReplacesImpl.end());
  189. }
  190. // `R` and `Replaces` are order-independent if applying them in either order
  191. // has the same effect, so we need to compare replacements associated to
  192. // applying them in either order.
  193. llvm::Expected<Replacements>
  194. Replacements::mergeIfOrderIndependent(const Replacement &R) const {
  195. Replacements Rs(R);
  196. // A Replacements set containing a single replacement that is `R` referring to
  197. // the code after the existing replacements `Replaces` are applied.
  198. Replacements RsShiftedByReplaces(getReplacementInChangedCode(R));
  199. // A Replacements set that is `Replaces` referring to the code after `R` is
  200. // applied.
  201. Replacements ReplacesShiftedByRs;
  202. for (const auto &Replace : Replaces)
  203. ReplacesShiftedByRs.Replaces.insert(
  204. Rs.getReplacementInChangedCode(Replace));
  205. // This is equivalent to applying `Replaces` first and then `R`.
  206. auto MergeShiftedRs = merge(RsShiftedByReplaces);
  207. // This is equivalent to applying `R` first and then `Replaces`.
  208. auto MergeShiftedReplaces = Rs.merge(ReplacesShiftedByRs);
  209. // Since empty or segmented replacements around existing replacements might be
  210. // produced above, we need to compare replacements in canonical forms.
  211. if (MergeShiftedRs.getCanonicalReplacements() ==
  212. MergeShiftedReplaces.getCanonicalReplacements())
  213. return MergeShiftedRs;
  214. return llvm::make_error<ReplacementError>(replacement_error::overlap_conflict,
  215. R, *Replaces.begin());
  216. }
  217. llvm::Error Replacements::add(const Replacement &R) {
  218. // Check the file path.
  219. if (!Replaces.empty() && R.getFilePath() != Replaces.begin()->getFilePath())
  220. return llvm::make_error<ReplacementError>(
  221. replacement_error::wrong_file_path, R, *Replaces.begin());
  222. // Special-case header insertions.
  223. if (R.getOffset() == std::numeric_limits<unsigned>::max()) {
  224. Replaces.insert(R);
  225. return llvm::Error::success();
  226. }
  227. // This replacement cannot conflict with replacements that end before
  228. // this replacement starts or start after this replacement ends.
  229. // We also know that there currently are no overlapping replacements.
  230. // Thus, we know that all replacements that start after the end of the current
  231. // replacement cannot overlap.
  232. Replacement AtEnd(R.getFilePath(), R.getOffset() + R.getLength(), 0, "");
  233. // Find the first entry that starts after or at the end of R. Note that
  234. // entries that start at the end can still be conflicting if R is an
  235. // insertion.
  236. auto I = Replaces.lower_bound(AtEnd);
  237. // If `I` starts at the same offset as `R`, `R` must be an insertion.
  238. if (I != Replaces.end() && R.getOffset() == I->getOffset()) {
  239. assert(R.getLength() == 0);
  240. // `I` is also an insertion, `R` and `I` conflict.
  241. if (I->getLength() == 0) {
  242. // Check if two insertions are order-indepedent: if inserting them in
  243. // either order produces the same text, they are order-independent.
  244. if ((R.getReplacementText() + I->getReplacementText()).str() !=
  245. (I->getReplacementText() + R.getReplacementText()).str())
  246. return llvm::make_error<ReplacementError>(
  247. replacement_error::insert_conflict, R, *I);
  248. // If insertions are order-independent, we can merge them.
  249. Replacement NewR(
  250. R.getFilePath(), R.getOffset(), 0,
  251. (R.getReplacementText() + I->getReplacementText()).str());
  252. Replaces.erase(I);
  253. Replaces.insert(std::move(NewR));
  254. return llvm::Error::success();
  255. }
  256. // Insertion `R` is adjacent to a non-insertion replacement `I`, so they
  257. // are order-independent. It is safe to assume that `R` will not conflict
  258. // with any replacement before `I` since all replacements before `I` must
  259. // either end before `R` or end at `R` but has length > 0 (if the
  260. // replacement before `I` is an insertion at `R`, it would have been `I`
  261. // since it is a lower bound of `AtEnd` and ordered before the current `I`
  262. // in the set).
  263. Replaces.insert(R);
  264. return llvm::Error::success();
  265. }
  266. // `I` is the smallest iterator (after `R`) whose entry cannot overlap.
  267. // If that is begin(), there are no overlaps.
  268. if (I == Replaces.begin()) {
  269. Replaces.insert(R);
  270. return llvm::Error::success();
  271. }
  272. --I;
  273. auto Overlap = [](const Replacement &R1, const Replacement &R2) -> bool {
  274. return Range(R1.getOffset(), R1.getLength())
  275. .overlapsWith(Range(R2.getOffset(), R2.getLength()));
  276. };
  277. // If the previous entry does not overlap, we know that entries before it
  278. // can also not overlap.
  279. if (!Overlap(R, *I)) {
  280. // If `R` and `I` do not have the same offset, it is safe to add `R` since
  281. // it must come after `I`. Otherwise:
  282. // - If `R` is an insertion, `I` must not be an insertion since it would
  283. // have come after `AtEnd`.
  284. // - If `R` is not an insertion, `I` must be an insertion; otherwise, `R`
  285. // and `I` would have overlapped.
  286. // In either case, we can safely insert `R`.
  287. Replaces.insert(R);
  288. } else {
  289. // `I` overlaps with `R`. We need to check `R` against all overlapping
  290. // replacements to see if they are order-indepedent. If they are, merge `R`
  291. // with them and replace them with the merged replacements.
  292. auto MergeBegin = I;
  293. auto MergeEnd = std::next(I);
  294. while (I != Replaces.begin()) {
  295. --I;
  296. // If `I` doesn't overlap with `R`, don't merge it.
  297. if (!Overlap(R, *I))
  298. break;
  299. MergeBegin = I;
  300. }
  301. Replacements OverlapReplaces(MergeBegin, MergeEnd);
  302. llvm::Expected<Replacements> Merged =
  303. OverlapReplaces.mergeIfOrderIndependent(R);
  304. if (!Merged)
  305. return Merged.takeError();
  306. Replaces.erase(MergeBegin, MergeEnd);
  307. Replaces.insert(Merged->begin(), Merged->end());
  308. }
  309. return llvm::Error::success();
  310. }
  311. namespace {
  312. // Represents a merged replacement, i.e. a replacement consisting of multiple
  313. // overlapping replacements from 'First' and 'Second' in mergeReplacements.
  314. //
  315. // Position projection:
  316. // Offsets and lengths of the replacements can generally refer to two different
  317. // coordinate spaces. Replacements from 'First' refer to the original text
  318. // whereas replacements from 'Second' refer to the text after applying 'First'.
  319. //
  320. // MergedReplacement always operates in the coordinate space of the original
  321. // text, i.e. transforms elements from 'Second' to take into account what was
  322. // changed based on the elements from 'First'.
  323. //
  324. // We can correctly calculate this projection as we look at the replacements in
  325. // order of strictly increasing offsets.
  326. //
  327. // Invariants:
  328. // * We always merge elements from 'First' into elements from 'Second' and vice
  329. // versa. Within each set, the replacements are non-overlapping.
  330. // * We only extend to the right, i.e. merge elements with strictly increasing
  331. // offsets.
  332. class MergedReplacement {
  333. public:
  334. MergedReplacement(const Replacement &R, bool MergeSecond, int D)
  335. : MergeSecond(MergeSecond), Delta(D), FilePath(R.getFilePath()),
  336. Offset(R.getOffset() + (MergeSecond ? 0 : Delta)),
  337. Length(R.getLength()), Text(std::string(R.getReplacementText())) {
  338. Delta += MergeSecond ? 0 : Text.size() - Length;
  339. DeltaFirst = MergeSecond ? Text.size() - Length : 0;
  340. }
  341. // Merges the next element 'R' into this merged element. As we always merge
  342. // from 'First' into 'Second' or vice versa, the MergedReplacement knows what
  343. // set the next element is coming from.
  344. void merge(const Replacement &R) {
  345. if (MergeSecond) {
  346. unsigned REnd = R.getOffset() + Delta + R.getLength();
  347. unsigned End = Offset + Text.size();
  348. if (REnd > End) {
  349. Length += REnd - End;
  350. MergeSecond = false;
  351. }
  352. StringRef TextRef = Text;
  353. StringRef Head = TextRef.substr(0, R.getOffset() + Delta - Offset);
  354. StringRef Tail = TextRef.substr(REnd - Offset);
  355. Text = (Head + R.getReplacementText() + Tail).str();
  356. Delta += R.getReplacementText().size() - R.getLength();
  357. } else {
  358. unsigned End = Offset + Length;
  359. StringRef RText = R.getReplacementText();
  360. StringRef Tail = RText.substr(End - R.getOffset());
  361. Text = (Text + Tail).str();
  362. if (R.getOffset() + RText.size() > End) {
  363. Length = R.getOffset() + R.getLength() - Offset;
  364. MergeSecond = true;
  365. } else {
  366. Length += R.getLength() - RText.size();
  367. }
  368. DeltaFirst += RText.size() - R.getLength();
  369. }
  370. }
  371. // Returns 'true' if 'R' starts strictly after the MergedReplacement and thus
  372. // doesn't need to be merged.
  373. bool endsBefore(const Replacement &R) const {
  374. if (MergeSecond)
  375. return Offset + Text.size() < R.getOffset() + Delta;
  376. return Offset + Length < R.getOffset();
  377. }
  378. // Returns 'true' if an element from the second set should be merged next.
  379. bool mergeSecond() const { return MergeSecond; }
  380. int deltaFirst() const { return DeltaFirst; }
  381. Replacement asReplacement() const { return {FilePath, Offset, Length, Text}; }
  382. private:
  383. bool MergeSecond;
  384. // Amount of characters that elements from 'Second' need to be shifted by in
  385. // order to refer to the original text.
  386. int Delta;
  387. // Sum of all deltas (text-length - length) of elements from 'First' merged
  388. // into this element. This is used to update 'Delta' once the
  389. // MergedReplacement is completed.
  390. int DeltaFirst;
  391. // Data of the actually merged replacement. FilePath and Offset aren't changed
  392. // as the element is only extended to the right.
  393. const StringRef FilePath;
  394. const unsigned Offset;
  395. unsigned Length;
  396. std::string Text;
  397. };
  398. } // namespace
  399. Replacements Replacements::merge(const Replacements &ReplacesToMerge) const {
  400. if (empty() || ReplacesToMerge.empty())
  401. return empty() ? ReplacesToMerge : *this;
  402. auto &First = Replaces;
  403. auto &Second = ReplacesToMerge.Replaces;
  404. // Delta is the amount of characters that replacements from 'Second' need to
  405. // be shifted so that their offsets refer to the original text.
  406. int Delta = 0;
  407. ReplacementsImpl Result;
  408. // Iterate over both sets and always add the next element (smallest total
  409. // Offset) from either 'First' or 'Second'. Merge that element with
  410. // subsequent replacements as long as they overlap. See more details in the
  411. // comment on MergedReplacement.
  412. for (auto FirstI = First.begin(), SecondI = Second.begin();
  413. FirstI != First.end() || SecondI != Second.end();) {
  414. bool NextIsFirst = SecondI == Second.end() ||
  415. (FirstI != First.end() &&
  416. FirstI->getOffset() < SecondI->getOffset() + Delta);
  417. MergedReplacement Merged(NextIsFirst ? *FirstI : *SecondI, NextIsFirst,
  418. Delta);
  419. ++(NextIsFirst ? FirstI : SecondI);
  420. while ((Merged.mergeSecond() && SecondI != Second.end()) ||
  421. (!Merged.mergeSecond() && FirstI != First.end())) {
  422. auto &I = Merged.mergeSecond() ? SecondI : FirstI;
  423. if (Merged.endsBefore(*I))
  424. break;
  425. Merged.merge(*I);
  426. ++I;
  427. }
  428. Delta -= Merged.deltaFirst();
  429. Result.insert(Merged.asReplacement());
  430. }
  431. return Replacements(Result.begin(), Result.end());
  432. }
  433. // Combines overlapping ranges in \p Ranges and sorts the combined ranges.
  434. // Returns a set of non-overlapping and sorted ranges that is equivalent to
  435. // \p Ranges.
  436. static std::vector<Range> combineAndSortRanges(std::vector<Range> Ranges) {
  437. llvm::sort(Ranges, [](const Range &LHS, const Range &RHS) {
  438. if (LHS.getOffset() != RHS.getOffset())
  439. return LHS.getOffset() < RHS.getOffset();
  440. return LHS.getLength() < RHS.getLength();
  441. });
  442. std::vector<Range> Result;
  443. for (const auto &R : Ranges) {
  444. if (Result.empty() ||
  445. Result.back().getOffset() + Result.back().getLength() < R.getOffset()) {
  446. Result.push_back(R);
  447. } else {
  448. unsigned NewEnd =
  449. std::max(Result.back().getOffset() + Result.back().getLength(),
  450. R.getOffset() + R.getLength());
  451. Result[Result.size() - 1] =
  452. Range(Result.back().getOffset(), NewEnd - Result.back().getOffset());
  453. }
  454. }
  455. return Result;
  456. }
  457. namespace clang {
  458. namespace tooling {
  459. std::vector<Range>
  460. calculateRangesAfterReplacements(const Replacements &Replaces,
  461. const std::vector<Range> &Ranges) {
  462. // To calculate the new ranges,
  463. // - Turn \p Ranges into Replacements at (offset, length) with an empty
  464. // (unimportant) replacement text of length "length".
  465. // - Merge with \p Replaces.
  466. // - The new ranges will be the affected ranges of the merged replacements.
  467. auto MergedRanges = combineAndSortRanges(Ranges);
  468. if (Replaces.empty())
  469. return MergedRanges;
  470. tooling::Replacements FakeReplaces;
  471. for (const auto &R : MergedRanges) {
  472. llvm::cantFail(
  473. FakeReplaces.add(Replacement(Replaces.begin()->getFilePath(),
  474. R.getOffset(), R.getLength(),
  475. std::string(R.getLength(), ' '))),
  476. "Replacements must not conflict since ranges have been merged.");
  477. }
  478. return FakeReplaces.merge(Replaces).getAffectedRanges();
  479. }
  480. } // namespace tooling
  481. } // namespace clang
  482. std::vector<Range> Replacements::getAffectedRanges() const {
  483. std::vector<Range> ChangedRanges;
  484. int Shift = 0;
  485. for (const auto &R : Replaces) {
  486. unsigned Offset = R.getOffset() + Shift;
  487. unsigned Length = R.getReplacementText().size();
  488. Shift += Length - R.getLength();
  489. ChangedRanges.push_back(Range(Offset, Length));
  490. }
  491. return combineAndSortRanges(ChangedRanges);
  492. }
  493. unsigned Replacements::getShiftedCodePosition(unsigned Position) const {
  494. unsigned Offset = 0;
  495. for (const auto &R : Replaces) {
  496. if (R.getOffset() + R.getLength() <= Position) {
  497. Offset += R.getReplacementText().size() - R.getLength();
  498. continue;
  499. }
  500. if (R.getOffset() < Position &&
  501. R.getOffset() + R.getReplacementText().size() <= Position) {
  502. Position = R.getOffset() + R.getReplacementText().size();
  503. if (!R.getReplacementText().empty())
  504. Position--;
  505. }
  506. break;
  507. }
  508. return Position + Offset;
  509. }
  510. namespace clang {
  511. namespace tooling {
  512. bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite) {
  513. bool Result = true;
  514. for (auto I = Replaces.rbegin(), E = Replaces.rend(); I != E; ++I) {
  515. if (I->isApplicable()) {
  516. Result = I->apply(Rewrite) && Result;
  517. } else {
  518. Result = false;
  519. }
  520. }
  521. return Result;
  522. }
  523. llvm::Expected<std::string> applyAllReplacements(StringRef Code,
  524. const Replacements &Replaces) {
  525. if (Replaces.empty())
  526. return Code.str();
  527. IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
  528. new llvm::vfs::InMemoryFileSystem);
  529. FileManager Files(FileSystemOptions(), InMemoryFileSystem);
  530. DiagnosticsEngine Diagnostics(
  531. IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
  532. new DiagnosticOptions);
  533. SourceManager SourceMgr(Diagnostics, Files);
  534. Rewriter Rewrite(SourceMgr, LangOptions());
  535. InMemoryFileSystem->addFile(
  536. "<stdin>", 0, llvm::MemoryBuffer::getMemBuffer(Code, "<stdin>"));
  537. FileID ID = SourceMgr.createFileID(*Files.getOptionalFileRef("<stdin>"),
  538. SourceLocation(),
  539. clang::SrcMgr::C_User);
  540. for (auto I = Replaces.rbegin(), E = Replaces.rend(); I != E; ++I) {
  541. Replacement Replace("<stdin>", I->getOffset(), I->getLength(),
  542. I->getReplacementText());
  543. if (!Replace.apply(Rewrite))
  544. return llvm::make_error<ReplacementError>(
  545. replacement_error::fail_to_apply, Replace);
  546. }
  547. std::string Result;
  548. llvm::raw_string_ostream OS(Result);
  549. Rewrite.getEditBuffer(ID).write(OS);
  550. OS.flush();
  551. return Result;
  552. }
  553. std::map<std::string, Replacements> groupReplacementsByFile(
  554. FileManager &FileMgr,
  555. const std::map<std::string, Replacements> &FileToReplaces) {
  556. std::map<std::string, Replacements> Result;
  557. llvm::SmallPtrSet<const FileEntry *, 16> ProcessedFileEntries;
  558. for (const auto &Entry : FileToReplaces) {
  559. auto FE = FileMgr.getFile(Entry.first);
  560. if (!FE)
  561. llvm::errs() << "File path " << Entry.first << " is invalid.\n";
  562. else if (ProcessedFileEntries.insert(*FE).second)
  563. Result[Entry.first] = std::move(Entry.second);
  564. }
  565. return Result;
  566. }
  567. } // namespace tooling
  568. } // namespace clang