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