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