clang API Documentation
00001 //===--- Replacement.h - Framework for clang refactoring tools --*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // Classes supporting refactorings that span multiple translation units. 00011 // While single translation unit refactorings are supported via the Rewriter, 00012 // when refactoring multiple translation units changes must be stored in a 00013 // SourceManager independent form, duplicate changes need to be removed, and 00014 // all changes must be applied at once at the end of the refactoring so that 00015 // the code is always parseable. 00016 // 00017 //===----------------------------------------------------------------------===// 00018 00019 #ifndef LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H 00020 #define LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H 00021 00022 #include "clang/Basic/SourceLocation.h" 00023 #include "llvm/ADT/StringRef.h" 00024 #include <set> 00025 #include <string> 00026 #include <vector> 00027 00028 namespace clang { 00029 00030 class Rewriter; 00031 00032 namespace tooling { 00033 00034 /// \brief A source range independent of the \c SourceManager. 00035 class Range { 00036 public: 00037 Range() : Offset(0), Length(0) {} 00038 Range(unsigned Offset, unsigned Length) : Offset(Offset), Length(Length) {} 00039 00040 /// \brief Accessors. 00041 /// @{ 00042 unsigned getOffset() const { return Offset; } 00043 unsigned getLength() const { return Length; } 00044 /// @} 00045 00046 /// \name Range Predicates 00047 /// @{ 00048 /// \brief Whether this range overlaps with \p RHS or not. 00049 bool overlapsWith(Range RHS) const { 00050 return Offset + Length > RHS.Offset && Offset < RHS.Offset + RHS.Length; 00051 } 00052 00053 /// \brief Whether this range contains \p RHS or not. 00054 bool contains(Range RHS) const { 00055 return RHS.Offset >= Offset && 00056 (RHS.Offset + RHS.Length) <= (Offset + Length); 00057 } 00058 /// @} 00059 00060 private: 00061 unsigned Offset; 00062 unsigned Length; 00063 }; 00064 00065 /// \brief A text replacement. 00066 /// 00067 /// Represents a SourceManager independent replacement of a range of text in a 00068 /// specific file. 00069 class Replacement { 00070 public: 00071 /// \brief Creates an invalid (not applicable) replacement. 00072 Replacement(); 00073 00074 /// \brief Creates a replacement of the range [Offset, Offset+Length) in 00075 /// FilePath with ReplacementText. 00076 /// 00077 /// \param FilePath A source file accessible via a SourceManager. 00078 /// \param Offset The byte offset of the start of the range in the file. 00079 /// \param Length The length of the range in bytes. 00080 Replacement(StringRef FilePath, unsigned Offset, 00081 unsigned Length, StringRef ReplacementText); 00082 00083 /// \brief Creates a Replacement of the range [Start, Start+Length) with 00084 /// ReplacementText. 00085 Replacement(const SourceManager &Sources, SourceLocation Start, unsigned Length, 00086 StringRef ReplacementText); 00087 00088 /// \brief Creates a Replacement of the given range with ReplacementText. 00089 Replacement(const SourceManager &Sources, const CharSourceRange &Range, 00090 StringRef ReplacementText); 00091 00092 /// \brief Creates a Replacement of the node with ReplacementText. 00093 template <typename Node> 00094 Replacement(const SourceManager &Sources, const Node &NodeToReplace, 00095 StringRef ReplacementText); 00096 00097 /// \brief Returns whether this replacement can be applied to a file. 00098 /// 00099 /// Only replacements that are in a valid file can be applied. 00100 bool isApplicable() const; 00101 00102 /// \brief Accessors. 00103 /// @{ 00104 StringRef getFilePath() const { return FilePath; } 00105 unsigned getOffset() const { return ReplacementRange.getOffset(); } 00106 unsigned getLength() const { return ReplacementRange.getLength(); } 00107 StringRef getReplacementText() const { return ReplacementText; } 00108 /// @} 00109 00110 /// \brief Applies the replacement on the Rewriter. 00111 bool apply(Rewriter &Rewrite) const; 00112 00113 /// \brief Returns a human readable string representation. 00114 std::string toString() const; 00115 00116 private: 00117 void setFromSourceLocation(const SourceManager &Sources, SourceLocation Start, 00118 unsigned Length, StringRef ReplacementText); 00119 void setFromSourceRange(const SourceManager &Sources, 00120 const CharSourceRange &Range, 00121 StringRef ReplacementText); 00122 00123 std::string FilePath; 00124 Range ReplacementRange; 00125 std::string ReplacementText; 00126 }; 00127 00128 /// \brief Less-than operator between two Replacements. 00129 bool operator<(const Replacement &LHS, const Replacement &RHS); 00130 00131 /// \brief Equal-to operator between two Replacements. 00132 bool operator==(const Replacement &LHS, const Replacement &RHS); 00133 00134 /// \brief A set of Replacements. 00135 /// FIXME: Change to a vector and deduplicate in the RefactoringTool. 00136 typedef std::set<Replacement> Replacements; 00137 00138 /// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite. 00139 /// 00140 /// Replacement applications happen independently of the success of 00141 /// other applications. 00142 /// 00143 /// \returns true if all replacements apply. false otherwise. 00144 bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite); 00145 00146 /// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite. 00147 /// 00148 /// Replacement applications happen independently of the success of 00149 /// other applications. 00150 /// 00151 /// \returns true if all replacements apply. false otherwise. 00152 bool applyAllReplacements(const std::vector<Replacement> &Replaces, 00153 Rewriter &Rewrite); 00154 00155 /// \brief Applies all replacements in \p Replaces to \p Code. 00156 /// 00157 /// This completely ignores the path stored in each replacement. If one or more 00158 /// replacements cannot be applied, this returns an empty \c string. 00159 std::string applyAllReplacements(StringRef Code, const Replacements &Replaces); 00160 00161 /// \brief Calculates how a code \p Position is shifted when \p Replaces are 00162 /// applied. 00163 unsigned shiftedCodePosition(const Replacements& Replaces, unsigned Position); 00164 00165 /// \brief Calculates how a code \p Position is shifted when \p Replaces are 00166 /// applied. 00167 /// 00168 /// \pre Replaces[i].getOffset() <= Replaces[i+1].getOffset(). 00169 unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces, 00170 unsigned Position); 00171 00172 /// \brief Removes duplicate Replacements and reports if Replacements conflict 00173 /// with one another. All Replacements are assumed to be in the same file. 00174 /// 00175 /// \post Replaces[i].getOffset() <= Replaces[i+1].getOffset(). 00176 /// 00177 /// This function sorts \p Replaces so that conflicts can be reported simply by 00178 /// offset into \p Replaces and number of elements in the conflict. 00179 void deduplicate(std::vector<Replacement> &Replaces, 00180 std::vector<Range> &Conflicts); 00181 00182 /// \brief Collection of Replacements generated from a single translation unit. 00183 struct TranslationUnitReplacements { 00184 /// Name of the main source for the translation unit. 00185 std::string MainSourceFile; 00186 00187 /// A freeform chunk of text to describe the context of the replacements. 00188 /// Will be printed, for example, when detecting conflicts during replacement 00189 /// deduplication. 00190 std::string Context; 00191 00192 std::vector<Replacement> Replacements; 00193 }; 00194 00195 /// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite. 00196 /// 00197 /// Replacement applications happen independently of the success of 00198 /// other applications. 00199 /// 00200 /// \returns true if all replacements apply. false otherwise. 00201 bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite); 00202 00203 /// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite. 00204 /// 00205 /// Replacement applications happen independently of the success of 00206 /// other applications. 00207 /// 00208 /// \returns true if all replacements apply. false otherwise. 00209 bool applyAllReplacements(const std::vector<Replacement> &Replaces, 00210 Rewriter &Rewrite); 00211 00212 /// \brief Applies all replacements in \p Replaces to \p Code. 00213 /// 00214 /// This completely ignores the path stored in each replacement. If one or more 00215 /// replacements cannot be applied, this returns an empty \c string. 00216 std::string applyAllReplacements(StringRef Code, const Replacements &Replaces); 00217 00218 template <typename Node> 00219 Replacement::Replacement(const SourceManager &Sources, 00220 const Node &NodeToReplace, StringRef ReplacementText) { 00221 const CharSourceRange Range = 00222 CharSourceRange::getTokenRange(NodeToReplace->getSourceRange()); 00223 setFromSourceRange(Sources, Range, ReplacementText); 00224 } 00225 00226 } // end namespace tooling 00227 } // end namespace clang 00228 00229 #endif // LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H