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; begin()46 iterator begin() const { return Buffer.begin(); } end()47 iterator end() const { return Buffer.end(); } size()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". InsertTextBefore(unsigned OrigOffset,StringRef Str)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. InsertTextAfter(unsigned OrigOffset,StringRef Str)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. Initialize(const char * BufStart,const char * BufEnd)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. AddInsertDelta(unsigned OrigOffset,int Change)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. AddReplaceDelta(unsigned OrigOffset,int Change)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 RewriteOptionsRewriteOptions143 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 Rewriter(SourceManager & SM,const LangOptions & LO)152 explicit Rewriter(SourceManager &SM, const LangOptions &LO) 153 : SourceMgr(&SM), LangOpts(&LO) {} Rewriter()154 explicit Rewriter() : SourceMgr(nullptr), LangOpts(nullptr) {} 155 setSourceMgr(SourceManager & SM,const LangOptions & LO)156 void setSourceMgr(SourceManager &SM, const LangOptions &LO) { 157 SourceMgr = &SM; 158 LangOpts = &LO; 159 } getSourceMgr()160 SourceManager &getSourceMgr() const { return *SourceMgr; } getLangOpts()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. isRewritable(SourceLocation Loc)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). InsertTextAfter(SourceLocation Loc,StringRef Str)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. InsertTextBefore(SourceLocation Loc,StringRef Str)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. ReplaceText(SourceRange range,StringRef NewStr)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); IncreaseIndentation(SourceRange 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. getRewriteBufferFor(FileID FID)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. buffer_begin()282 buffer_iterator buffer_begin() { return RewriteBuffers.begin(); } buffer_end()283 buffer_iterator buffer_end() { return RewriteBuffers.end(); } buffer_begin()284 const_buffer_iterator buffer_begin() const { return RewriteBuffers.begin(); } buffer_end()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