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