10b57cec5SDimitry Andric //===- Replacement.h - Framework for clang refactoring tools ----*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric //  Classes supporting refactorings that span multiple translation units.
100b57cec5SDimitry Andric //  While single translation unit refactorings are supported via the Rewriter,
110b57cec5SDimitry Andric //  when refactoring multiple translation units changes must be stored in a
120b57cec5SDimitry Andric //  SourceManager independent form, duplicate changes need to be removed, and
130b57cec5SDimitry Andric //  all changes must be applied at once at the end of the refactoring so that
140b57cec5SDimitry Andric //  the code is always parseable.
150b57cec5SDimitry Andric //
160b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #ifndef LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H
190b57cec5SDimitry Andric #define LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric #include "clang/Basic/LangOptions.h"
220b57cec5SDimitry Andric #include "clang/Basic/SourceLocation.h"
230b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
240b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
250b57cec5SDimitry Andric #include "llvm/Support/Error.h"
260b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
270b57cec5SDimitry Andric #include <map>
28bdd1243dSDimitry Andric #include <optional>
290b57cec5SDimitry Andric #include <set>
300b57cec5SDimitry Andric #include <string>
310b57cec5SDimitry Andric #include <system_error>
320b57cec5SDimitry Andric #include <utility>
330b57cec5SDimitry Andric #include <vector>
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric namespace clang {
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric class FileManager;
380b57cec5SDimitry Andric class Rewriter;
390b57cec5SDimitry Andric class SourceManager;
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric namespace tooling {
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric /// A source range independent of the \c SourceManager.
440b57cec5SDimitry Andric class Range {
450b57cec5SDimitry Andric public:
460b57cec5SDimitry Andric   Range() = default;
Range(unsigned Offset,unsigned Length)470b57cec5SDimitry Andric   Range(unsigned Offset, unsigned Length) : Offset(Offset), Length(Length) {}
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   /// Accessors.
500b57cec5SDimitry Andric   /// @{
getOffset()510b57cec5SDimitry Andric   unsigned getOffset() const { return Offset; }
getLength()520b57cec5SDimitry Andric   unsigned getLength() const { return Length; }
530b57cec5SDimitry Andric   /// @}
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   /// \name Range Predicates
560b57cec5SDimitry Andric   /// @{
570b57cec5SDimitry Andric   /// Whether this range overlaps with \p RHS or not.
overlapsWith(Range RHS)580b57cec5SDimitry Andric   bool overlapsWith(Range RHS) const {
590b57cec5SDimitry Andric     return Offset + Length > RHS.Offset && Offset < RHS.Offset + RHS.Length;
600b57cec5SDimitry Andric   }
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric   /// Whether this range contains \p RHS or not.
contains(Range RHS)630b57cec5SDimitry Andric   bool contains(Range RHS) const {
640b57cec5SDimitry Andric     return RHS.Offset >= Offset &&
650b57cec5SDimitry Andric            (RHS.Offset + RHS.Length) <= (Offset + Length);
660b57cec5SDimitry Andric   }
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   /// Whether this range equals to \p RHS or not.
690b57cec5SDimitry Andric   bool operator==(const Range &RHS) const {
700b57cec5SDimitry Andric     return Offset == RHS.getOffset() && Length == RHS.getLength();
710b57cec5SDimitry Andric   }
720b57cec5SDimitry Andric   /// @}
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric private:
750b57cec5SDimitry Andric   unsigned Offset = 0;
760b57cec5SDimitry Andric   unsigned Length = 0;
770b57cec5SDimitry Andric };
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric /// A text replacement.
800b57cec5SDimitry Andric ///
810b57cec5SDimitry Andric /// Represents a SourceManager independent replacement of a range of text in a
820b57cec5SDimitry Andric /// specific file.
830b57cec5SDimitry Andric class Replacement {
840b57cec5SDimitry Andric public:
850b57cec5SDimitry Andric   /// Creates an invalid (not applicable) replacement.
860b57cec5SDimitry Andric   Replacement();
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric   /// Creates a replacement of the range [Offset, Offset+Length) in
890b57cec5SDimitry Andric   /// FilePath with ReplacementText.
900b57cec5SDimitry Andric   ///
910b57cec5SDimitry Andric   /// \param FilePath A source file accessible via a SourceManager.
920b57cec5SDimitry Andric   /// \param Offset The byte offset of the start of the range in the file.
930b57cec5SDimitry Andric   /// \param Length The length of the range in bytes.
940b57cec5SDimitry Andric   Replacement(StringRef FilePath, unsigned Offset, unsigned Length,
950b57cec5SDimitry Andric               StringRef ReplacementText);
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   /// Creates a Replacement of the range [Start, Start+Length) with
980b57cec5SDimitry Andric   /// ReplacementText.
990b57cec5SDimitry Andric   Replacement(const SourceManager &Sources, SourceLocation Start,
1000b57cec5SDimitry Andric               unsigned Length, StringRef ReplacementText);
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   /// Creates a Replacement of the given range with ReplacementText.
1030b57cec5SDimitry Andric   Replacement(const SourceManager &Sources, const CharSourceRange &Range,
1040b57cec5SDimitry Andric               StringRef ReplacementText,
1050b57cec5SDimitry Andric               const LangOptions &LangOpts = LangOptions());
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   /// Creates a Replacement of the node with ReplacementText.
1080b57cec5SDimitry Andric   template <typename Node>
1090b57cec5SDimitry Andric   Replacement(const SourceManager &Sources, const Node &NodeToReplace,
1100b57cec5SDimitry Andric               StringRef ReplacementText,
1110b57cec5SDimitry Andric               const LangOptions &LangOpts = LangOptions());
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   /// Returns whether this replacement can be applied to a file.
1140b57cec5SDimitry Andric   ///
1150b57cec5SDimitry Andric   /// Only replacements that are in a valid file can be applied.
1160b57cec5SDimitry Andric   bool isApplicable() const;
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   /// Accessors.
1190b57cec5SDimitry Andric   /// @{
getFilePath()1200b57cec5SDimitry Andric   StringRef getFilePath() const { return FilePath; }
getOffset()1210b57cec5SDimitry Andric   unsigned getOffset() const { return ReplacementRange.getOffset(); }
getLength()1220b57cec5SDimitry Andric   unsigned getLength() const { return ReplacementRange.getLength(); }
getReplacementText()1230b57cec5SDimitry Andric   StringRef getReplacementText() const { return ReplacementText; }
1240b57cec5SDimitry Andric   /// @}
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric   /// Applies the replacement on the Rewriter.
1270b57cec5SDimitry Andric   bool apply(Rewriter &Rewrite) const;
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric   /// Returns a human readable string representation.
1300b57cec5SDimitry Andric   std::string toString() const;
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric private:
1330b57cec5SDimitry Andric   void setFromSourceLocation(const SourceManager &Sources, SourceLocation Start,
1340b57cec5SDimitry Andric                              unsigned Length, StringRef ReplacementText);
1350b57cec5SDimitry Andric   void setFromSourceRange(const SourceManager &Sources,
1360b57cec5SDimitry Andric                           const CharSourceRange &Range,
1370b57cec5SDimitry Andric                           StringRef ReplacementText,
1380b57cec5SDimitry Andric                           const LangOptions &LangOpts);
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric   std::string FilePath;
1410b57cec5SDimitry Andric   Range ReplacementRange;
1420b57cec5SDimitry Andric   std::string ReplacementText;
1430b57cec5SDimitry Andric };
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric enum class replacement_error {
1460b57cec5SDimitry Andric   fail_to_apply = 0,
1470b57cec5SDimitry Andric   wrong_file_path,
1480b57cec5SDimitry Andric   overlap_conflict,
1490b57cec5SDimitry Andric   insert_conflict,
1500b57cec5SDimitry Andric };
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric /// Carries extra error information in replacement-related llvm::Error,
1530b57cec5SDimitry Andric /// e.g. fail applying replacements and replacements conflict.
1540b57cec5SDimitry Andric class ReplacementError : public llvm::ErrorInfo<ReplacementError> {
1550b57cec5SDimitry Andric public:
ReplacementError(replacement_error Err)1560b57cec5SDimitry Andric   ReplacementError(replacement_error Err) : Err(Err) {}
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric   /// Constructs an error related to an existing replacement.
ReplacementError(replacement_error Err,Replacement Existing)1590b57cec5SDimitry Andric   ReplacementError(replacement_error Err, Replacement Existing)
1600b57cec5SDimitry Andric       : Err(Err), ExistingReplacement(std::move(Existing)) {}
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric   /// Constructs an error related to a new replacement and an existing
1630b57cec5SDimitry Andric   /// replacement in a set of replacements.
ReplacementError(replacement_error Err,Replacement New,Replacement Existing)1640b57cec5SDimitry Andric   ReplacementError(replacement_error Err, Replacement New, Replacement Existing)
1650b57cec5SDimitry Andric       : Err(Err), NewReplacement(std::move(New)),
1660b57cec5SDimitry Andric         ExistingReplacement(std::move(Existing)) {}
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   std::string message() const override;
1690b57cec5SDimitry Andric 
log(raw_ostream & OS)1700b57cec5SDimitry Andric   void log(raw_ostream &OS) const override { OS << message(); }
1710b57cec5SDimitry Andric 
get()1720b57cec5SDimitry Andric   replacement_error get() const { return Err; }
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric   static char ID;
1750b57cec5SDimitry Andric 
getNewReplacement()176bdd1243dSDimitry Andric   const std::optional<Replacement> &getNewReplacement() const {
1770b57cec5SDimitry Andric     return NewReplacement;
1780b57cec5SDimitry Andric   }
1790b57cec5SDimitry Andric 
getExistingReplacement()180bdd1243dSDimitry Andric   const std::optional<Replacement> &getExistingReplacement() const {
1810b57cec5SDimitry Andric     return ExistingReplacement;
1820b57cec5SDimitry Andric   }
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric private:
1850b57cec5SDimitry Andric   // Users are not expected to use error_code.
convertToErrorCode()1860b57cec5SDimitry Andric   std::error_code convertToErrorCode() const override {
1870b57cec5SDimitry Andric     return llvm::inconvertibleErrorCode();
1880b57cec5SDimitry Andric   }
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric   replacement_error Err;
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric   // A new replacement, which is to expected be added into a set of
1930b57cec5SDimitry Andric   // replacements, that is causing problem.
194bdd1243dSDimitry Andric   std::optional<Replacement> NewReplacement;
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric   // An existing replacement in a replacements set that is causing problem.
197bdd1243dSDimitry Andric   std::optional<Replacement> ExistingReplacement;
1980b57cec5SDimitry Andric };
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric /// Less-than operator between two Replacements.
2010b57cec5SDimitry Andric bool operator<(const Replacement &LHS, const Replacement &RHS);
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric /// Equal-to operator between two Replacements.
2040b57cec5SDimitry Andric bool operator==(const Replacement &LHS, const Replacement &RHS);
205bdd1243dSDimitry Andric inline bool operator!=(const Replacement &LHS, const Replacement &RHS) {
206bdd1243dSDimitry Andric   return !(LHS == RHS);
207bdd1243dSDimitry Andric }
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric /// Maintains a set of replacements that are conflict-free.
2100b57cec5SDimitry Andric /// Two replacements are considered conflicts if they overlap or have the same
2110b57cec5SDimitry Andric /// offset (i.e. order-dependent).
2120b57cec5SDimitry Andric class Replacements {
2130b57cec5SDimitry Andric private:
2140b57cec5SDimitry Andric   using ReplacementsImpl = std::set<Replacement>;
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric public:
2170b57cec5SDimitry Andric   using const_iterator = ReplacementsImpl::const_iterator;
2180b57cec5SDimitry Andric   using const_reverse_iterator = ReplacementsImpl::const_reverse_iterator;
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric   Replacements() = default;
2210b57cec5SDimitry Andric 
Replacements(const Replacement & R)2220b57cec5SDimitry Andric   explicit Replacements(const Replacement &R) { Replaces.insert(R); }
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric   /// Adds a new replacement \p R to the current set of replacements.
2250b57cec5SDimitry Andric   /// \p R must have the same file path as all existing replacements.
2260b57cec5SDimitry Andric   /// Returns `success` if the replacement is successfully inserted; otherwise,
2270b57cec5SDimitry Andric   /// it returns an llvm::Error, i.e. there is a conflict between R and the
2280b57cec5SDimitry Andric   /// existing replacements (i.e. they are order-dependent) or R's file path is
2290b57cec5SDimitry Andric   /// different from the filepath of existing replacements. Callers must
2300b57cec5SDimitry Andric   /// explicitly check the Error returned, and the returned error can be
2310b57cec5SDimitry Andric   /// converted to a string message with `llvm::toString()`. This prevents users
2320b57cec5SDimitry Andric   /// from adding order-dependent replacements. To control the order in which
2330b57cec5SDimitry Andric   /// order-dependent replacements are applied, use merge({R}) with R referring
2340b57cec5SDimitry Andric   /// to the changed code after applying all existing replacements.
2350b57cec5SDimitry Andric   /// Two replacements A and B are considered order-independent if applying them
2360b57cec5SDimitry Andric   /// in either order produces the same result. Note that the range of the
2370b57cec5SDimitry Andric   /// replacement that is applied later still refers to the original code.
2380b57cec5SDimitry Andric   /// These include (but not restricted to) replacements that:
2390b57cec5SDimitry Andric   ///   - don't overlap (being directly adjacent is fine) and
2400b57cec5SDimitry Andric   ///   - are overlapping deletions.
2410b57cec5SDimitry Andric   ///   - are insertions at the same offset and applying them in either order
2420b57cec5SDimitry Andric   ///     has the same effect, i.e. X + Y = Y + X when inserting X and Y
2430b57cec5SDimitry Andric   ///     respectively.
2440b57cec5SDimitry Andric   ///   - are identical replacements, i.e. applying the same replacement twice
2450b57cec5SDimitry Andric   ///     is equivalent to applying it once.
2460b57cec5SDimitry Andric   /// Examples:
2470b57cec5SDimitry Andric   /// 1. Replacement A(0, 0, "a") and B(0, 0, "aa") are order-independent since
2480b57cec5SDimitry Andric   ///    applying them in either order gives replacement (0, 0, "aaa").
2490b57cec5SDimitry Andric   ///    However, A(0, 0, "a") and B(0, 0, "b") are order-dependent since
2500b57cec5SDimitry Andric   ///    applying A first gives (0, 0, "ab") while applying B first gives (B, A,
2510b57cec5SDimitry Andric   ///    "ba").
2520b57cec5SDimitry Andric   /// 2. Replacement A(0, 2, "123") and B(0, 2, "123") are order-independent
2530b57cec5SDimitry Andric   ///    since applying them in either order gives (0, 2, "123").
2540b57cec5SDimitry Andric   /// 3. Replacement A(0, 3, "123") and B(2, 3, "321") are order-independent
2550b57cec5SDimitry Andric   ///    since either order gives (0, 5, "12321").
2560b57cec5SDimitry Andric   /// 4. Replacement A(0, 3, "ab") and B(0, 3, "ab") are order-independent since
2570b57cec5SDimitry Andric   ///    applying the same replacement twice is equivalent to applying it once.
2580b57cec5SDimitry Andric   /// Replacements with offset UINT_MAX are special - we do not detect conflicts
2590b57cec5SDimitry Andric   /// for such replacements since users may add them intentionally as a special
2600b57cec5SDimitry Andric   /// category of replacements.
2610b57cec5SDimitry Andric   llvm::Error add(const Replacement &R);
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric   /// Merges \p Replaces into the current replacements. \p Replaces
2640b57cec5SDimitry Andric   /// refers to code after applying the current replacements.
265bdd1243dSDimitry Andric   [[nodiscard]] Replacements merge(const Replacements &Replaces) const;
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric   // Returns the affected ranges in the changed code.
2680b57cec5SDimitry Andric   std::vector<Range> getAffectedRanges() const;
2690b57cec5SDimitry Andric 
2700b57cec5SDimitry Andric   // Returns the new offset in the code after replacements being applied.
2710b57cec5SDimitry Andric   // Note that if there is an insertion at Offset in the current replacements,
2720b57cec5SDimitry Andric   // \p Offset will be shifted to Offset + Length in inserted text.
2730b57cec5SDimitry Andric   unsigned getShiftedCodePosition(unsigned Position) const;
2740b57cec5SDimitry Andric 
size()2750b57cec5SDimitry Andric   unsigned size() const { return Replaces.size(); }
2760b57cec5SDimitry Andric 
clear()2770b57cec5SDimitry Andric   void clear() { Replaces.clear(); }
2780b57cec5SDimitry Andric 
empty()2790b57cec5SDimitry Andric   bool empty() const { return Replaces.empty(); }
2800b57cec5SDimitry Andric 
begin()2810b57cec5SDimitry Andric   const_iterator begin() const { return Replaces.begin(); }
2820b57cec5SDimitry Andric 
end()2830b57cec5SDimitry Andric   const_iterator end() const { return Replaces.end(); }
2840b57cec5SDimitry Andric 
rbegin()2850b57cec5SDimitry Andric   const_reverse_iterator rbegin() const  { return Replaces.rbegin(); }
2860b57cec5SDimitry Andric 
rend()2870b57cec5SDimitry Andric   const_reverse_iterator rend() const { return Replaces.rend(); }
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric   bool operator==(const Replacements &RHS) const {
2900b57cec5SDimitry Andric     return Replaces == RHS.Replaces;
2910b57cec5SDimitry Andric   }
2920b57cec5SDimitry Andric 
2930b57cec5SDimitry Andric private:
Replacements(const_iterator Begin,const_iterator End)2940b57cec5SDimitry Andric   Replacements(const_iterator Begin, const_iterator End)
2950b57cec5SDimitry Andric       : Replaces(Begin, End) {}
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric   // Returns `R` with new range that refers to code after `Replaces` being
2980b57cec5SDimitry Andric   // applied.
2990b57cec5SDimitry Andric   Replacement getReplacementInChangedCode(const Replacement &R) const;
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric   // Returns a set of replacements that is equivalent to the current
3020b57cec5SDimitry Andric   // replacements by merging all adjacent replacements. Two sets of replacements
3030b57cec5SDimitry Andric   // are considered equivalent if they have the same effect when they are
3040b57cec5SDimitry Andric   // applied.
3050b57cec5SDimitry Andric   Replacements getCanonicalReplacements() const;
3060b57cec5SDimitry Andric 
307bdd1243dSDimitry Andric   // If `R` and all existing replacements are order-independent, then merge it
3080b57cec5SDimitry Andric   // with `Replaces` and returns the merged replacements; otherwise, returns an
3090b57cec5SDimitry Andric   // error.
3100b57cec5SDimitry Andric   llvm::Expected<Replacements>
3110b57cec5SDimitry Andric   mergeIfOrderIndependent(const Replacement &R) const;
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric   ReplacementsImpl Replaces;
3140b57cec5SDimitry Andric };
3150b57cec5SDimitry Andric 
3160b57cec5SDimitry Andric /// Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
3170b57cec5SDimitry Andric ///
3180b57cec5SDimitry Andric /// Replacement applications happen independently of the success of
3190b57cec5SDimitry Andric /// other applications.
3200b57cec5SDimitry Andric ///
3210b57cec5SDimitry Andric /// \returns true if all replacements apply. false otherwise.
3220b57cec5SDimitry Andric bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite);
3230b57cec5SDimitry Andric 
3240b57cec5SDimitry Andric /// Applies all replacements in \p Replaces to \p Code.
3250b57cec5SDimitry Andric ///
3260b57cec5SDimitry Andric /// This completely ignores the path stored in each replacement. If all
3270b57cec5SDimitry Andric /// replacements are applied successfully, this returns the code with
3280b57cec5SDimitry Andric /// replacements applied; otherwise, an llvm::Error carrying llvm::StringError
3290b57cec5SDimitry Andric /// is returned (the Error message can be converted to string using
3300b57cec5SDimitry Andric /// `llvm::toString()` and 'std::error_code` in the `Error` should be ignored).
3310b57cec5SDimitry Andric llvm::Expected<std::string> applyAllReplacements(StringRef Code,
3320b57cec5SDimitry Andric                                                  const Replacements &Replaces);
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric /// Collection of Replacements generated from a single translation unit.
3350b57cec5SDimitry Andric struct TranslationUnitReplacements {
3360b57cec5SDimitry Andric   /// Name of the main source for the translation unit.
3370b57cec5SDimitry Andric   std::string MainSourceFile;
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric   std::vector<Replacement> Replacements;
3400b57cec5SDimitry Andric };
3410b57cec5SDimitry Andric 
3420b57cec5SDimitry Andric /// Calculates the new ranges after \p Replaces are applied. These
3430b57cec5SDimitry Andric /// include both the original \p Ranges and the affected ranges of \p Replaces
3440b57cec5SDimitry Andric /// in the new code.
3450b57cec5SDimitry Andric ///
3460b57cec5SDimitry Andric /// \pre Replacements must be for the same file.
3470b57cec5SDimitry Andric ///
3480b57cec5SDimitry Andric /// \return The new ranges after \p Replaces are applied. The new ranges will be
3490b57cec5SDimitry Andric /// sorted and non-overlapping.
3500b57cec5SDimitry Andric std::vector<Range>
3510b57cec5SDimitry Andric calculateRangesAfterReplacements(const Replacements &Replaces,
3520b57cec5SDimitry Andric                                  const std::vector<Range> &Ranges);
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric /// If there are multiple <File, Replacements> pairs with the same file
3550b57cec5SDimitry Andric /// entry, we only keep one pair and discard the rest.
3560b57cec5SDimitry Andric /// If a file does not exist, its corresponding replacements will be ignored.
3570b57cec5SDimitry Andric std::map<std::string, Replacements> groupReplacementsByFile(
3580b57cec5SDimitry Andric     FileManager &FileMgr,
3590b57cec5SDimitry Andric     const std::map<std::string, Replacements> &FileToReplaces);
3600b57cec5SDimitry Andric 
3610b57cec5SDimitry Andric template <typename Node>
Replacement(const SourceManager & Sources,const Node & NodeToReplace,StringRef ReplacementText,const LangOptions & LangOpts)3620b57cec5SDimitry Andric Replacement::Replacement(const SourceManager &Sources,
3630b57cec5SDimitry Andric                          const Node &NodeToReplace, StringRef ReplacementText,
3640b57cec5SDimitry Andric                          const LangOptions &LangOpts) {
3650b57cec5SDimitry Andric   const CharSourceRange Range =
3660b57cec5SDimitry Andric       CharSourceRange::getTokenRange(NodeToReplace->getSourceRange());
3670b57cec5SDimitry Andric   setFromSourceRange(Sources, Range, ReplacementText, LangOpts);
3680b57cec5SDimitry Andric }
3690b57cec5SDimitry Andric 
3700b57cec5SDimitry Andric } // namespace tooling
3710b57cec5SDimitry Andric 
3720b57cec5SDimitry Andric } // namespace clang
3730b57cec5SDimitry Andric 
3740b57cec5SDimitry Andric #endif // LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H
375