Home | History | Annotate | Download | only in Rewrite
      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/DeltaTree.h"
     20 #include "clang/Rewrite/RewriteRope.h"
     21 #include "llvm/ADT/StringRef.h"
     22 #include <cstring>
     23 #include <map>
     24 #include <string>
     25 
     26 namespace llvm { class raw_ostream; }
     27 
     28 namespace clang {
     29   class LangOptions;
     30   class Rewriter;
     31   class SourceManager;
     32   class Stmt;
     33 
     34 /// RewriteBuffer - As code is rewritten, SourceBuffer's from the original
     35 /// input with modifications get a new RewriteBuffer associated with them.  The
     36 /// RewriteBuffer captures the modified text itself as well as information used
     37 /// to map between SourceLocation's in the original input and offsets in the
     38 /// RewriteBuffer.  For example, if text is inserted into the buffer, any
     39 /// locations after the insertion point have to be mapped.
     40 class RewriteBuffer {
     41   friend class Rewriter;
     42   /// Deltas - Keep track of all the deltas in the source code due to insertions
     43   /// and deletions.
     44   DeltaTree Deltas;
     45 
     46   /// Buffer - This is the actual buffer itself.  Note that using a vector or
     47   /// string is a horribly inefficient way to do this, we should use a rope
     48   /// instead.
     49   typedef RewriteRope BufferTy;
     50   BufferTy Buffer;
     51 public:
     52   typedef BufferTy::const_iterator iterator;
     53   iterator begin() const { return Buffer.begin(); }
     54   iterator end() const { return Buffer.end(); }
     55   unsigned size() const { return Buffer.size(); }
     56 
     57   llvm::raw_ostream &write(llvm::raw_ostream &) 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, llvm::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, llvm::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, llvm::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                    llvm::StringRef NewStr);
     91 
     92 private:  // 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.
    127 class Rewriter {
    128   SourceManager *SourceMgr;
    129   const LangOptions *LangOpts;
    130   std::map<FileID, RewriteBuffer> RewriteBuffers;
    131 public:
    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 
    151   explicit Rewriter(SourceManager &SM, const LangOptions &LO)
    152     : SourceMgr(&SM), LangOpts(&LO) {}
    153   explicit Rewriter() : SourceMgr(0), LangOpts(0) {}
    154 
    155   void setSourceMgr(SourceManager &SM, const LangOptions &LO) {
    156     SourceMgr = &SM;
    157     LangOpts = &LO;
    158   }
    159   SourceManager &getSourceMgr() { return *SourceMgr; }
    160   const LangOptions &getLangOpts() { return *LangOpts; }
    161 
    162   /// isRewritable - Return true if this location is a raw file location, which
    163   /// is rewritable.  Locations from macros, etc are not rewritable.
    164   static bool isRewritable(SourceLocation Loc) {
    165     return Loc.isFileID();
    166   }
    167 
    168   /// getRangeSize - Return the size in bytes of the specified range if they
    169   /// are in the same file.  If not, this returns -1.
    170   int getRangeSize(SourceRange Range,
    171                    RewriteOptions opts = RewriteOptions()) const;
    172   int getRangeSize(const CharSourceRange &Range,
    173                    RewriteOptions opts = RewriteOptions()) const;
    174 
    175   /// getRewrittenText - Return the rewritten form of the text in the specified
    176   /// range.  If the start or end of the range was unrewritable or if they are
    177   /// in different buffers, this returns an empty string.
    178   ///
    179   /// Note that this method is not particularly efficient.
    180   ///
    181   std::string getRewrittenText(SourceRange Range) const;
    182 
    183   /// InsertText - Insert the specified string at the specified location in the
    184   /// original buffer.  This method returns true (and does nothing) if the input
    185   /// location was not rewritable, false otherwise.
    186   ///
    187   /// \param indentNewLines if true new lines in the string are indented
    188   /// using the indentation of the source line in position \arg Loc.
    189   bool InsertText(SourceLocation Loc, llvm::StringRef Str,
    190                   bool InsertAfter = true, bool indentNewLines = false);
    191 
    192   /// InsertTextAfter - Insert the specified string at the specified location in
    193   ///  the original buffer.  This method returns true (and does nothing) if
    194   ///  the input location was not rewritable, false otherwise.  Text is
    195   ///  inserted after any other text that has been previously inserted
    196   ///  at the some point (the default behavior for InsertText).
    197   bool InsertTextAfter(SourceLocation Loc, llvm::StringRef Str) {
    198     return InsertText(Loc, Str);
    199   }
    200 
    201   /// \brief Insert the specified string after the token in the
    202   /// specified location.
    203   bool InsertTextAfterToken(SourceLocation Loc, llvm::StringRef Str);
    204 
    205   /// InsertText - Insert the specified string at the specified location in the
    206   /// original buffer.  This method returns true (and does nothing) if the input
    207   /// location was not rewritable, false otherwise.  Text is
    208   /// inserted before any other text that has been previously inserted
    209   /// at the some point.
    210   bool InsertTextBefore(SourceLocation Loc, llvm::StringRef Str) {
    211     return InsertText(Loc, Str, false);
    212   }
    213 
    214   /// RemoveText - Remove the specified text region.
    215   bool RemoveText(SourceLocation Start, unsigned Length,
    216                   RewriteOptions opts = RewriteOptions());
    217 
    218   /// \brief Remove the specified text region.
    219   bool RemoveText(CharSourceRange range,
    220                   RewriteOptions opts = RewriteOptions()) {
    221     return RemoveText(range.getBegin(), getRangeSize(range, opts), opts);
    222   }
    223 
    224   /// \brief Remove the specified text region.
    225   bool RemoveText(SourceRange range, RewriteOptions opts = RewriteOptions()) {
    226     return RemoveText(range.getBegin(), getRangeSize(range, opts), opts);
    227   }
    228 
    229   /// ReplaceText - This method replaces a range of characters in the input
    230   /// buffer with a new string.  This is effectively a combined "remove/insert"
    231   /// operation.
    232   bool ReplaceText(SourceLocation Start, unsigned OrigLength,
    233                    llvm::StringRef NewStr);
    234 
    235   /// ReplaceText - This method replaces a range of characters in the input
    236   /// buffer with a new string.  This is effectively a combined "remove/insert"
    237   /// operation.
    238   bool ReplaceText(SourceRange range, llvm::StringRef NewStr) {
    239     return ReplaceText(range.getBegin(), getRangeSize(range), NewStr);
    240   }
    241 
    242   /// ReplaceText - This method replaces a range of characters in the input
    243   /// buffer with a new string.  This is effectively a combined "remove/insert"
    244   /// operation.
    245   bool ReplaceText(SourceRange range, SourceRange replacementRange);
    246 
    247   /// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty
    248   /// printer to generate the replacement code.  This returns true if the input
    249   /// could not be rewritten, or false if successful.
    250   bool ReplaceStmt(Stmt *From, Stmt *To);
    251 
    252   /// \brief Increase indentation for the lines between the given source range.
    253   /// To determine what the indentation should be, 'parentIndent' is used
    254   /// that should be at a source location with an indentation one degree
    255   /// lower than the given range.
    256   bool IncreaseIndentation(CharSourceRange range, SourceLocation parentIndent);
    257   bool IncreaseIndentation(SourceRange range, SourceLocation parentIndent) {
    258     return IncreaseIndentation(CharSourceRange::getTokenRange(range),
    259                                parentIndent);
    260   }
    261 
    262   /// ConvertToString converts statement 'From' to a string using the
    263   /// pretty printer.
    264   std::string ConvertToString(Stmt *From);
    265 
    266   /// getEditBuffer - This is like getRewriteBufferFor, but always returns a
    267   /// buffer, and allows you to write on it directly.  This is useful if you
    268   /// want efficient low-level access to apis for scribbling on one specific
    269   /// FileID's buffer.
    270   RewriteBuffer &getEditBuffer(FileID FID);
    271 
    272   /// getRewriteBufferFor - Return the rewrite buffer for the specified FileID.
    273   /// If no modification has been made to it, return null.
    274   const RewriteBuffer *getRewriteBufferFor(FileID FID) const {
    275     std::map<FileID, RewriteBuffer>::const_iterator I =
    276       RewriteBuffers.find(FID);
    277     return I == RewriteBuffers.end() ? 0 : &I->second;
    278   }
    279 
    280   // Iterators over rewrite buffers.
    281   buffer_iterator buffer_begin() { return RewriteBuffers.begin(); }
    282   buffer_iterator buffer_end() { return RewriteBuffers.end(); }
    283 
    284 private:
    285   unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) const;
    286 };
    287 
    288 } // end namespace clang
    289 
    290 #endif
    291