Home | History | Annotate | Line # | Download | only in Core
      1 //===- Rewriter.h - Code rewriting interface --------------------*- C++ -*-===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 //  This file defines the Rewriter class, which is used for code
     10 //  transformations.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifndef LLVM_CLANG_REWRITE_CORE_REWRITER_H
     15 #define LLVM_CLANG_REWRITE_CORE_REWRITER_H
     16 
     17 #include "clang/Basic/LLVM.h"
     18 #include "clang/Basic/SourceLocation.h"
     19 #include "clang/Rewrite/Core/RewriteBuffer.h"
     20 #include "llvm/ADT/StringRef.h"
     21 #include <map>
     22 #include <string>
     23 
     24 namespace clang {
     25 
     26 class LangOptions;
     27 class SourceManager;
     28 
     29 /// Rewriter - This is the main interface to the rewrite buffers.  Its primary
     30 /// job is to dispatch high-level requests to the low-level RewriteBuffers that
     31 /// are involved.
     32 class Rewriter {
     33   SourceManager *SourceMgr = nullptr;
     34   const LangOptions *LangOpts = nullptr;
     35   std::map<FileID, RewriteBuffer> RewriteBuffers;
     36 
     37 public:
     38   struct RewriteOptions {
     39     /// Given a source range, true to include previous inserts at the
     40     /// beginning of the range as part of the range itself (true by default).
     41     bool IncludeInsertsAtBeginOfRange = true;
     42 
     43     /// Given a source range, true to include previous inserts at the
     44     /// end of the range as part of the range itself (true by default).
     45     bool IncludeInsertsAtEndOfRange = true;
     46 
     47     /// If true and removing some text leaves a blank line
     48     /// also remove the empty line (false by default).
     49     ///
     50     /// FIXME: This sometimes corrupts the file's rewrite buffer due to
     51     /// incorrect indexing in the implementation (see the FIXME in
     52     /// clang::RewriteBuffer::RemoveText).  Moreover, it's inefficient because
     53     /// it must scan the buffer from the beginning to find the start of the
     54     /// line.  When feasible, it's better for the caller to check for a blank
     55     /// line and then, if found, expand the removal range to include it.
     56     /// Checking for a blank line is easy if, for example, the caller can
     57     /// guarantee this is the first edit of a line.  In that case, it can just
     58     /// scan before and after the removal range until the next newline or
     59     /// begin/end of the input.
     60     bool RemoveLineIfEmpty = false;
     61 
     62     RewriteOptions() {}
     63   };
     64 
     65   using buffer_iterator = std::map<FileID, RewriteBuffer>::iterator;
     66   using const_buffer_iterator = std::map<FileID, RewriteBuffer>::const_iterator;
     67 
     68   explicit Rewriter() = default;
     69   explicit Rewriter(SourceManager &SM, const LangOptions &LO)
     70       : SourceMgr(&SM), LangOpts(&LO) {}
     71 
     72   void setSourceMgr(SourceManager &SM, const LangOptions &LO) {
     73     SourceMgr = &SM;
     74     LangOpts = &LO;
     75   }
     76 
     77   SourceManager &getSourceMgr() const { return *SourceMgr; }
     78   const LangOptions &getLangOpts() const { return *LangOpts; }
     79 
     80   /// isRewritable - Return true if this location is a raw file location, which
     81   /// is rewritable.  Locations from macros, etc are not rewritable.
     82   static bool isRewritable(SourceLocation Loc) {
     83     return Loc.isFileID();
     84   }
     85 
     86   /// getRangeSize - Return the size in bytes of the specified range if they
     87   /// are in the same file.  If not, this returns -1.
     88   int getRangeSize(SourceRange Range,
     89                    RewriteOptions opts = RewriteOptions()) const;
     90   int getRangeSize(const CharSourceRange &Range,
     91                    RewriteOptions opts = RewriteOptions()) const;
     92 
     93   /// getRewrittenText - Return the rewritten form of the text in the specified
     94   /// range.  If the start or end of the range was unrewritable or if they are
     95   /// in different buffers, this returns an empty string.
     96   ///
     97   /// Note that this method is not particularly efficient.
     98   std::string getRewrittenText(CharSourceRange Range) const;
     99 
    100   /// getRewrittenText - Return the rewritten form of the text in the specified
    101   /// range.  If the start or end of the range was unrewritable or if they are
    102   /// in different buffers, this returns an empty string.
    103   ///
    104   /// Note that this method is not particularly efficient.
    105   std::string getRewrittenText(SourceRange Range) const {
    106     return getRewrittenText(CharSourceRange::getTokenRange(Range));
    107   }
    108 
    109   /// InsertText - Insert the specified string at the specified location in the
    110   /// original buffer.  This method returns true (and does nothing) if the input
    111   /// location was not rewritable, false otherwise.
    112   ///
    113   /// \param indentNewLines if true new lines in the string are indented
    114   /// using the indentation of the source line in position \p Loc.
    115   bool InsertText(SourceLocation Loc, StringRef Str,
    116                   bool InsertAfter = true, bool indentNewLines = false);
    117 
    118   /// InsertTextAfter - Insert the specified string at the specified location in
    119   ///  the original buffer.  This method returns true (and does nothing) if
    120   ///  the input location was not rewritable, false otherwise.  Text is
    121   ///  inserted after any other text that has been previously inserted
    122   ///  at the some point (the default behavior for InsertText).
    123   bool InsertTextAfter(SourceLocation Loc, StringRef Str) {
    124     return InsertText(Loc, Str);
    125   }
    126 
    127   /// Insert the specified string after the token in the
    128   /// specified location.
    129   bool InsertTextAfterToken(SourceLocation Loc, StringRef Str);
    130 
    131   /// InsertText - Insert the specified string at the specified location in the
    132   /// original buffer.  This method returns true (and does nothing) if the input
    133   /// location was not rewritable, false otherwise.  Text is
    134   /// inserted before any other text that has been previously inserted
    135   /// at the some point.
    136   bool InsertTextBefore(SourceLocation Loc, StringRef Str) {
    137     return InsertText(Loc, Str, false);
    138   }
    139 
    140   /// RemoveText - Remove the specified text region.
    141   bool RemoveText(SourceLocation Start, unsigned Length,
    142                   RewriteOptions opts = RewriteOptions());
    143 
    144   /// Remove the specified text region.
    145   bool RemoveText(CharSourceRange range,
    146                   RewriteOptions opts = RewriteOptions()) {
    147     return RemoveText(range.getBegin(), getRangeSize(range, opts), opts);
    148   }
    149 
    150   /// Remove the specified text region.
    151   bool RemoveText(SourceRange range, RewriteOptions opts = RewriteOptions()) {
    152     return RemoveText(range.getBegin(), getRangeSize(range, opts), opts);
    153   }
    154 
    155   /// ReplaceText - This method replaces a range of characters in the input
    156   /// buffer with a new string.  This is effectively a combined "remove/insert"
    157   /// operation.
    158   bool ReplaceText(SourceLocation Start, unsigned OrigLength,
    159                    StringRef NewStr);
    160 
    161   /// ReplaceText - This method replaces a range of characters in the input
    162   /// buffer with a new string.  This is effectively a combined "remove/insert"
    163   /// operation.
    164   bool ReplaceText(CharSourceRange range, StringRef NewStr) {
    165     return ReplaceText(range.getBegin(), getRangeSize(range), NewStr);
    166   }
    167 
    168   /// ReplaceText - This method replaces a range of characters in the input
    169   /// buffer with a new string.  This is effectively a combined "remove/insert"
    170   /// operation.
    171   bool ReplaceText(SourceRange range, StringRef NewStr) {
    172     return ReplaceText(range.getBegin(), getRangeSize(range), NewStr);
    173   }
    174 
    175   /// ReplaceText - This method replaces a range of characters in the input
    176   /// buffer with a new string.  This is effectively a combined "remove/insert"
    177   /// operation.
    178   bool ReplaceText(SourceRange range, SourceRange replacementRange);
    179 
    180   /// Increase indentation for the lines between the given source range.
    181   /// To determine what the indentation should be, 'parentIndent' is used
    182   /// that should be at a source location with an indentation one degree
    183   /// lower than the given range.
    184   bool IncreaseIndentation(CharSourceRange range, SourceLocation parentIndent);
    185   bool IncreaseIndentation(SourceRange range, SourceLocation parentIndent) {
    186     return IncreaseIndentation(CharSourceRange::getTokenRange(range),
    187                                parentIndent);
    188   }
    189 
    190   /// getEditBuffer - This is like getRewriteBufferFor, but always returns a
    191   /// buffer, and allows you to write on it directly.  This is useful if you
    192   /// want efficient low-level access to apis for scribbling on one specific
    193   /// FileID's buffer.
    194   RewriteBuffer &getEditBuffer(FileID FID);
    195 
    196   /// getRewriteBufferFor - Return the rewrite buffer for the specified FileID.
    197   /// If no modification has been made to it, return null.
    198   const RewriteBuffer *getRewriteBufferFor(FileID FID) const {
    199     std::map<FileID, RewriteBuffer>::const_iterator I =
    200       RewriteBuffers.find(FID);
    201     return I == RewriteBuffers.end() ? nullptr : &I->second;
    202   }
    203 
    204   // Iterators over rewrite buffers.
    205   buffer_iterator buffer_begin() { return RewriteBuffers.begin(); }
    206   buffer_iterator buffer_end() { return RewriteBuffers.end(); }
    207   const_buffer_iterator buffer_begin() const { return RewriteBuffers.begin(); }
    208   const_buffer_iterator buffer_end() const { return RewriteBuffers.end(); }
    209 
    210   /// overwriteChangedFiles - Save all changed files to disk.
    211   ///
    212   /// Returns true if any files were not saved successfully.
    213   /// Outputs diagnostics via the source manager's diagnostic engine
    214   /// in case of an error.
    215   bool overwriteChangedFiles();
    216 
    217 private:
    218   unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) const;
    219 };
    220 
    221 } // namespace clang
    222 
    223 #endif // LLVM_CLANG_REWRITE_CORE_REWRITER_H
    224