Replacement.cpp 24 KB

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