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   RewriteRope Buffer;
     44 public:
     45   typedef RewriteRope::const_iterator iterator;
     46   iterator begin() const { return Buffer.begin(); }
     47   iterator end() const { return Buffer.end(); }
     48   unsigned size() const { return Buffer.size(); }
     49 
     50   /// \brief Write to \p Stream the result of applying all changes to the
     51   /// original buffer.
     52   /// Note that it isn't safe to use this function to overwrite memory mapped
     53   /// files in-place (PR17960). Consider using a higher-level utility such as
     54   /// Rewriter::overwriteChangedFiles() instead.
     55   ///
     56   /// The original buffer is not actually changed.
     57   raw_ostream &write(raw_ostream &Stream) 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, 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, 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, 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                    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   typedef std::map<FileID, RewriteBuffer>::const_iterator const_buffer_iterator;
    151 
    152   explicit Rewriter(SourceManager &SM, const LangOptions &LO)
    153     : SourceMgr(&SM), LangOpts(&LO) {}
    154   explicit Rewriter() : SourceMgr(nullptr), LangOpts(nullptr) {}
    155 
    156   void setSourceMgr(SourceManager &SM, const LangOptions &LO) {
    157     SourceMgr = &SM;
    158     LangOpts = &LO;
    159   }
    160   SourceManager &getSourceMgr() const { return *SourceMgr; }
    161   const LangOptions &getLangOpts() const { return *LangOpts; }
    162 
    163   /// isRewritable - Return true if this location is a raw file location, which
    164   /// is rewritable.  Locations from macros, etc are not rewritable.
    165   static bool isRewritable(SourceLocation Loc) {
    166     return Loc.isFileID();
    167   }
    168 
    169   /// getRangeSize - Return the size in bytes of the specified range if they
    170   /// are in the same file.  If not, this returns -1.
    171   int getRangeSize(SourceRange Range,
    172                    RewriteOptions opts = RewriteOptions()) const;
    173   int getRangeSize(const CharSourceRange &Range,
    174                    RewriteOptions opts = RewriteOptions()) const;
    175 
    176   /// getRewrittenText - Return the rewritten form of the text in the specified
    177   /// range.  If the start or end of the range was unrewritable or if they are
    178   /// in different buffers, this returns an empty string.
    179   ///
    180   /// Note that this method is not particularly efficient.
    181   ///
    182   std::string getRewrittenText(SourceRange Range) const;
    183 
    184   /// InsertText - Insert the specified string at the specified location in the
    185   /// original buffer.  This method returns true (and does nothing) if the input
    186   /// location was not rewritable, false otherwise.
    187   ///
    188   /// \param indentNewLines if true new lines in the string are indented
    189   /// using the indentation of the source line in position \p Loc.
    190   bool InsertText(SourceLocation Loc, StringRef Str,
    191                   bool InsertAfter = true, bool indentNewLines = false);
    192 
    193   /// InsertTextAfter - Insert the specified string at the specified location in
    194   ///  the original buffer.  This method returns true (and does nothing) if
    195   ///  the input location was not rewritable, false otherwise.  Text is
    196   ///  inserted after any other text that has been previously inserted
    197   ///  at the some point (the default behavior for InsertText).
    198   bool InsertTextAfter(SourceLocation Loc, StringRef Str) {
    199     return InsertText(Loc, Str);
    200   }
    201 
    202   /// \brief Insert the specified string after the token in the
    203   /// specified location.
    204   bool InsertTextAfterToken(SourceLocation Loc, StringRef Str);
    205 
    206   /// InsertText - Insert the specified string at the specified location in the
    207   /// original buffer.  This method returns true (and does nothing) if the input
    208   /// location was not rewritable, false otherwise.  Text is
    209   /// inserted before any other text that has been previously inserted
    210   /// at the some point.
    211   bool InsertTextBefore(SourceLocation Loc, StringRef Str) {
    212     return InsertText(Loc, Str, false);
    213   }
    214 
    215   /// RemoveText - Remove the specified text region.
    216   bool RemoveText(SourceLocation Start, unsigned Length,
    217                   RewriteOptions opts = RewriteOptions());
    218 
    219   /// \brief Remove the specified text region.
    220   bool RemoveText(CharSourceRange range,
    221                   RewriteOptions opts = RewriteOptions()) {
    222     return RemoveText(range.getBegin(), getRangeSize(range, opts), opts);
    223   }
    224 
    225   /// \brief Remove the specified text region.
    226   bool RemoveText(SourceRange range, RewriteOptions opts = RewriteOptions()) {
    227     return RemoveText(range.getBegin(), getRangeSize(range, opts), opts);
    228   }
    229 
    230   /// ReplaceText - This method replaces a range of characters in the input
    231   /// buffer with a new string.  This is effectively a combined "remove/insert"
    232   /// operation.
    233   bool ReplaceText(SourceLocation Start, unsigned OrigLength,
    234                    StringRef NewStr);
    235 
    236   /// ReplaceText - This method replaces a range of characters in the input
    237   /// buffer with a new string.  This is effectively a combined "remove/insert"
    238   /// operation.
    239   bool ReplaceText(SourceRange range, StringRef NewStr) {
    240     return ReplaceText(range.getBegin(), getRangeSize(range), NewStr);
    241   }
    242 
    243   /// ReplaceText - This method replaces a range of characters in the input
    244   /// buffer with a new string.  This is effectively a combined "remove/insert"
    245   /// operation.
    246   bool ReplaceText(SourceRange range, SourceRange replacementRange);
    247 
    248   /// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty
    249   /// printer to generate the replacement code.  This returns true if the input
    250   /// could not be rewritten, or false if successful.
    251   bool ReplaceStmt(Stmt *From, Stmt *To);
    252 
    253   /// \brief Increase indentation for the lines between the given source range.
    254   /// To determine what the indentation should be, 'parentIndent' is used
    255   /// that should be at a source location with an indentation one degree
    256   /// lower than the given range.
    257   bool IncreaseIndentation(CharSourceRange range, SourceLocation parentIndent);
    258   bool IncreaseIndentation(SourceRange range, SourceLocation parentIndent) {
    259     return IncreaseIndentation(CharSourceRange::getTokenRange(range),
    260                                parentIndent);
    261   }
    262 
    263   /// ConvertToString converts statement 'From' to a string using the
    264   /// pretty printer.
    265   std::string ConvertToString(Stmt *From);
    266 
    267   /// getEditBuffer - This is like getRewriteBufferFor, but always returns a
    268   /// buffer, and allows you to write on it directly.  This is useful if you
    269   /// want efficient low-level access to apis for scribbling on one specific
    270   /// FileID's buffer.
    271   RewriteBuffer &getEditBuffer(FileID FID);
    272 
    273   /// getRewriteBufferFor - Return the rewrite buffer for the specified FileID.
    274   /// If no modification has been made to it, return null.
    275   const RewriteBuffer *getRewriteBufferFor(FileID FID) const {
    276     std::map<FileID, RewriteBuffer>::const_iterator I =
    277       RewriteBuffers.find(FID);
    278     return I == RewriteBuffers.end() ? nullptr : &I->second;
    279   }
    280 
    281   // Iterators over rewrite buffers.
    282   buffer_iterator buffer_begin() { return RewriteBuffers.begin(); }
    283   buffer_iterator buffer_end() { return RewriteBuffers.end(); }
    284   const_buffer_iterator buffer_begin() const { return RewriteBuffers.begin(); }
    285   const_buffer_iterator buffer_end() const { return RewriteBuffers.end(); }
    286 
    287   /// overwriteChangedFiles - Save all changed files to disk.
    288   ///
    289   /// Returns true if any files were not saved successfully.
    290   /// Outputs diagnostics via the source manager's diagnostic engine
    291   /// in case of an error.
    292   bool overwriteChangedFiles();
    293 
    294 private:
    295   unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) const;
    296 };
    297 
    298 } // end namespace clang
    299 
    300 #endif
    301