1239313Sdim//===--- Refactoring.h - Framework for clang refactoring tools --*- C++ -*-===//
2239313Sdim//
3239313Sdim//                     The LLVM Compiler Infrastructure
4239313Sdim//
5239313Sdim// This file is distributed under the University of Illinois Open Source
6239313Sdim// License. See LICENSE.TXT for details.
7239313Sdim//
8239313Sdim//===----------------------------------------------------------------------===//
9239313Sdim//
10239313Sdim//  Interfaces supporting refactorings that span multiple translation units.
11239313Sdim//  While single translation unit refactorings are supported via the Rewriter,
12239313Sdim//  when refactoring multiple translation units changes must be stored in a
13239313Sdim//  SourceManager independent form, duplicate changes need to be removed, and
14239313Sdim//  all changes must be applied at once at the end of the refactoring so that
15239313Sdim//  the code is always parseable.
16239313Sdim//
17239313Sdim//===----------------------------------------------------------------------===//
18239313Sdim
19239313Sdim#ifndef LLVM_CLANG_TOOLING_REFACTORING_H
20239313Sdim#define LLVM_CLANG_TOOLING_REFACTORING_H
21239313Sdim
22239313Sdim#include "clang/Basic/SourceLocation.h"
23239313Sdim#include "clang/Tooling/Tooling.h"
24249423Sdim#include "llvm/ADT/StringRef.h"
25239313Sdim#include <set>
26239313Sdim#include <string>
27239313Sdim
28239313Sdimnamespace clang {
29239313Sdim
30239313Sdimclass Rewriter;
31239313Sdimclass SourceLocation;
32239313Sdim
33239313Sdimnamespace tooling {
34239313Sdim
35239313Sdim/// \brief A text replacement.
36239313Sdim///
37239313Sdim/// Represents a SourceManager independent replacement of a range of text in a
38239313Sdim/// specific file.
39239313Sdimclass Replacement {
40239313Sdimpublic:
41239313Sdim  /// \brief Creates an invalid (not applicable) replacement.
42239313Sdim  Replacement();
43239313Sdim
44239313Sdim  /// \brief Creates a replacement of the range [Offset, Offset+Length) in
45239313Sdim  /// FilePath with ReplacementText.
46239313Sdim  ///
47239313Sdim  /// \param FilePath A source file accessible via a SourceManager.
48239313Sdim  /// \param Offset The byte offset of the start of the range in the file.
49239313Sdim  /// \param Length The length of the range in bytes.
50249423Sdim  Replacement(StringRef FilePath, unsigned Offset,
51249423Sdim              unsigned Length, StringRef ReplacementText);
52239313Sdim
53239313Sdim  /// \brief Creates a Replacement of the range [Start, Start+Length) with
54239313Sdim  /// ReplacementText.
55239313Sdim  Replacement(SourceManager &Sources, SourceLocation Start, unsigned Length,
56249423Sdim              StringRef ReplacementText);
57239313Sdim
58239313Sdim  /// \brief Creates a Replacement of the given range with ReplacementText.
59239313Sdim  Replacement(SourceManager &Sources, const CharSourceRange &Range,
60249423Sdim              StringRef ReplacementText);
61239313Sdim
62239313Sdim  /// \brief Creates a Replacement of the node with ReplacementText.
63239313Sdim  template <typename Node>
64239313Sdim  Replacement(SourceManager &Sources, const Node &NodeToReplace,
65249423Sdim              StringRef ReplacementText);
66239313Sdim
67239313Sdim  /// \brief Returns whether this replacement can be applied to a file.
68239313Sdim  ///
69239313Sdim  /// Only replacements that are in a valid file can be applied.
70239313Sdim  bool isApplicable() const;
71239313Sdim
72239313Sdim  /// \brief Accessors.
73239313Sdim  /// @{
74239313Sdim  StringRef getFilePath() const { return FilePath; }
75239313Sdim  unsigned getOffset() const { return Offset; }
76239313Sdim  unsigned getLength() const { return Length; }
77243830Sdim  StringRef getReplacementText() const { return ReplacementText; }
78239313Sdim  /// @}
79239313Sdim
80239313Sdim  /// \brief Applies the replacement on the Rewriter.
81239313Sdim  bool apply(Rewriter &Rewrite) const;
82239313Sdim
83239313Sdim  /// \brief Returns a human readable string representation.
84239313Sdim  std::string toString() const;
85239313Sdim
86239313Sdim  /// \brief Comparator to be able to use Replacement in std::set for uniquing.
87239313Sdim  class Less {
88239313Sdim  public:
89239313Sdim    bool operator()(const Replacement &R1, const Replacement &R2) const;
90239313Sdim  };
91239313Sdim
92239313Sdim private:
93239313Sdim  void setFromSourceLocation(SourceManager &Sources, SourceLocation Start,
94249423Sdim                             unsigned Length, StringRef ReplacementText);
95239313Sdim  void setFromSourceRange(SourceManager &Sources, const CharSourceRange &Range,
96249423Sdim                          StringRef ReplacementText);
97239313Sdim
98239313Sdim  std::string FilePath;
99239313Sdim  unsigned Offset;
100239313Sdim  unsigned Length;
101239313Sdim  std::string ReplacementText;
102239313Sdim};
103239313Sdim
104239313Sdim/// \brief A set of Replacements.
105239313Sdim/// FIXME: Change to a vector and deduplicate in the RefactoringTool.
106239313Sdimtypedef std::set<Replacement, Replacement::Less> Replacements;
107239313Sdim
108249423Sdim/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
109239313Sdim///
110249423Sdim/// Replacement applications happen independently of the success of
111249423Sdim/// other applications.
112249423Sdim///
113249423Sdim/// \returns true if all replacements apply. false otherwise.
114239313Sdimbool applyAllReplacements(Replacements &Replaces, Rewriter &Rewrite);
115239313Sdim
116239313Sdim/// \brief A tool to run refactorings.
117239313Sdim///
118249423Sdim/// This is a refactoring specific version of \see ClangTool. FrontendActions
119249423Sdim/// passed to run() and runAndSave() should add replacements to
120249423Sdim/// getReplacements().
121249423Sdimclass RefactoringTool : public ClangTool {
122239313Sdimpublic:
123239313Sdim  /// \see ClangTool::ClangTool.
124239313Sdim  RefactoringTool(const CompilationDatabase &Compilations,
125239313Sdim                  ArrayRef<std::string> SourcePaths);
126239313Sdim
127249423Sdim  /// \brief Returns the set of replacements to which replacements should
128249423Sdim  /// be added during the run of the tool.
129239313Sdim  Replacements &getReplacements();
130239313Sdim
131249423Sdim  /// \brief Call run(), apply all generated replacements, and immediately save
132249423Sdim  /// the results to disk.
133249423Sdim  ///
134249423Sdim  /// \returns 0 upon success. Non-zero upon failure.
135249423Sdim  int runAndSave(FrontendActionFactory *ActionFactory);
136239313Sdim
137249423Sdim  /// \brief Apply all stored replacements to the given Rewriter.
138249423Sdim  ///
139249423Sdim  /// Replacement applications happen independently of the success of other
140249423Sdim  /// applications.
141249423Sdim  ///
142249423Sdim  /// \returns true if all replacements apply. false otherwise.
143249423Sdim  bool applyAllReplacements(Rewriter &Rewrite);
144249423Sdim
145239313Sdimprivate:
146249423Sdim  /// \brief Write all refactored files to disk.
147249423Sdim  int saveRewrittenFiles(Rewriter &Rewrite);
148249423Sdim
149249423Sdimprivate:
150239313Sdim  Replacements Replace;
151239313Sdim};
152239313Sdim
153239313Sdimtemplate <typename Node>
154239313SdimReplacement::Replacement(SourceManager &Sources, const Node &NodeToReplace,
155249423Sdim                         StringRef ReplacementText) {
156239313Sdim  const CharSourceRange Range =
157239313Sdim      CharSourceRange::getTokenRange(NodeToReplace->getSourceRange());
158239313Sdim  setFromSourceRange(Sources, Range, ReplacementText);
159239313Sdim}
160239313Sdim
161239313Sdim} // end namespace tooling
162239313Sdim} // end namespace clang
163239313Sdim
164239313Sdim#endif // end namespace LLVM_CLANG_TOOLING_REFACTORING_H
165