Home | History | Annotate | Download | only in Core
      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;
     51   iterator begin() const { return Buffer.begin(); }
     52   iterator end() const { return Buffer.end(); }
     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".
     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.
     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.
     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.
    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.
    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 
    145     RewriteOptions()
    146       : IncludeInsertsAtBeginOfRange(true),
    147         IncludeInsertsAtEndOfRange(true),
    148         RemoveLineIfEmpty(false) { }
    149   };
    150 
    151   typedef std::map<FileID, RewriteBuffer>::iterator buffer_iterator;
    152 
    153   explicit Rewriter(SourceManager &SM, const LangOptions &LO)
    154     : SourceMgr(&SM), LangOpts(&LO) {}
    155   explicit Rewriter() : SourceMgr(0), LangOpts(0) {}
    156 
    157   void setSourceMgr(SourceManager &SM, const LangOptions &LO) {
    158     SourceMgr = &SM;
    159     LangOpts = &LO;
    160   }
    161   SourceManager &getSourceMgr() const { return *SourceMgr; }
    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.
    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).
    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.
    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.
    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);
    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.
    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.
    283   buffer_iterator buffer_begin() { return RewriteBuffers.begin(); }
    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