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_REWRITE_CORE_REWRITER_H
     16 #define LLVM_CLANG_REWRITE_CORE_REWRITER_H
     17 
     18 #include "clang/Basic/SourceLocation.h"
     19 #include "clang/Rewrite/Core/RewriteBuffer.h"
     20 #include <cstring>
     21 #include <map>
     22 #include <string>
     23 
     24 namespace clang {
     25   class LangOptions;
     26   class SourceManager;
     27 
     28 /// Rewriter - This is the main interface to the rewrite buffers.  Its primary
     29 /// job is to dispatch high-level requests to the low-level RewriteBuffers that
     30 /// are involved.
     31 class Rewriter {
     32   SourceManager *SourceMgr;
     33   const LangOptions *LangOpts;
     34   std::map<FileID, RewriteBuffer> RewriteBuffers;
     35 public:
     36   struct RewriteOptions {
     37     /// \brief Given a source range, true to include previous inserts at the
     38     /// beginning of the range as part of the range itself (true by default).
     39     bool IncludeInsertsAtBeginOfRange;
     40     /// \brief Given a source range, true to include previous inserts at the
     41     /// end of the range as part of the range itself (true by default).
     42     bool IncludeInsertsAtEndOfRange;
     43     /// \brief If true and removing some text leaves a blank line
     44     /// also remove the empty line (false by default).
     45     bool RemoveLineIfEmpty;
     46 
     47     RewriteOptions()
     48       : IncludeInsertsAtBeginOfRange(true),
     49         IncludeInsertsAtEndOfRange(true),
     50         RemoveLineIfEmpty(false) { }
     51   };
     52 
     53   typedef std::map<FileID, RewriteBuffer>::iterator buffer_iterator;
     54   typedef std::map<FileID, RewriteBuffer>::const_iterator const_buffer_iterator;
     55 
     56   explicit Rewriter(SourceManager &SM, const LangOptions &LO)
     57     : SourceMgr(&SM), LangOpts(&LO) {}
     58   explicit Rewriter() : SourceMgr(nullptr), LangOpts(nullptr) {}
     59 
     60   void setSourceMgr(SourceManager &SM, const LangOptions &LO) {
     61     SourceMgr = &SM;
     62     LangOpts = &LO;
     63   }
     64   SourceManager &getSourceMgr() const { return *SourceMgr; }
     65   const LangOptions &getLangOpts() const { return *LangOpts; }
     66 
     67   /// isRewritable - Return true if this location is a raw file location, which
     68   /// is rewritable.  Locations from macros, etc are not rewritable.
     69   static bool isRewritable(SourceLocation Loc) {
     70     return Loc.isFileID();
     71   }
     72 
     73   /// getRangeSize - Return the size in bytes of the specified range if they
     74   /// are in the same file.  If not, this returns -1.
     75   int getRangeSize(SourceRange Range,
     76                    RewriteOptions opts = RewriteOptions()) const;
     77   int getRangeSize(const CharSourceRange &Range,
     78                    RewriteOptions opts = RewriteOptions()) const;
     79 
     80   /// getRewrittenText - Return the rewritten form of the text in the specified
     81   /// range.  If the start or end of the range was unrewritable or if they are
     82   /// in different buffers, this returns an empty string.
     83   ///
     84   /// Note that this method is not particularly efficient.
     85   ///
     86   std::string getRewrittenText(SourceRange Range) const;
     87 
     88   /// InsertText - Insert the specified string at the specified location in the
     89   /// original buffer.  This method returns true (and does nothing) if the input
     90   /// location was not rewritable, false otherwise.
     91   ///
     92   /// \param indentNewLines if true new lines in the string are indented
     93   /// using the indentation of the source line in position \p Loc.
     94   bool InsertText(SourceLocation Loc, StringRef Str,
     95                   bool InsertAfter = true, bool indentNewLines = false);
     96 
     97   /// InsertTextAfter - Insert the specified string at the specified location in
     98   ///  the original buffer.  This method returns true (and does nothing) if
     99   ///  the input location was not rewritable, false otherwise.  Text is
    100   ///  inserted after any other text that has been previously inserted
    101   ///  at the some point (the default behavior for InsertText).
    102   bool InsertTextAfter(SourceLocation Loc, StringRef Str) {
    103     return InsertText(Loc, Str);
    104   }
    105 
    106   /// \brief Insert the specified string after the token in the
    107   /// specified location.
    108   bool InsertTextAfterToken(SourceLocation Loc, StringRef Str);
    109 
    110   /// InsertText - Insert the specified string at the specified location in the
    111   /// original buffer.  This method returns true (and does nothing) if the input
    112   /// location was not rewritable, false otherwise.  Text is
    113   /// inserted before any other text that has been previously inserted
    114   /// at the some point.
    115   bool InsertTextBefore(SourceLocation Loc, StringRef Str) {
    116     return InsertText(Loc, Str, false);
    117   }
    118 
    119   /// RemoveText - Remove the specified text region.
    120   bool RemoveText(SourceLocation Start, unsigned Length,
    121                   RewriteOptions opts = RewriteOptions());
    122 
    123   /// \brief Remove the specified text region.
    124   bool RemoveText(CharSourceRange range,
    125                   RewriteOptions opts = RewriteOptions()) {
    126     return RemoveText(range.getBegin(), getRangeSize(range, opts), opts);
    127   }
    128 
    129   /// \brief Remove the specified text region.
    130   bool RemoveText(SourceRange range, RewriteOptions opts = RewriteOptions()) {
    131     return RemoveText(range.getBegin(), getRangeSize(range, opts), opts);
    132   }
    133 
    134   /// ReplaceText - This method replaces a range of characters in the input
    135   /// buffer with a new string.  This is effectively a combined "remove/insert"
    136   /// operation.
    137   bool ReplaceText(SourceLocation Start, unsigned OrigLength,
    138                    StringRef NewStr);
    139 
    140   /// ReplaceText - This method replaces a range of characters in the input
    141   /// buffer with a new string.  This is effectively a combined "remove/insert"
    142   /// operation.
    143   bool ReplaceText(SourceRange range, StringRef NewStr) {
    144     return ReplaceText(range.getBegin(), getRangeSize(range), NewStr);
    145   }
    146 
    147   /// ReplaceText - This method replaces a range of characters in the input
    148   /// buffer with a new string.  This is effectively a combined "remove/insert"
    149   /// operation.
    150   bool ReplaceText(SourceRange range, SourceRange replacementRange);
    151 
    152   /// \brief Increase indentation for the lines between the given source range.
    153   /// To determine what the indentation should be, 'parentIndent' is used
    154   /// that should be at a source location with an indentation one degree
    155   /// lower than the given range.
    156   bool IncreaseIndentation(CharSourceRange range, SourceLocation parentIndent);
    157   bool IncreaseIndentation(SourceRange range, SourceLocation parentIndent) {
    158     return IncreaseIndentation(CharSourceRange::getTokenRange(range),
    159                                parentIndent);
    160   }
    161 
    162   /// getEditBuffer - This is like getRewriteBufferFor, but always returns a
    163   /// buffer, and allows you to write on it directly.  This is useful if you
    164   /// want efficient low-level access to apis for scribbling on one specific
    165   /// FileID's buffer.
    166   RewriteBuffer &getEditBuffer(FileID FID);
    167 
    168   /// getRewriteBufferFor - Return the rewrite buffer for the specified FileID.
    169   /// If no modification has been made to it, return null.
    170   const RewriteBuffer *getRewriteBufferFor(FileID FID) const {
    171     std::map<FileID, RewriteBuffer>::const_iterator I =
    172       RewriteBuffers.find(FID);
    173     return I == RewriteBuffers.end() ? nullptr : &I->second;
    174   }
    175 
    176   // Iterators over rewrite buffers.
    177   buffer_iterator buffer_begin() { return RewriteBuffers.begin(); }
    178   buffer_iterator buffer_end() { return RewriteBuffers.end(); }
    179   const_buffer_iterator buffer_begin() const { return RewriteBuffers.begin(); }
    180   const_buffer_iterator buffer_end() const { return RewriteBuffers.end(); }
    181 
    182   /// overwriteChangedFiles - Save all changed files to disk.
    183   ///
    184   /// Returns true if any files were not saved successfully.
    185   /// Outputs diagnostics via the source manager's diagnostic engine
    186   /// in case of an error.
    187   bool overwriteChangedFiles();
    188 
    189 private:
    190   unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) const;
    191 };
    192 
    193 } // end namespace clang
    194 
    195 #endif
    196