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/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 31 /// RewriteBuffer - As code is rewritten, SourceBuffer's from the original 32 /// input with modifications get a new RewriteBuffer associated with them. The 33 /// RewriteBuffer captures the modified text itself as well as information used 34 /// to map between SourceLocation's in the original input and offsets in the 35 /// RewriteBuffer. For example, if text is inserted into the buffer, any 36 /// locations after the insertion point have to be mapped. 37 class RewriteBuffer { 38 friend class Rewriter; 39 /// Deltas - Keep track of all the deltas in the source code due to insertions 40 /// and deletions. 41 DeltaTree Deltas; 42 RewriteRope Buffer; 43 public: 44 typedef RewriteRope::const_iterator iterator; begin()45 iterator begin() const { return Buffer.begin(); } end()46 iterator end() const { return Buffer.end(); } size()47 unsigned size() const { return Buffer.size(); } 48 49 /// \brief Write to \p Stream the result of applying all changes to the 50 /// original buffer. 51 /// Note that it isn't safe to use this function to overwrite memory mapped 52 /// files in-place (PR17960). Consider using a higher-level utility such as 53 /// Rewriter::overwriteChangedFiles() instead. 54 /// 55 /// The original buffer is not actually changed. 56 raw_ostream &write(raw_ostream &Stream) const; 57 58 /// RemoveText - Remove the specified text. 59 void RemoveText(unsigned OrigOffset, unsigned Size, 60 bool removeLineIfEmpty = false); 61 62 /// InsertText - Insert some text at the specified point, where the offset in 63 /// the buffer is specified relative to the original SourceBuffer. The 64 /// text is inserted after the specified location. 65 /// 66 void InsertText(unsigned OrigOffset, StringRef Str, 67 bool InsertAfter = true); 68 69 70 /// InsertTextBefore - Insert some text before the specified point, where the 71 /// offset in the buffer is specified relative to the original 72 /// SourceBuffer. The text is inserted before the specified location. This is 73 /// method is the same as InsertText with "InsertAfter == false". InsertTextBefore(unsigned OrigOffset,StringRef Str)74 void InsertTextBefore(unsigned OrigOffset, StringRef Str) { 75 InsertText(OrigOffset, Str, false); 76 } 77 78 /// InsertTextAfter - Insert some text at the specified point, where the 79 /// offset in the buffer is specified relative to the original SourceBuffer. 80 /// The text is inserted after the specified location. InsertTextAfter(unsigned OrigOffset,StringRef Str)81 void InsertTextAfter(unsigned OrigOffset, StringRef Str) { 82 InsertText(OrigOffset, Str); 83 } 84 85 /// ReplaceText - This method replaces a range of characters in the input 86 /// buffer with a new string. This is effectively a combined "remove/insert" 87 /// operation. 88 void ReplaceText(unsigned OrigOffset, unsigned OrigLength, 89 StringRef NewStr); 90 91 private: // Methods only usable by Rewriter. 92 93 /// Initialize - Start this rewrite buffer out with a copy of the unmodified 94 /// input buffer. Initialize(const char * BufStart,const char * BufEnd)95 void Initialize(const char *BufStart, const char *BufEnd) { 96 Buffer.assign(BufStart, BufEnd); 97 } 98 99 /// getMappedOffset - Given an offset into the original SourceBuffer that this 100 /// RewriteBuffer is based on, map it into the offset space of the 101 /// RewriteBuffer. If AfterInserts is true and if the OrigOffset indicates a 102 /// position where text is inserted, the location returned will be after any 103 /// inserted text at the position. 104 unsigned getMappedOffset(unsigned OrigOffset, 105 bool AfterInserts = false) const{ 106 return Deltas.getDeltaAt(2*OrigOffset+AfterInserts)+OrigOffset; 107 } 108 109 /// AddInsertDelta - When an insertion is made at a position, this 110 /// method is used to record that information. AddInsertDelta(unsigned OrigOffset,int Change)111 void AddInsertDelta(unsigned OrigOffset, int Change) { 112 return Deltas.AddDelta(2*OrigOffset, Change); 113 } 114 115 /// AddReplaceDelta - When a replacement/deletion is made at a position, this 116 /// method is used to record that information. AddReplaceDelta(unsigned OrigOffset,int Change)117 void AddReplaceDelta(unsigned OrigOffset, int Change) { 118 return Deltas.AddDelta(2*OrigOffset+1, Change); 119 } 120 }; 121 122 123 /// Rewriter - This is the main interface to the rewrite buffers. Its primary 124 /// job is to dispatch high-level requests to the low-level RewriteBuffers that 125 /// are involved. 126 class Rewriter { 127 SourceManager *SourceMgr; 128 const LangOptions *LangOpts; 129 std::map<FileID, RewriteBuffer> RewriteBuffers; 130 public: 131 struct RewriteOptions { 132 /// \brief Given a source range, true to include previous inserts at the 133 /// beginning of the range as part of the range itself (true by default). 134 bool IncludeInsertsAtBeginOfRange; 135 /// \brief Given a source range, true to include previous inserts at the 136 /// end of the range as part of the range itself (true by default). 137 bool IncludeInsertsAtEndOfRange; 138 /// \brief If true and removing some text leaves a blank line 139 /// also remove the empty line (false by default). 140 bool RemoveLineIfEmpty; 141 RewriteOptionsRewriteOptions142 RewriteOptions() 143 : IncludeInsertsAtBeginOfRange(true), 144 IncludeInsertsAtEndOfRange(true), 145 RemoveLineIfEmpty(false) { } 146 }; 147 148 typedef std::map<FileID, RewriteBuffer>::iterator buffer_iterator; 149 typedef std::map<FileID, RewriteBuffer>::const_iterator const_buffer_iterator; 150 Rewriter(SourceManager & SM,const LangOptions & LO)151 explicit Rewriter(SourceManager &SM, const LangOptions &LO) 152 : SourceMgr(&SM), LangOpts(&LO) {} Rewriter()153 explicit Rewriter() : SourceMgr(nullptr), LangOpts(nullptr) {} 154 setSourceMgr(SourceManager & SM,const LangOptions & LO)155 void setSourceMgr(SourceManager &SM, const LangOptions &LO) { 156 SourceMgr = &SM; 157 LangOpts = &LO; 158 } getSourceMgr()159 SourceManager &getSourceMgr() const { return *SourceMgr; } getLangOpts()160 const LangOptions &getLangOpts() const { return *LangOpts; } 161 162 /// isRewritable - Return true if this location is a raw file location, which 163 /// is rewritable. Locations from macros, etc are not rewritable. isRewritable(SourceLocation Loc)164 static bool isRewritable(SourceLocation Loc) { 165 return Loc.isFileID(); 166 } 167 168 /// getRangeSize - Return the size in bytes of the specified range if they 169 /// are in the same file. If not, this returns -1. 170 int getRangeSize(SourceRange Range, 171 RewriteOptions opts = RewriteOptions()) const; 172 int getRangeSize(const CharSourceRange &Range, 173 RewriteOptions opts = RewriteOptions()) const; 174 175 /// getRewrittenText - Return the rewritten form of the text in the specified 176 /// range. If the start or end of the range was unrewritable or if they are 177 /// in different buffers, this returns an empty string. 178 /// 179 /// Note that this method is not particularly efficient. 180 /// 181 std::string getRewrittenText(SourceRange Range) const; 182 183 /// InsertText - Insert the specified string at the specified location in the 184 /// original buffer. This method returns true (and does nothing) if the input 185 /// location was not rewritable, false otherwise. 186 /// 187 /// \param indentNewLines if true new lines in the string are indented 188 /// using the indentation of the source line in position \p Loc. 189 bool InsertText(SourceLocation Loc, StringRef Str, 190 bool InsertAfter = true, bool indentNewLines = false); 191 192 /// InsertTextAfter - Insert the specified string at the specified location in 193 /// the original buffer. This method returns true (and does nothing) if 194 /// the input location was not rewritable, false otherwise. Text is 195 /// inserted after any other text that has been previously inserted 196 /// at the some point (the default behavior for InsertText). InsertTextAfter(SourceLocation Loc,StringRef Str)197 bool InsertTextAfter(SourceLocation Loc, StringRef Str) { 198 return InsertText(Loc, Str); 199 } 200 201 /// \brief Insert the specified string after the token in the 202 /// specified location. 203 bool InsertTextAfterToken(SourceLocation Loc, StringRef Str); 204 205 /// InsertText - Insert the specified string at the specified location in the 206 /// original buffer. This method returns true (and does nothing) if the input 207 /// location was not rewritable, false otherwise. Text is 208 /// inserted before any other text that has been previously inserted 209 /// at the some point. InsertTextBefore(SourceLocation Loc,StringRef Str)210 bool InsertTextBefore(SourceLocation Loc, StringRef Str) { 211 return InsertText(Loc, Str, false); 212 } 213 214 /// RemoveText - Remove the specified text region. 215 bool RemoveText(SourceLocation Start, unsigned Length, 216 RewriteOptions opts = RewriteOptions()); 217 218 /// \brief Remove the specified text region. 219 bool RemoveText(CharSourceRange range, 220 RewriteOptions opts = RewriteOptions()) { 221 return RemoveText(range.getBegin(), getRangeSize(range, opts), opts); 222 } 223 224 /// \brief Remove the specified text region. 225 bool RemoveText(SourceRange range, RewriteOptions opts = RewriteOptions()) { 226 return RemoveText(range.getBegin(), getRangeSize(range, opts), opts); 227 } 228 229 /// ReplaceText - This method replaces a range of characters in the input 230 /// buffer with a new string. This is effectively a combined "remove/insert" 231 /// operation. 232 bool ReplaceText(SourceLocation Start, unsigned OrigLength, 233 StringRef NewStr); 234 235 /// ReplaceText - This method replaces a range of characters in the input 236 /// buffer with a new string. This is effectively a combined "remove/insert" 237 /// operation. ReplaceText(SourceRange range,StringRef NewStr)238 bool ReplaceText(SourceRange range, StringRef NewStr) { 239 return ReplaceText(range.getBegin(), getRangeSize(range), NewStr); 240 } 241 242 /// ReplaceText - This method replaces a range of characters in the input 243 /// buffer with a new string. This is effectively a combined "remove/insert" 244 /// operation. 245 bool ReplaceText(SourceRange range, SourceRange replacementRange); 246 247 /// \brief Increase indentation for the lines between the given source range. 248 /// To determine what the indentation should be, 'parentIndent' is used 249 /// that should be at a source location with an indentation one degree 250 /// lower than the given range. 251 bool IncreaseIndentation(CharSourceRange range, SourceLocation parentIndent); IncreaseIndentation(SourceRange range,SourceLocation parentIndent)252 bool IncreaseIndentation(SourceRange range, SourceLocation parentIndent) { 253 return IncreaseIndentation(CharSourceRange::getTokenRange(range), 254 parentIndent); 255 } 256 257 /// getEditBuffer - This is like getRewriteBufferFor, but always returns a 258 /// buffer, and allows you to write on it directly. This is useful if you 259 /// want efficient low-level access to apis for scribbling on one specific 260 /// FileID's buffer. 261 RewriteBuffer &getEditBuffer(FileID FID); 262 263 /// getRewriteBufferFor - Return the rewrite buffer for the specified FileID. 264 /// If no modification has been made to it, return null. getRewriteBufferFor(FileID FID)265 const RewriteBuffer *getRewriteBufferFor(FileID FID) const { 266 std::map<FileID, RewriteBuffer>::const_iterator I = 267 RewriteBuffers.find(FID); 268 return I == RewriteBuffers.end() ? nullptr : &I->second; 269 } 270 271 // Iterators over rewrite buffers. buffer_begin()272 buffer_iterator buffer_begin() { return RewriteBuffers.begin(); } buffer_end()273 buffer_iterator buffer_end() { return RewriteBuffers.end(); } buffer_begin()274 const_buffer_iterator buffer_begin() const { return RewriteBuffers.begin(); } buffer_end()275 const_buffer_iterator buffer_end() const { return RewriteBuffers.end(); } 276 277 /// overwriteChangedFiles - Save all changed files to disk. 278 /// 279 /// Returns true if any files were not saved successfully. 280 /// Outputs diagnostics via the source manager's diagnostic engine 281 /// in case of an error. 282 bool overwriteChangedFiles(); 283 284 private: 285 unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) const; 286 }; 287 288 } // end namespace clang 289 290 #endif 291