]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/llvm/tools/clang/include/clang/Tooling/Refactoring.h
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / llvm / tools / clang / include / clang / Tooling / Refactoring.h
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
28 namespace clang {
29
30 class Rewriter;
31 class SourceLocation;
32
33 namespace tooling {
34
35 /// \brief A source range independent of the \c SourceManager.
36 class Range {
37 public:
38   Range() : Offset(0), Length(0) {}
39   Range(unsigned Offset, unsigned Length) : Offset(Offset), Length(Length) {}
40
41   /// \brief Accessors.
42   /// @{
43   unsigned getOffset() const { return Offset; }
44   unsigned getLength() const { return Length; }
45   /// @}
46
47   /// \name Range Predicates
48   /// @{
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;
52   }
53
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);
58   }
59   /// @}
60
61 private:
62   unsigned Offset;
63   unsigned Length;
64 };
65
66 /// \brief A text replacement.
67 ///
68 /// Represents a SourceManager independent replacement of a range of text in a
69 /// specific file.
70 class Replacement {
71 public:
72   /// \brief Creates an invalid (not applicable) replacement.
73   Replacement();
74
75   /// \brief Creates a replacement of the range [Offset, Offset+Length) in
76   /// FilePath with ReplacementText.
77   ///
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);
83
84   /// \brief Creates a Replacement of the range [Start, Start+Length) with
85   /// ReplacementText.
86   Replacement(SourceManager &Sources, SourceLocation Start, unsigned Length,
87               StringRef ReplacementText);
88
89   /// \brief Creates a Replacement of the given range with ReplacementText.
90   Replacement(SourceManager &Sources, const CharSourceRange &Range,
91               StringRef ReplacementText);
92
93   /// \brief Creates a Replacement of the node with ReplacementText.
94   template <typename Node>
95   Replacement(SourceManager &Sources, const Node &NodeToReplace,
96               StringRef ReplacementText);
97
98   /// \brief Returns whether this replacement can be applied to a file.
99   ///
100   /// Only replacements that are in a valid file can be applied.
101   bool isApplicable() const;
102
103   /// \brief Accessors.
104   /// @{
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; }
109   /// @}
110
111   /// \brief Applies the replacement on the Rewriter.
112   bool apply(Rewriter &Rewrite) const;
113
114   /// \brief Returns a human readable string representation.
115   std::string toString() const;
116
117  private:
118   void setFromSourceLocation(SourceManager &Sources, SourceLocation Start,
119                              unsigned Length, StringRef ReplacementText);
120   void setFromSourceRange(SourceManager &Sources, 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.
129 bool operator<(const Replacement &LHS, const Replacement &RHS);
130
131 /// \brief Equal-to operator between two Replacements.
132 bool 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.
136 typedef 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.
144 bool 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.
152 bool 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.
159 std::string applyAllReplacements(StringRef Code, const Replacements &Replaces);
160
161 /// \brief Calculates how a code \p Position is shifted when \p Replaces are
162 /// applied.
163 unsigned 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().
169 unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces,
170                              unsigned Position);
171
172 /// \brief Removes duplicate Replacements and reports if Replacements conflict
173 /// with one another.
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.
179 void deduplicate(std::vector<Replacement> &Replaces,
180                  std::vector<Range> &Conflicts);
181
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;
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 A tool to run refactorings.
196 ///
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 {
201 public:
202   /// \see ClangTool::ClangTool.
203   RefactoringTool(const CompilationDatabase &Compilations,
204                   ArrayRef<std::string> SourcePaths);
205
206   /// \brief Returns the set of replacements to which replacements should
207   /// be added during the run of the tool.
208   Replacements &getReplacements();
209
210   /// \brief Call run(), apply all generated replacements, and immediately save
211   /// the results to disk.
212   ///
213   /// \returns 0 upon success. Non-zero upon failure.
214   int runAndSave(FrontendActionFactory *ActionFactory);
215
216   /// \brief Apply all stored replacements to the given Rewriter.
217   ///
218   /// Replacement applications happen independently of the success of other
219   /// applications.
220   ///
221   /// \returns true if all replacements apply. false otherwise.
222   bool applyAllReplacements(Rewriter &Rewrite);
223
224 private:
225   /// \brief Write all refactored files to disk.
226   int saveRewrittenFiles(Rewriter &Rewrite);
227
228 private:
229   Replacements Replace;
230 };
231
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);
238 }
239
240 } // end namespace tooling
241 } // end namespace clang
242
243 #endif // end namespace LLVM_CLANG_TOOLING_REFACTORING_H