1 //===--- Refactoring.h - Framework for clang refactoring tools --*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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.
17 //===----------------------------------------------------------------------===//
19 #ifndef LLVM_CLANG_TOOLING_REFACTORING_H
20 #define LLVM_CLANG_TOOLING_REFACTORING_H
22 #include "clang/Basic/SourceLocation.h"
23 #include "clang/Tooling/Tooling.h"
24 #include "llvm/ADT/StringRef.h"
35 /// \brief A source range independent of the \c SourceManager.
38 Range() : Offset(0), Length(0) {}
39 Range(unsigned Offset, unsigned Length) : Offset(Offset), Length(Length) {}
43 unsigned getOffset() const { return Offset; }
44 unsigned getLength() const { return Length; }
47 /// \name Range Predicates
49 /// \brief Whether this range overlaps with \p RHS or not.
50 bool overlapsWith(Range RHS) const {
51 return Offset + Length > RHS.Offset && Offset < RHS.Offset + RHS.Length;
54 /// \brief Whether this range contains \p RHS or not.
55 bool contains(Range RHS) const {
56 return RHS.Offset >= Offset &&
57 (RHS.Offset + RHS.Length) <= (Offset + Length);
66 /// \brief A text replacement.
68 /// Represents a SourceManager independent replacement of a range of text in a
72 /// \brief Creates an invalid (not applicable) replacement.
75 /// \brief Creates a replacement of the range [Offset, Offset+Length) in
76 /// FilePath with ReplacementText.
78 /// \param FilePath A source file accessible via a SourceManager.
79 /// \param Offset The byte offset of the start of the range in the file.
80 /// \param Length The length of the range in bytes.
81 Replacement(StringRef FilePath, unsigned Offset,
82 unsigned Length, StringRef ReplacementText);
84 /// \brief Creates a Replacement of the range [Start, Start+Length) with
86 Replacement(SourceManager &Sources, SourceLocation Start, unsigned Length,
87 StringRef ReplacementText);
89 /// \brief Creates a Replacement of the given range with ReplacementText.
90 Replacement(SourceManager &Sources, const CharSourceRange &Range,
91 StringRef ReplacementText);
93 /// \brief Creates a Replacement of the node with ReplacementText.
94 template <typename Node>
95 Replacement(SourceManager &Sources, const Node &NodeToReplace,
96 StringRef ReplacementText);
98 /// \brief Returns whether this replacement can be applied to a file.
100 /// Only replacements that are in a valid file can be applied.
101 bool isApplicable() const;
103 /// \brief Accessors.
105 StringRef getFilePath() const { return FilePath; }
106 unsigned getOffset() const { return ReplacementRange.getOffset(); }
107 unsigned getLength() const { return ReplacementRange.getLength(); }
108 StringRef getReplacementText() const { return ReplacementText; }
111 /// \brief Applies the replacement on the Rewriter.
112 bool apply(Rewriter &Rewrite) const;
114 /// \brief Returns a human readable string representation.
115 std::string toString() const;
118 void setFromSourceLocation(SourceManager &Sources, SourceLocation Start,
119 unsigned Length, StringRef ReplacementText);
120 void setFromSourceRange(SourceManager &Sources, const CharSourceRange &Range,
121 StringRef ReplacementText);
123 std::string FilePath;
124 Range ReplacementRange;
125 std::string ReplacementText;
128 /// \brief Less-than operator between two Replacements.
129 bool operator<(const Replacement &LHS, const Replacement &RHS);
131 /// \brief Equal-to operator between two Replacements.
132 bool operator==(const Replacement &LHS, const Replacement &RHS);
134 /// \brief A set of Replacements.
135 /// FIXME: Change to a vector and deduplicate in the RefactoringTool.
136 typedef std::set<Replacement> Replacements;
138 /// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
140 /// Replacement applications happen independently of the success of
141 /// other applications.
143 /// \returns true if all replacements apply. false otherwise.
144 bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite);
146 /// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
148 /// Replacement applications happen independently of the success of
149 /// other applications.
151 /// \returns true if all replacements apply. false otherwise.
152 bool applyAllReplacements(const std::vector<Replacement> &Replaces,
155 /// \brief Applies all replacements in \p Replaces to \p Code.
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.
159 std::string applyAllReplacements(StringRef Code, const Replacements &Replaces);
161 /// \brief Calculates how a code \p Position is shifted when \p Replaces are
163 unsigned shiftedCodePosition(const Replacements& Replaces, unsigned Position);
165 /// \brief Calculates how a code \p Position is shifted when \p Replaces are
168 /// \pre Replaces[i].getOffset() <= Replaces[i+1].getOffset().
169 unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces,
172 /// \brief Removes duplicate Replacements and reports if Replacements conflict
173 /// with one another.
175 /// \post Replaces[i].getOffset() <= Replaces[i+1].getOffset().
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.
179 void deduplicate(std::vector<Replacement> &Replaces,
180 std::vector<Range> &Conflicts);
182 /// \brief Collection of Replacements generated from a single translation unit.
183 struct TranslationUnitReplacements {
184 /// Name of the main source for the translation unit.
185 std::string MainSourceFile;
187 /// A freeform chunk of text to describe the context of the replacements.
188 /// Will be printed, for example, when detecting conflicts during replacement
192 std::vector<Replacement> Replacements;
195 /// \brief A tool to run refactorings.
197 /// This is a refactoring specific version of \see ClangTool. FrontendActions
198 /// passed to run() and runAndSave() should add replacements to
199 /// getReplacements().
200 class RefactoringTool : public ClangTool {
202 /// \see ClangTool::ClangTool.
203 RefactoringTool(const CompilationDatabase &Compilations,
204 ArrayRef<std::string> SourcePaths);
206 /// \brief Returns the set of replacements to which replacements should
207 /// be added during the run of the tool.
208 Replacements &getReplacements();
210 /// \brief Call run(), apply all generated replacements, and immediately save
211 /// the results to disk.
213 /// \returns 0 upon success. Non-zero upon failure.
214 int runAndSave(FrontendActionFactory *ActionFactory);
216 /// \brief Apply all stored replacements to the given Rewriter.
218 /// Replacement applications happen independently of the success of other
221 /// \returns true if all replacements apply. false otherwise.
222 bool applyAllReplacements(Rewriter &Rewrite);
225 /// \brief Write all refactored files to disk.
226 int saveRewrittenFiles(Rewriter &Rewrite);
229 Replacements Replace;
232 template <typename Node>
233 Replacement::Replacement(SourceManager &Sources, const Node &NodeToReplace,
234 StringRef ReplacementText) {
235 const CharSourceRange Range =
236 CharSourceRange::getTokenRange(NodeToReplace->getSourceRange());
237 setFromSourceRange(Sources, Range, ReplacementText);
240 } // end namespace tooling
241 } // end namespace clang
243 #endif // end namespace LLVM_CLANG_TOOLING_REFACTORING_H