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