1//===--- Rewriter.h - Code rewriting interface ------------------*- 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//  This file defines the Rewriter class, which is used for code
11//  transformations.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_CLANG_REWRITER_H
16#define LLVM_CLANG_REWRITER_H
17
18#include "clang/Basic/SourceLocation.h"
19#include "clang/Rewrite/Core/DeltaTree.h"
20#include "clang/Rewrite/Core/RewriteRope.h"
21#include "llvm/ADT/StringRef.h"
22#include <cstring>
23#include <map>
24#include <string>
25
26namespace clang {
27  class LangOptions;
28  class Rewriter;
29  class SourceManager;
30  class Stmt;
31
32/// RewriteBuffer - As code is rewritten, SourceBuffer's from the original
33/// input with modifications get a new RewriteBuffer associated with them.  The
34/// RewriteBuffer captures the modified text itself as well as information used
35/// to map between SourceLocation's in the original input and offsets in the
36/// RewriteBuffer.  For example, if text is inserted into the buffer, any
37/// locations after the insertion point have to be mapped.
38class RewriteBuffer {
39  friend class Rewriter;
40  /// Deltas - Keep track of all the deltas in the source code due to insertions
41  /// and deletions.
42  DeltaTree Deltas;
43  RewriteRope Buffer;
44public:
45  typedef RewriteRope::const_iterator iterator;
46  iterator begin() const { return Buffer.begin(); }
47  iterator end() const { return Buffer.end(); }
48  unsigned size() const { return Buffer.size(); }
49
50  /// \brief Write to \p Stream the result of applying all changes to the
51  /// original buffer.
52  /// Note that it isn't safe to use this function to overwrite memory mapped
53  /// files in-place (PR17960). Consider using a higher-level utility such as
54  /// Rewriter::overwriteChangedFiles() instead.
55  ///
56  /// The original buffer is not actually changed.
57  raw_ostream &write(raw_ostream &Stream) const;
58
59  /// RemoveText - Remove the specified text.
60  void RemoveText(unsigned OrigOffset, unsigned Size,
61                  bool removeLineIfEmpty = false);
62
63  /// InsertText - Insert some text at the specified point, where the offset in
64  /// the buffer is specified relative to the original SourceBuffer.  The
65  /// text is inserted after the specified location.
66  ///
67  void InsertText(unsigned OrigOffset, StringRef Str,
68                  bool InsertAfter = true);
69
70
71  /// InsertTextBefore - Insert some text before the specified point, where the
72  /// offset in the buffer is specified relative to the original
73  /// SourceBuffer. The text is inserted before the specified location.  This is
74  /// method is the same as InsertText with "InsertAfter == false".
75  void InsertTextBefore(unsigned OrigOffset, StringRef Str) {
76    InsertText(OrigOffset, Str, false);
77  }
78
79  /// InsertTextAfter - Insert some text at the specified point, where the
80  /// offset in the buffer is specified relative to the original SourceBuffer.
81  /// The text is inserted after the specified location.
82  void InsertTextAfter(unsigned OrigOffset, StringRef Str) {
83    InsertText(OrigOffset, Str);
84  }
85
86  /// ReplaceText - This method replaces a range of characters in the input
87  /// buffer with a new string.  This is effectively a combined "remove/insert"
88  /// operation.
89  void ReplaceText(unsigned OrigOffset, unsigned OrigLength,
90                   StringRef NewStr);
91
92private:  // Methods only usable by Rewriter.
93
94  /// Initialize - Start this rewrite buffer out with a copy of the unmodified
95  /// input buffer.
96  void Initialize(const char *BufStart, const char *BufEnd) {
97    Buffer.assign(BufStart, BufEnd);
98  }
99
100  /// getMappedOffset - Given an offset into the original SourceBuffer that this
101  /// RewriteBuffer is based on, map it into the offset space of the
102  /// RewriteBuffer.  If AfterInserts is true and if the OrigOffset indicates a
103  /// position where text is inserted, the location returned will be after any
104  /// inserted text at the position.
105  unsigned getMappedOffset(unsigned OrigOffset,
106                           bool AfterInserts = false) const{
107    return Deltas.getDeltaAt(2*OrigOffset+AfterInserts)+OrigOffset;
108  }
109
110  /// AddInsertDelta - When an insertion is made at a position, this
111  /// method is used to record that information.
112  void AddInsertDelta(unsigned OrigOffset, int Change) {
113    return Deltas.AddDelta(2*OrigOffset, Change);
114  }
115
116  /// AddReplaceDelta - When a replacement/deletion is made at a position, this
117  /// method is used to record that information.
118  void AddReplaceDelta(unsigned OrigOffset, int Change) {
119    return Deltas.AddDelta(2*OrigOffset+1, Change);
120  }
121};
122
123
124/// Rewriter - This is the main interface to the rewrite buffers.  Its primary
125/// job is to dispatch high-level requests to the low-level RewriteBuffers that
126/// are involved.
127class Rewriter {
128  SourceManager *SourceMgr;
129  const LangOptions *LangOpts;
130  std::map<FileID, RewriteBuffer> RewriteBuffers;
131public:
132  struct RewriteOptions {
133    /// \brief Given a source range, true to include previous inserts at the
134    /// beginning of the range as part of the range itself (true by default).
135    bool IncludeInsertsAtBeginOfRange;
136    /// \brief Given a source range, true to include previous inserts at the
137    /// end of the range as part of the range itself (true by default).
138    bool IncludeInsertsAtEndOfRange;
139    /// \brief If true and removing some text leaves a blank line
140    /// also remove the empty line (false by default).
141    bool RemoveLineIfEmpty;
142
143    RewriteOptions()
144      : IncludeInsertsAtBeginOfRange(true),
145        IncludeInsertsAtEndOfRange(true),
146        RemoveLineIfEmpty(false) { }
147  };
148
149  typedef std::map<FileID, RewriteBuffer>::iterator buffer_iterator;
150  typedef std::map<FileID, RewriteBuffer>::const_iterator const_buffer_iterator;
151
152  explicit Rewriter(SourceManager &SM, const LangOptions &LO)
153    : SourceMgr(&SM), LangOpts(&LO) {}
154  explicit Rewriter() : SourceMgr(nullptr), LangOpts(nullptr) {}
155
156  void setSourceMgr(SourceManager &SM, const LangOptions &LO) {
157    SourceMgr = &SM;
158    LangOpts = &LO;
159  }
160  SourceManager &getSourceMgr() const { return *SourceMgr; }
161  const LangOptions &getLangOpts() const { return *LangOpts; }
162
163  /// isRewritable - Return true if this location is a raw file location, which
164  /// is rewritable.  Locations from macros, etc are not rewritable.
165  static bool isRewritable(SourceLocation Loc) {
166    return Loc.isFileID();
167  }
168
169  /// getRangeSize - Return the size in bytes of the specified range if they
170  /// are in the same file.  If not, this returns -1.
171  int getRangeSize(SourceRange Range,
172                   RewriteOptions opts = RewriteOptions()) const;
173  int getRangeSize(const CharSourceRange &Range,
174                   RewriteOptions opts = RewriteOptions()) const;
175
176  /// getRewrittenText - Return the rewritten form of the text in the specified
177  /// range.  If the start or end of the range was unrewritable or if they are
178  /// in different buffers, this returns an empty string.
179  ///
180  /// Note that this method is not particularly efficient.
181  ///
182  std::string getRewrittenText(SourceRange Range) const;
183
184  /// InsertText - Insert the specified string at the specified location in the
185  /// original buffer.  This method returns true (and does nothing) if the input
186  /// location was not rewritable, false otherwise.
187  ///
188  /// \param indentNewLines if true new lines in the string are indented
189  /// using the indentation of the source line in position \p Loc.
190  bool InsertText(SourceLocation Loc, StringRef Str,
191                  bool InsertAfter = true, bool indentNewLines = false);
192
193  /// InsertTextAfter - Insert the specified string at the specified location in
194  ///  the original buffer.  This method returns true (and does nothing) if
195  ///  the input location was not rewritable, false otherwise.  Text is
196  ///  inserted after any other text that has been previously inserted
197  ///  at the some point (the default behavior for InsertText).
198  bool InsertTextAfter(SourceLocation Loc, StringRef Str) {
199    return InsertText(Loc, Str);
200  }
201
202  /// \brief Insert the specified string after the token in the
203  /// specified location.
204  bool InsertTextAfterToken(SourceLocation Loc, StringRef Str);
205
206  /// InsertText - Insert the specified string at the specified location in the
207  /// original buffer.  This method returns true (and does nothing) if the input
208  /// location was not rewritable, false otherwise.  Text is
209  /// inserted before any other text that has been previously inserted
210  /// at the some point.
211  bool InsertTextBefore(SourceLocation Loc, StringRef Str) {
212    return InsertText(Loc, Str, false);
213  }
214
215  /// RemoveText - Remove the specified text region.
216  bool RemoveText(SourceLocation Start, unsigned Length,
217                  RewriteOptions opts = RewriteOptions());
218
219  /// \brief Remove the specified text region.
220  bool RemoveText(CharSourceRange range,
221                  RewriteOptions opts = RewriteOptions()) {
222    return RemoveText(range.getBegin(), getRangeSize(range, opts), opts);
223  }
224
225  /// \brief Remove the specified text region.
226  bool RemoveText(SourceRange range, RewriteOptions opts = RewriteOptions()) {
227    return RemoveText(range.getBegin(), getRangeSize(range, opts), opts);
228  }
229
230  /// ReplaceText - This method replaces a range of characters in the input
231  /// buffer with a new string.  This is effectively a combined "remove/insert"
232  /// operation.
233  bool ReplaceText(SourceLocation Start, unsigned OrigLength,
234                   StringRef NewStr);
235
236  /// ReplaceText - This method replaces a range of characters in the input
237  /// buffer with a new string.  This is effectively a combined "remove/insert"
238  /// operation.
239  bool ReplaceText(SourceRange range, StringRef NewStr) {
240    return ReplaceText(range.getBegin(), getRangeSize(range), NewStr);
241  }
242
243  /// ReplaceText - This method replaces a range of characters in the input
244  /// buffer with a new string.  This is effectively a combined "remove/insert"
245  /// operation.
246  bool ReplaceText(SourceRange range, SourceRange replacementRange);
247
248  /// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty
249  /// printer to generate the replacement code.  This returns true if the input
250  /// could not be rewritten, or false if successful.
251  bool ReplaceStmt(Stmt *From, Stmt *To);
252
253  /// \brief Increase indentation for the lines between the given source range.
254  /// To determine what the indentation should be, 'parentIndent' is used
255  /// that should be at a source location with an indentation one degree
256  /// lower than the given range.
257  bool IncreaseIndentation(CharSourceRange range, SourceLocation parentIndent);
258  bool IncreaseIndentation(SourceRange range, SourceLocation parentIndent) {
259    return IncreaseIndentation(CharSourceRange::getTokenRange(range),
260                               parentIndent);
261  }
262
263  /// ConvertToString converts statement 'From' to a string using the
264  /// pretty printer.
265  std::string ConvertToString(Stmt *From);
266
267  /// getEditBuffer - This is like getRewriteBufferFor, but always returns a
268  /// buffer, and allows you to write on it directly.  This is useful if you
269  /// want efficient low-level access to apis for scribbling on one specific
270  /// FileID's buffer.
271  RewriteBuffer &getEditBuffer(FileID FID);
272
273  /// getRewriteBufferFor - Return the rewrite buffer for the specified FileID.
274  /// If no modification has been made to it, return null.
275  const RewriteBuffer *getRewriteBufferFor(FileID FID) const {
276    std::map<FileID, RewriteBuffer>::const_iterator I =
277      RewriteBuffers.find(FID);
278    return I == RewriteBuffers.end() ? nullptr : &I->second;
279  }
280
281  // Iterators over rewrite buffers.
282  buffer_iterator buffer_begin() { return RewriteBuffers.begin(); }
283  buffer_iterator buffer_end() { return RewriteBuffers.end(); }
284  const_buffer_iterator buffer_begin() const { return RewriteBuffers.begin(); }
285  const_buffer_iterator buffer_end() const { return RewriteBuffers.end(); }
286
287  /// overwriteChangedFiles - Save all changed files to disk.
288  ///
289  /// Returns true if any files were not saved successfully.
290  /// Outputs diagnostics via the source manager's diagnostic engine
291  /// in case of an error.
292  bool overwriteChangedFiles();
293
294private:
295  unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) const;
296};
297
298} // end namespace clang
299
300#endif
301