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