1243791Sdim//===--- Rewriter.h - Code rewriting interface ------------------*- C++ -*-===//
2243791Sdim//
3243791Sdim//                     The LLVM Compiler Infrastructure
4243791Sdim//
5243791Sdim// This file is distributed under the University of Illinois Open Source
6243791Sdim// License. See LICENSE.TXT for details.
7243791Sdim//
8243791Sdim//===----------------------------------------------------------------------===//
9243791Sdim//
10243791Sdim//  This file defines the Rewriter class, which is used for code
11243791Sdim//  transformations.
12243791Sdim//
13243791Sdim//===----------------------------------------------------------------------===//
14243791Sdim
15243791Sdim#ifndef LLVM_CLANG_REWRITER_H
16243791Sdim#define LLVM_CLANG_REWRITER_H
17243791Sdim
18243791Sdim#include "clang/Basic/SourceLocation.h"
19243791Sdim#include "clang/Rewrite/Core/DeltaTree.h"
20243791Sdim#include "clang/Rewrite/Core/RewriteRope.h"
21243791Sdim#include "llvm/ADT/StringRef.h"
22243791Sdim#include <cstring>
23243791Sdim#include <map>
24243791Sdim#include <string>
25243791Sdim
26243791Sdimnamespace clang {
27243791Sdim  class LangOptions;
28243791Sdim  class Rewriter;
29243791Sdim  class SourceManager;
30243791Sdim  class Stmt;
31243791Sdim
32243791Sdim/// RewriteBuffer - As code is rewritten, SourceBuffer's from the original
33243791Sdim/// input with modifications get a new RewriteBuffer associated with them.  The
34243791Sdim/// RewriteBuffer captures the modified text itself as well as information used
35243791Sdim/// to map between SourceLocation's in the original input and offsets in the
36243791Sdim/// RewriteBuffer.  For example, if text is inserted into the buffer, any
37243791Sdim/// locations after the insertion point have to be mapped.
38243791Sdimclass RewriteBuffer {
39243791Sdim  friend class Rewriter;
40243791Sdim  /// Deltas - Keep track of all the deltas in the source code due to insertions
41243791Sdim  /// and deletions.
42243791Sdim  DeltaTree Deltas;
43243791Sdim
44243791Sdim  /// Buffer - This is the actual buffer itself.  Note that using a vector or
45243791Sdim  /// string is a horribly inefficient way to do this, we should use a rope
46243791Sdim  /// instead.
47243791Sdim  typedef RewriteRope BufferTy;
48243791Sdim  BufferTy Buffer;
49243791Sdimpublic:
50243791Sdim  typedef BufferTy::const_iterator iterator;
51243791Sdim  iterator begin() const { return Buffer.begin(); }
52243791Sdim  iterator end() const { return Buffer.end(); }
53243791Sdim  unsigned size() const { return Buffer.size(); }
54243791Sdim
55249423Sdim  /// \brief Write to \p Stream the result of applying all changes to the
56249423Sdim  /// original buffer.
57249423Sdim  ///
58249423Sdim  /// The original buffer is not actually changed.
59249423Sdim  raw_ostream &write(raw_ostream &Stream) const;
60243791Sdim
61243791Sdim  /// RemoveText - Remove the specified text.
62243791Sdim  void RemoveText(unsigned OrigOffset, unsigned Size,
63243791Sdim                  bool removeLineIfEmpty = false);
64243791Sdim
65243791Sdim  /// InsertText - Insert some text at the specified point, where the offset in
66243791Sdim  /// the buffer is specified relative to the original SourceBuffer.  The
67243791Sdim  /// text is inserted after the specified location.
68243791Sdim  ///
69243791Sdim  void InsertText(unsigned OrigOffset, StringRef Str,
70243791Sdim                  bool InsertAfter = true);
71243791Sdim
72243791Sdim
73243791Sdim  /// InsertTextBefore - Insert some text before the specified point, where the
74243791Sdim  /// offset in the buffer is specified relative to the original
75243791Sdim  /// SourceBuffer. The text is inserted before the specified location.  This is
76243791Sdim  /// method is the same as InsertText with "InsertAfter == false".
77243791Sdim  void InsertTextBefore(unsigned OrigOffset, StringRef Str) {
78243791Sdim    InsertText(OrigOffset, Str, false);
79243791Sdim  }
80243791Sdim
81243791Sdim  /// InsertTextAfter - Insert some text at the specified point, where the
82243791Sdim  /// offset in the buffer is specified relative to the original SourceBuffer.
83243791Sdim  /// The text is inserted after the specified location.
84243791Sdim  void InsertTextAfter(unsigned OrigOffset, StringRef Str) {
85243791Sdim    InsertText(OrigOffset, Str);
86243791Sdim  }
87243791Sdim
88243791Sdim  /// ReplaceText - This method replaces a range of characters in the input
89243791Sdim  /// buffer with a new string.  This is effectively a combined "remove/insert"
90243791Sdim  /// operation.
91243791Sdim  void ReplaceText(unsigned OrigOffset, unsigned OrigLength,
92243791Sdim                   StringRef NewStr);
93243791Sdim
94243791Sdimprivate:  // Methods only usable by Rewriter.
95243791Sdim
96243791Sdim  /// Initialize - Start this rewrite buffer out with a copy of the unmodified
97243791Sdim  /// input buffer.
98243791Sdim  void Initialize(const char *BufStart, const char *BufEnd) {
99243791Sdim    Buffer.assign(BufStart, BufEnd);
100243791Sdim  }
101243791Sdim
102243791Sdim  /// getMappedOffset - Given an offset into the original SourceBuffer that this
103243791Sdim  /// RewriteBuffer is based on, map it into the offset space of the
104243791Sdim  /// RewriteBuffer.  If AfterInserts is true and if the OrigOffset indicates a
105243791Sdim  /// position where text is inserted, the location returned will be after any
106243791Sdim  /// inserted text at the position.
107243791Sdim  unsigned getMappedOffset(unsigned OrigOffset,
108243791Sdim                           bool AfterInserts = false) const{
109243791Sdim    return Deltas.getDeltaAt(2*OrigOffset+AfterInserts)+OrigOffset;
110243791Sdim  }
111243791Sdim
112243791Sdim  /// AddInsertDelta - When an insertion is made at a position, this
113243791Sdim  /// method is used to record that information.
114243791Sdim  void AddInsertDelta(unsigned OrigOffset, int Change) {
115243791Sdim    return Deltas.AddDelta(2*OrigOffset, Change);
116243791Sdim  }
117243791Sdim
118243791Sdim  /// AddReplaceDelta - When a replacement/deletion is made at a position, this
119243791Sdim  /// method is used to record that information.
120243791Sdim  void AddReplaceDelta(unsigned OrigOffset, int Change) {
121243791Sdim    return Deltas.AddDelta(2*OrigOffset+1, Change);
122243791Sdim  }
123243791Sdim};
124243791Sdim
125243791Sdim
126243791Sdim/// Rewriter - This is the main interface to the rewrite buffers.  Its primary
127243791Sdim/// job is to dispatch high-level requests to the low-level RewriteBuffers that
128243791Sdim/// are involved.
129243791Sdimclass Rewriter {
130243791Sdim  SourceManager *SourceMgr;
131243791Sdim  const LangOptions *LangOpts;
132243791Sdim  std::map<FileID, RewriteBuffer> RewriteBuffers;
133243791Sdimpublic:
134243791Sdim  struct RewriteOptions {
135243791Sdim    /// \brief Given a source range, true to include previous inserts at the
136243791Sdim    /// beginning of the range as part of the range itself (true by default).
137243791Sdim    bool IncludeInsertsAtBeginOfRange;
138243791Sdim    /// \brief Given a source range, true to include previous inserts at the
139243791Sdim    /// end of the range as part of the range itself (true by default).
140243791Sdim    bool IncludeInsertsAtEndOfRange;
141243791Sdim    /// \brief If true and removing some text leaves a blank line
142243791Sdim    /// also remove the empty line (false by default).
143243791Sdim    bool RemoveLineIfEmpty;
144243791Sdim
145243791Sdim    RewriteOptions()
146243791Sdim      : IncludeInsertsAtBeginOfRange(true),
147243791Sdim        IncludeInsertsAtEndOfRange(true),
148243791Sdim        RemoveLineIfEmpty(false) { }
149243791Sdim  };
150243791Sdim
151243791Sdim  typedef std::map<FileID, RewriteBuffer>::iterator buffer_iterator;
152243791Sdim
153243791Sdim  explicit Rewriter(SourceManager &SM, const LangOptions &LO)
154243791Sdim    : SourceMgr(&SM), LangOpts(&LO) {}
155243791Sdim  explicit Rewriter() : SourceMgr(0), LangOpts(0) {}
156243791Sdim
157243791Sdim  void setSourceMgr(SourceManager &SM, const LangOptions &LO) {
158243791Sdim    SourceMgr = &SM;
159243791Sdim    LangOpts = &LO;
160243791Sdim  }
161243791Sdim  SourceManager &getSourceMgr() const { return *SourceMgr; }
162243791Sdim  const LangOptions &getLangOpts() const { return *LangOpts; }
163243791Sdim
164243791Sdim  /// isRewritable - Return true if this location is a raw file location, which
165243791Sdim  /// is rewritable.  Locations from macros, etc are not rewritable.
166243791Sdim  static bool isRewritable(SourceLocation Loc) {
167243791Sdim    return Loc.isFileID();
168243791Sdim  }
169243791Sdim
170243791Sdim  /// getRangeSize - Return the size in bytes of the specified range if they
171243791Sdim  /// are in the same file.  If not, this returns -1.
172243791Sdim  int getRangeSize(SourceRange Range,
173243791Sdim                   RewriteOptions opts = RewriteOptions()) const;
174243791Sdim  int getRangeSize(const CharSourceRange &Range,
175243791Sdim                   RewriteOptions opts = RewriteOptions()) const;
176243791Sdim
177243791Sdim  /// getRewrittenText - Return the rewritten form of the text in the specified
178243791Sdim  /// range.  If the start or end of the range was unrewritable or if they are
179243791Sdim  /// in different buffers, this returns an empty string.
180243791Sdim  ///
181243791Sdim  /// Note that this method is not particularly efficient.
182243791Sdim  ///
183243791Sdim  std::string getRewrittenText(SourceRange Range) const;
184243791Sdim
185243791Sdim  /// InsertText - Insert the specified string at the specified location in the
186243791Sdim  /// original buffer.  This method returns true (and does nothing) if the input
187243791Sdim  /// location was not rewritable, false otherwise.
188243791Sdim  ///
189243791Sdim  /// \param indentNewLines if true new lines in the string are indented
190243791Sdim  /// using the indentation of the source line in position \p Loc.
191243791Sdim  bool InsertText(SourceLocation Loc, StringRef Str,
192243791Sdim                  bool InsertAfter = true, bool indentNewLines = false);
193243791Sdim
194243791Sdim  /// InsertTextAfter - Insert the specified string at the specified location in
195243791Sdim  ///  the original buffer.  This method returns true (and does nothing) if
196243791Sdim  ///  the input location was not rewritable, false otherwise.  Text is
197243791Sdim  ///  inserted after any other text that has been previously inserted
198243791Sdim  ///  at the some point (the default behavior for InsertText).
199243791Sdim  bool InsertTextAfter(SourceLocation Loc, StringRef Str) {
200243791Sdim    return InsertText(Loc, Str);
201243791Sdim  }
202243791Sdim
203243791Sdim  /// \brief Insert the specified string after the token in the
204243791Sdim  /// specified location.
205243791Sdim  bool InsertTextAfterToken(SourceLocation Loc, StringRef Str);
206243791Sdim
207243791Sdim  /// InsertText - Insert the specified string at the specified location in the
208243791Sdim  /// original buffer.  This method returns true (and does nothing) if the input
209243791Sdim  /// location was not rewritable, false otherwise.  Text is
210243791Sdim  /// inserted before any other text that has been previously inserted
211243791Sdim  /// at the some point.
212243791Sdim  bool InsertTextBefore(SourceLocation Loc, StringRef Str) {
213243791Sdim    return InsertText(Loc, Str, false);
214243791Sdim  }
215243791Sdim
216243791Sdim  /// RemoveText - Remove the specified text region.
217243791Sdim  bool RemoveText(SourceLocation Start, unsigned Length,
218243791Sdim                  RewriteOptions opts = RewriteOptions());
219243791Sdim
220243791Sdim  /// \brief Remove the specified text region.
221243791Sdim  bool RemoveText(CharSourceRange range,
222243791Sdim                  RewriteOptions opts = RewriteOptions()) {
223243791Sdim    return RemoveText(range.getBegin(), getRangeSize(range, opts), opts);
224243791Sdim  }
225243791Sdim
226243791Sdim  /// \brief Remove the specified text region.
227243791Sdim  bool RemoveText(SourceRange range, RewriteOptions opts = RewriteOptions()) {
228243791Sdim    return RemoveText(range.getBegin(), getRangeSize(range, opts), opts);
229243791Sdim  }
230243791Sdim
231243791Sdim  /// ReplaceText - This method replaces a range of characters in the input
232243791Sdim  /// buffer with a new string.  This is effectively a combined "remove/insert"
233243791Sdim  /// operation.
234243791Sdim  bool ReplaceText(SourceLocation Start, unsigned OrigLength,
235243791Sdim                   StringRef NewStr);
236243791Sdim
237243791Sdim  /// ReplaceText - This method replaces a range of characters in the input
238243791Sdim  /// buffer with a new string.  This is effectively a combined "remove/insert"
239243791Sdim  /// operation.
240243791Sdim  bool ReplaceText(SourceRange range, StringRef NewStr) {
241243791Sdim    return ReplaceText(range.getBegin(), getRangeSize(range), NewStr);
242243791Sdim  }
243243791Sdim
244243791Sdim  /// ReplaceText - This method replaces a range of characters in the input
245243791Sdim  /// buffer with a new string.  This is effectively a combined "remove/insert"
246243791Sdim  /// operation.
247243791Sdim  bool ReplaceText(SourceRange range, SourceRange replacementRange);
248243791Sdim
249243791Sdim  /// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty
250243791Sdim  /// printer to generate the replacement code.  This returns true if the input
251243791Sdim  /// could not be rewritten, or false if successful.
252243791Sdim  bool ReplaceStmt(Stmt *From, Stmt *To);
253243791Sdim
254243791Sdim  /// \brief Increase indentation for the lines between the given source range.
255243791Sdim  /// To determine what the indentation should be, 'parentIndent' is used
256243791Sdim  /// that should be at a source location with an indentation one degree
257243791Sdim  /// lower than the given range.
258243791Sdim  bool IncreaseIndentation(CharSourceRange range, SourceLocation parentIndent);
259243791Sdim  bool IncreaseIndentation(SourceRange range, SourceLocation parentIndent) {
260243791Sdim    return IncreaseIndentation(CharSourceRange::getTokenRange(range),
261243791Sdim                               parentIndent);
262243791Sdim  }
263243791Sdim
264243791Sdim  /// ConvertToString converts statement 'From' to a string using the
265243791Sdim  /// pretty printer.
266243791Sdim  std::string ConvertToString(Stmt *From);
267243791Sdim
268243791Sdim  /// getEditBuffer - This is like getRewriteBufferFor, but always returns a
269243791Sdim  /// buffer, and allows you to write on it directly.  This is useful if you
270243791Sdim  /// want efficient low-level access to apis for scribbling on one specific
271243791Sdim  /// FileID's buffer.
272243791Sdim  RewriteBuffer &getEditBuffer(FileID FID);
273243791Sdim
274243791Sdim  /// getRewriteBufferFor - Return the rewrite buffer for the specified FileID.
275243791Sdim  /// If no modification has been made to it, return null.
276243791Sdim  const RewriteBuffer *getRewriteBufferFor(FileID FID) const {
277243791Sdim    std::map<FileID, RewriteBuffer>::const_iterator I =
278243791Sdim      RewriteBuffers.find(FID);
279243791Sdim    return I == RewriteBuffers.end() ? 0 : &I->second;
280243791Sdim  }
281243791Sdim
282243791Sdim  // Iterators over rewrite buffers.
283243791Sdim  buffer_iterator buffer_begin() { return RewriteBuffers.begin(); }
284243791Sdim  buffer_iterator buffer_end() { return RewriteBuffers.end(); }
285243791Sdim
286249423Sdim  /// overwriteChangedFiles - Save all changed files to disk.
287243791Sdim  ///
288243791Sdim  /// Returns whether not all changes were saved successfully.
289243791Sdim  /// Outputs diagnostics via the source manager's diagnostic engine
290243791Sdim  /// in case of an error.
291243791Sdim  bool overwriteChangedFiles();
292243791Sdim
293243791Sdimprivate:
294243791Sdim  unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) const;
295243791Sdim};
296243791Sdim
297243791Sdim} // end namespace clang
298243791Sdim
299243791Sdim#endif
300