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