Refactoring.h revision 8a99945769aa83270bda4ae4890f519800aa19eb
1//===--- Refactoring.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// Interfaces 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_REFACTORING_H 20#define LLVM_CLANG_TOOLING_REFACTORING_H 21 22#include "clang/Basic/SourceLocation.h" 23#include "clang/Tooling/Tooling.h" 24#include "llvm/ADT/StringRef.h" 25#include <set> 26#include <string> 27 28namespace clang { 29 30class Rewriter; 31class SourceLocation; 32 33namespace tooling { 34 35/// \brief A source range independent of the \c SourceManager. 36class Range { 37public: 38 Range() : Offset(0), Length(0) {} 39 Range(unsigned Offset, unsigned Length) : Offset(Offset), Length(Length) {} 40 41 unsigned getOffset() const { return Offset; } 42 unsigned getLength() const { return Length; } 43 44private: 45 unsigned Offset; 46 unsigned Length; 47}; 48 49/// \brief A text replacement. 50/// 51/// Represents a SourceManager independent replacement of a range of text in a 52/// specific file. 53class Replacement { 54public: 55 /// \brief Creates an invalid (not applicable) replacement. 56 Replacement(); 57 58 /// \brief Creates a replacement of the range [Offset, Offset+Length) in 59 /// FilePath with ReplacementText. 60 /// 61 /// \param FilePath A source file accessible via a SourceManager. 62 /// \param Offset The byte offset of the start of the range in the file. 63 /// \param Length The length of the range in bytes. 64 Replacement(StringRef FilePath, unsigned Offset, 65 unsigned Length, StringRef ReplacementText); 66 67 /// \brief Creates a Replacement of the range [Start, Start+Length) with 68 /// ReplacementText. 69 Replacement(SourceManager &Sources, SourceLocation Start, unsigned Length, 70 StringRef ReplacementText); 71 72 /// \brief Creates a Replacement of the given range with ReplacementText. 73 Replacement(SourceManager &Sources, const CharSourceRange &Range, 74 StringRef ReplacementText); 75 76 /// \brief Creates a Replacement of the node with ReplacementText. 77 template <typename Node> 78 Replacement(SourceManager &Sources, const Node &NodeToReplace, 79 StringRef ReplacementText); 80 81 /// \brief Returns whether this replacement can be applied to a file. 82 /// 83 /// Only replacements that are in a valid file can be applied. 84 bool isApplicable() const; 85 86 /// \brief Accessors. 87 /// @{ 88 StringRef getFilePath() const { return FilePath; } 89 unsigned getOffset() const { return ReplacementRange.getOffset(); } 90 unsigned getLength() const { return ReplacementRange.getLength(); } 91 StringRef getReplacementText() const { return ReplacementText; } 92 /// @} 93 94 /// \brief Applies the replacement on the Rewriter. 95 bool apply(Rewriter &Rewrite) const; 96 97 /// \brief Returns a human readable string representation. 98 std::string toString() const; 99 100 /// \brief Comparator to be able to use Replacement in std::set for uniquing. 101 class Less { 102 public: 103 bool operator()(const Replacement &R1, const Replacement &R2) const; 104 }; 105 106 private: 107 void setFromSourceLocation(SourceManager &Sources, SourceLocation Start, 108 unsigned Length, StringRef ReplacementText); 109 void setFromSourceRange(SourceManager &Sources, const CharSourceRange &Range, 110 StringRef ReplacementText); 111 112 std::string FilePath; 113 Range ReplacementRange; 114 std::string ReplacementText; 115}; 116 117/// \brief A set of Replacements. 118/// FIXME: Change to a vector and deduplicate in the RefactoringTool. 119typedef std::set<Replacement, Replacement::Less> Replacements; 120 121/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite. 122/// 123/// Replacement applications happen independently of the success of 124/// other applications. 125/// 126/// \returns true if all replacements apply. false otherwise. 127bool applyAllReplacements(Replacements &Replaces, Rewriter &Rewrite); 128 129/// \brief Applies all replacements in \p Replaces to \p Code. 130/// 131/// This completely ignores the path stored in each replacement. If one or more 132/// replacements cannot be applied, this returns an empty \c string. 133std::string applyAllReplacements(StringRef Code, Replacements &Replaces); 134 135/// \brief A tool to run refactorings. 136/// 137/// This is a refactoring specific version of \see ClangTool. FrontendActions 138/// passed to run() and runAndSave() should add replacements to 139/// getReplacements(). 140class RefactoringTool : public ClangTool { 141public: 142 /// \see ClangTool::ClangTool. 143 RefactoringTool(const CompilationDatabase &Compilations, 144 ArrayRef<std::string> SourcePaths); 145 146 /// \brief Returns the set of replacements to which replacements should 147 /// be added during the run of the tool. 148 Replacements &getReplacements(); 149 150 /// \brief Call run(), apply all generated replacements, and immediately save 151 /// the results to disk. 152 /// 153 /// \returns 0 upon success. Non-zero upon failure. 154 int runAndSave(FrontendActionFactory *ActionFactory); 155 156 /// \brief Apply all stored replacements to the given Rewriter. 157 /// 158 /// Replacement applications happen independently of the success of other 159 /// applications. 160 /// 161 /// \returns true if all replacements apply. false otherwise. 162 bool applyAllReplacements(Rewriter &Rewrite); 163 164private: 165 /// \brief Write all refactored files to disk. 166 int saveRewrittenFiles(Rewriter &Rewrite); 167 168private: 169 Replacements Replace; 170}; 171 172template <typename Node> 173Replacement::Replacement(SourceManager &Sources, const Node &NodeToReplace, 174 StringRef ReplacementText) { 175 const CharSourceRange Range = 176 CharSourceRange::getTokenRange(NodeToReplace->getSourceRange()); 177 setFromSourceRange(Sources, Range, ReplacementText); 178} 179 180} // end namespace tooling 181} // end namespace clang 182 183#endif // end namespace LLVM_CLANG_TOOLING_REFACTORING_H 184