Rewriter.h revision 66490d26d14b9597768322b670a94cedbbe71448
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 typedef RewriteRope BufferTy; 44 BufferTy Buffer; 45public: 46 typedef BufferTy::const_iterator iterator; 47 iterator begin() const { return Buffer.begin(); } 48 iterator end() const { return Buffer.end(); } 49 unsigned size() const { return Buffer.size(); } 50 51 /// \brief Write to \p Stream the result of applying all changes to the 52 /// original buffer. 53 /// 54 /// The original buffer is not actually changed. 55 raw_ostream &write(raw_ostream &Stream) 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". 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. 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 90private: // Methods only usable by Rewriter. 91 92 /// Initialize - Start this rewrite buffer out with a copy of the unmodified 93 /// input buffer. 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. 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. 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. 125class Rewriter { 126 SourceManager *SourceMgr; 127 const LangOptions *LangOpts; 128 std::map<FileID, RewriteBuffer> RewriteBuffers; 129public: 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 141 RewriteOptions() 142 : IncludeInsertsAtBeginOfRange(true), 143 IncludeInsertsAtEndOfRange(true), 144 RemoveLineIfEmpty(false) { } 145 }; 146 147 typedef std::map<FileID, RewriteBuffer>::iterator buffer_iterator; 148 typedef std::map<FileID, RewriteBuffer>::const_iterator const_buffer_iterator; 149 150 explicit Rewriter(SourceManager &SM, const LangOptions &LO) 151 : SourceMgr(&SM), LangOpts(&LO) {} 152 explicit Rewriter() : SourceMgr(0), LangOpts(0) {} 153 154 void setSourceMgr(SourceManager &SM, const LangOptions &LO) { 155 SourceMgr = &SM; 156 LangOpts = &LO; 157 } 158 SourceManager &getSourceMgr() const { return *SourceMgr; } 159 const LangOptions &getLangOpts() const { return *LangOpts; } 160 161 /// isRewritable - Return true if this location is a raw file location, which 162 /// is rewritable. Locations from macros, etc are not rewritable. 163 static bool isRewritable(SourceLocation Loc) { 164 return Loc.isFileID(); 165 } 166 167 /// getRangeSize - Return the size in bytes of the specified range if they 168 /// are in the same file. If not, this returns -1. 169 int getRangeSize(SourceRange Range, 170 RewriteOptions opts = RewriteOptions()) const; 171 int getRangeSize(const CharSourceRange &Range, 172 RewriteOptions opts = RewriteOptions()) const; 173 174 /// getRewrittenText - Return the rewritten form of the text in the specified 175 /// range. If the start or end of the range was unrewritable or if they are 176 /// in different buffers, this returns an empty string. 177 /// 178 /// Note that this method is not particularly efficient. 179 /// 180 std::string getRewrittenText(SourceRange Range) const; 181 182 /// InsertText - Insert the specified string at the specified location in the 183 /// original buffer. This method returns true (and does nothing) if the input 184 /// location was not rewritable, false otherwise. 185 /// 186 /// \param indentNewLines if true new lines in the string are indented 187 /// using the indentation of the source line in position \p Loc. 188 bool InsertText(SourceLocation Loc, StringRef Str, 189 bool InsertAfter = true, bool indentNewLines = false); 190 191 /// InsertTextAfter - Insert the specified string at the specified location in 192 /// the original buffer. This method returns true (and does nothing) if 193 /// the input location was not rewritable, false otherwise. Text is 194 /// inserted after any other text that has been previously inserted 195 /// at the some point (the default behavior for InsertText). 196 bool InsertTextAfter(SourceLocation Loc, StringRef Str) { 197 return InsertText(Loc, Str); 198 } 199 200 /// \brief Insert the specified string after the token in the 201 /// specified location. 202 bool InsertTextAfterToken(SourceLocation Loc, StringRef Str); 203 204 /// InsertText - Insert the specified string at the specified location in the 205 /// original buffer. This method returns true (and does nothing) if the input 206 /// location was not rewritable, false otherwise. Text is 207 /// inserted before any other text that has been previously inserted 208 /// at the some point. 209 bool InsertTextBefore(SourceLocation Loc, StringRef Str) { 210 return InsertText(Loc, Str, false); 211 } 212 213 /// RemoveText - Remove the specified text region. 214 bool RemoveText(SourceLocation Start, unsigned Length, 215 RewriteOptions opts = RewriteOptions()); 216 217 /// \brief Remove the specified text region. 218 bool RemoveText(CharSourceRange range, 219 RewriteOptions opts = RewriteOptions()) { 220 return RemoveText(range.getBegin(), getRangeSize(range, opts), opts); 221 } 222 223 /// \brief Remove the specified text region. 224 bool RemoveText(SourceRange range, RewriteOptions opts = RewriteOptions()) { 225 return RemoveText(range.getBegin(), getRangeSize(range, opts), opts); 226 } 227 228 /// ReplaceText - This method replaces a range of characters in the input 229 /// buffer with a new string. This is effectively a combined "remove/insert" 230 /// operation. 231 bool ReplaceText(SourceLocation Start, unsigned OrigLength, 232 StringRef NewStr); 233 234 /// ReplaceText - This method replaces a range of characters in the input 235 /// buffer with a new string. This is effectively a combined "remove/insert" 236 /// operation. 237 bool ReplaceText(SourceRange range, StringRef NewStr) { 238 return ReplaceText(range.getBegin(), getRangeSize(range), NewStr); 239 } 240 241 /// ReplaceText - This method replaces a range of characters in the input 242 /// buffer with a new string. This is effectively a combined "remove/insert" 243 /// operation. 244 bool ReplaceText(SourceRange range, SourceRange replacementRange); 245 246 /// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty 247 /// printer to generate the replacement code. This returns true if the input 248 /// could not be rewritten, or false if successful. 249 bool ReplaceStmt(Stmt *From, Stmt *To); 250 251 /// \brief Increase indentation for the lines between the given source range. 252 /// To determine what the indentation should be, 'parentIndent' is used 253 /// that should be at a source location with an indentation one degree 254 /// lower than the given range. 255 bool IncreaseIndentation(CharSourceRange range, SourceLocation parentIndent); 256 bool IncreaseIndentation(SourceRange range, SourceLocation parentIndent) { 257 return IncreaseIndentation(CharSourceRange::getTokenRange(range), 258 parentIndent); 259 } 260 261 /// ConvertToString converts statement 'From' to a string using the 262 /// pretty printer. 263 std::string ConvertToString(Stmt *From); 264 265 /// getEditBuffer - This is like getRewriteBufferFor, but always returns a 266 /// buffer, and allows you to write on it directly. This is useful if you 267 /// want efficient low-level access to apis for scribbling on one specific 268 /// FileID's buffer. 269 RewriteBuffer &getEditBuffer(FileID FID); 270 271 /// getRewriteBufferFor - Return the rewrite buffer for the specified FileID. 272 /// If no modification has been made to it, return null. 273 const RewriteBuffer *getRewriteBufferFor(FileID FID) const { 274 std::map<FileID, RewriteBuffer>::const_iterator I = 275 RewriteBuffers.find(FID); 276 return I == RewriteBuffers.end() ? 0 : &I->second; 277 } 278 279 // Iterators over rewrite buffers. 280 buffer_iterator buffer_begin() { return RewriteBuffers.begin(); } 281 buffer_iterator buffer_end() { return RewriteBuffers.end(); } 282 const_buffer_iterator buffer_begin() const { return RewriteBuffers.begin(); } 283 const_buffer_iterator buffer_end() const { return RewriteBuffers.end(); } 284 285 /// overwriteChangedFiles - Save all changed files to disk. 286 /// 287 /// Returns whether not all changes were saved successfully. 288 /// Outputs diagnostics via the source manager's diagnostic engine 289 /// in case of an error. 290 bool overwriteChangedFiles(); 291 292private: 293 unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) const; 294}; 295 296} // end namespace clang 297 298#endif 299