1//===--- Replacement.h - Framework for clang refactoring tools --*- C++ -*-===// 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// Classes supporting refactorings that span multiple translation units. 11// While single translation unit refactorings are supported via the Rewriter, 12// when refactoring multiple translation units changes must be stored in a 13// SourceManager independent form, duplicate changes need to be removed, and 14// all changes must be applied at once at the end of the refactoring so that 15// the code is always parseable. 16// 17//===----------------------------------------------------------------------===// 18 19#ifndef LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H 20#define LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H 21 22#include "clang/Basic/SourceLocation.h" 23#include "llvm/ADT/StringRef.h" 24#include <set> 25#include <string> 26#include <vector> 27 28namespace clang { 29 30class Rewriter; 31 32namespace tooling { 33 34/// \brief A source range independent of the \c SourceManager. 35class Range { 36public: 37 Range() : Offset(0), Length(0) {} 38 Range(unsigned Offset, unsigned Length) : Offset(Offset), Length(Length) {} 39 40 /// \brief Accessors. 41 /// @{ 42 unsigned getOffset() const { return Offset; } 43 unsigned getLength() const { return Length; } 44 /// @} 45 46 /// \name Range Predicates 47 /// @{ 48 /// \brief Whether this range overlaps with \p RHS or not. 49 bool overlapsWith(Range RHS) const { 50 return Offset + Length > RHS.Offset && Offset < RHS.Offset + RHS.Length; 51 } 52 53 /// \brief Whether this range contains \p RHS or not. 54 bool contains(Range RHS) const { 55 return RHS.Offset >= Offset && 56 (RHS.Offset + RHS.Length) <= (Offset + Length); 57 } 58 /// @} 59 60private: 61 unsigned Offset; 62 unsigned Length; 63}; 64 65/// \brief A text replacement. 66/// 67/// Represents a SourceManager independent replacement of a range of text in a 68/// specific file. 69class Replacement { 70public: 71 /// \brief Creates an invalid (not applicable) replacement. 72 Replacement(); 73 74 /// \brief Creates a replacement of the range [Offset, Offset+Length) in 75 /// FilePath with ReplacementText. 76 /// 77 /// \param FilePath A source file accessible via a SourceManager. 78 /// \param Offset The byte offset of the start of the range in the file. 79 /// \param Length The length of the range in bytes. 80 Replacement(StringRef FilePath, unsigned Offset, 81 unsigned Length, StringRef ReplacementText); 82 83 /// \brief Creates a Replacement of the range [Start, Start+Length) with 84 /// ReplacementText. 85 Replacement(const SourceManager &Sources, SourceLocation Start, unsigned Length, 86 StringRef ReplacementText); 87 88 /// \brief Creates a Replacement of the given range with ReplacementText. 89 Replacement(const SourceManager &Sources, const CharSourceRange &Range, 90 StringRef ReplacementText); 91 92 /// \brief Creates a Replacement of the node with ReplacementText. 93 template <typename Node> 94 Replacement(const SourceManager &Sources, const Node &NodeToReplace, 95 StringRef ReplacementText); 96 97 /// \brief Returns whether this replacement can be applied to a file. 98 /// 99 /// Only replacements that are in a valid file can be applied. 100 bool isApplicable() const; 101 102 /// \brief Accessors. 103 /// @{ 104 StringRef getFilePath() const { return FilePath; } 105 unsigned getOffset() const { return ReplacementRange.getOffset(); } 106 unsigned getLength() const { return ReplacementRange.getLength(); } 107 StringRef getReplacementText() const { return ReplacementText; } 108 /// @} 109 110 /// \brief Applies the replacement on the Rewriter. 111 bool apply(Rewriter &Rewrite) const; 112 113 /// \brief Returns a human readable string representation. 114 std::string toString() const; 115 116 private: 117 void setFromSourceLocation(const SourceManager &Sources, SourceLocation Start, 118 unsigned Length, StringRef ReplacementText); 119 void setFromSourceRange(const SourceManager &Sources, 120 const CharSourceRange &Range, 121 StringRef ReplacementText); 122 123 std::string FilePath; 124 Range ReplacementRange; 125 std::string ReplacementText; 126}; 127 128/// \brief Less-than operator between two Replacements. 129bool operator<(const Replacement &LHS, const Replacement &RHS); 130 131/// \brief Equal-to operator between two Replacements. 132bool operator==(const Replacement &LHS, const Replacement &RHS); 133 134/// \brief A set of Replacements. 135/// FIXME: Change to a vector and deduplicate in the RefactoringTool. 136typedef std::set<Replacement> Replacements; 137 138/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite. 139/// 140/// Replacement applications happen independently of the success of 141/// other applications. 142/// 143/// \returns true if all replacements apply. false otherwise. 144bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite); 145 146/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite. 147/// 148/// Replacement applications happen independently of the success of 149/// other applications. 150/// 151/// \returns true if all replacements apply. false otherwise. 152bool applyAllReplacements(const std::vector<Replacement> &Replaces, 153 Rewriter &Rewrite); 154 155/// \brief Applies all replacements in \p Replaces to \p Code. 156/// 157/// This completely ignores the path stored in each replacement. If one or more 158/// replacements cannot be applied, this returns an empty \c string. 159std::string applyAllReplacements(StringRef Code, const Replacements &Replaces); 160 161/// \brief Calculates how a code \p Position is shifted when \p Replaces are 162/// applied. 163unsigned shiftedCodePosition(const Replacements& Replaces, unsigned Position); 164 165/// \brief Calculates how a code \p Position is shifted when \p Replaces are 166/// applied. 167/// 168/// \pre Replaces[i].getOffset() <= Replaces[i+1].getOffset(). 169unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces, 170 unsigned Position); 171 172/// \brief Removes duplicate Replacements and reports if Replacements conflict 173/// with one another. All Replacements are assumed to be in the same file. 174/// 175/// \post Replaces[i].getOffset() <= Replaces[i+1].getOffset(). 176/// 177/// This function sorts \p Replaces so that conflicts can be reported simply by 178/// offset into \p Replaces and number of elements in the conflict. 179void deduplicate(std::vector<Replacement> &Replaces, 180 std::vector<Range> &Conflicts); 181 182/// \brief Collection of Replacements generated from a single translation unit. 183struct TranslationUnitReplacements { 184 /// Name of the main source for the translation unit. 185 std::string MainSourceFile; 186 187 /// A freeform chunk of text to describe the context of the replacements. 188 /// Will be printed, for example, when detecting conflicts during replacement 189 /// deduplication. 190 std::string Context; 191 192 std::vector<Replacement> Replacements; 193}; 194 195/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite. 196/// 197/// Replacement applications happen independently of the success of 198/// other applications. 199/// 200/// \returns true if all replacements apply. false otherwise. 201bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite); 202 203/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite. 204/// 205/// Replacement applications happen independently of the success of 206/// other applications. 207/// 208/// \returns true if all replacements apply. false otherwise. 209bool applyAllReplacements(const std::vector<Replacement> &Replaces, 210 Rewriter &Rewrite); 211 212/// \brief Applies all replacements in \p Replaces to \p Code. 213/// 214/// This completely ignores the path stored in each replacement. If one or more 215/// replacements cannot be applied, this returns an empty \c string. 216std::string applyAllReplacements(StringRef Code, const Replacements &Replaces); 217 218template <typename Node> 219Replacement::Replacement(const SourceManager &Sources, 220 const Node &NodeToReplace, StringRef ReplacementText) { 221 const CharSourceRange Range = 222 CharSourceRange::getTokenRange(NodeToReplace->getSourceRange()); 223 setFromSourceRange(Sources, Range, ReplacementText); 224} 225 226} // end namespace tooling 227} // end namespace clang 228 229#endif // LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H 230