Rewriter.h revision 60c9c305a8f47cb1e6d4aa174e90e80355c4d415
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 RewriteRope Buffer; 44public: 45 typedef RewriteRope::const_iterator iterator; 46 iterator begin() const { return Buffer.begin(); } 47 iterator end() const { return Buffer.end(); } 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 /// 53 /// The original buffer is not actually changed. 54 raw_ostream &write(raw_ostream &Stream) const; 55 56 /// RemoveText - Remove the specified text. 57 void RemoveText(unsigned OrigOffset, unsigned Size, 58 bool removeLineIfEmpty = false); 59 60 /// InsertText - Insert some text at the specified point, where the offset in 61 /// the buffer is specified relative to the original SourceBuffer. The 62 /// text is inserted after the specified location. 63 /// 64 void InsertText(unsigned OrigOffset, StringRef Str, 65 bool InsertAfter = true); 66 67 68 /// InsertTextBefore - Insert some text before the specified point, where the 69 /// offset in the buffer is specified relative to the original 70 /// SourceBuffer. The text is inserted before the specified location. This is 71 /// method is the same as InsertText with "InsertAfter == false". 72 void InsertTextBefore(unsigned OrigOffset, StringRef Str) { 73 InsertText(OrigOffset, Str, false); 74 } 75 76 /// InsertTextAfter - Insert some text at the specified point, where the 77 /// offset in the buffer is specified relative to the original SourceBuffer. 78 /// The text is inserted after the specified location. 79 void InsertTextAfter(unsigned OrigOffset, StringRef Str) { 80 InsertText(OrigOffset, Str); 81 } 82 83 /// ReplaceText - This method replaces a range of characters in the input 84 /// buffer with a new string. This is effectively a combined "remove/insert" 85 /// operation. 86 void ReplaceText(unsigned OrigOffset, unsigned OrigLength, 87 StringRef NewStr); 88 89private: // Methods only usable by Rewriter. 90 91 /// Initialize - Start this rewrite buffer out with a copy of the unmodified 92 /// input buffer. 93 void Initialize(const char *BufStart, const char *BufEnd) { 94 Buffer.assign(BufStart, BufEnd); 95 } 96 97 /// getMappedOffset - Given an offset into the original SourceBuffer that this 98 /// RewriteBuffer is based on, map it into the offset space of the 99 /// RewriteBuffer. If AfterInserts is true and if the OrigOffset indicates a 100 /// position where text is inserted, the location returned will be after any 101 /// inserted text at the position. 102 unsigned getMappedOffset(unsigned OrigOffset, 103 bool AfterInserts = false) const{ 104 return Deltas.getDeltaAt(2*OrigOffset+AfterInserts)+OrigOffset; 105 } 106 107 /// AddInsertDelta - When an insertion is made at a position, this 108 /// method is used to record that information. 109 void AddInsertDelta(unsigned OrigOffset, int Change) { 110 return Deltas.AddDelta(2*OrigOffset, Change); 111 } 112 113 /// AddReplaceDelta - When a replacement/deletion is made at a position, this 114 /// method is used to record that information. 115 void AddReplaceDelta(unsigned OrigOffset, int Change) { 116 return Deltas.AddDelta(2*OrigOffset+1, Change); 117 } 118}; 119 120 121/// Rewriter - This is the main interface to the rewrite buffers. Its primary 122/// job is to dispatch high-level requests to the low-level RewriteBuffers that 123/// are involved. 124class Rewriter { 125 SourceManager *SourceMgr; 126 const LangOptions *LangOpts; 127 std::map<FileID, RewriteBuffer> RewriteBuffers; 128public: 129 struct RewriteOptions { 130 /// \brief Given a source range, true to include previous inserts at the 131 /// beginning of the range as part of the range itself (true by default). 132 bool IncludeInsertsAtBeginOfRange; 133 /// \brief Given a source range, true to include previous inserts at the 134 /// end of the range as part of the range itself (true by default). 135 bool IncludeInsertsAtEndOfRange; 136 /// \brief If true and removing some text leaves a blank line 137 /// also remove the empty line (false by default). 138 bool RemoveLineIfEmpty; 139 140 RewriteOptions() 141 : IncludeInsertsAtBeginOfRange(true), 142 IncludeInsertsAtEndOfRange(true), 143 RemoveLineIfEmpty(false) { } 144 }; 145 146 typedef std::map<FileID, RewriteBuffer>::iterator buffer_iterator; 147 typedef std::map<FileID, RewriteBuffer>::const_iterator const_buffer_iterator; 148 149 explicit Rewriter(SourceManager &SM, const LangOptions &LO) 150 : SourceMgr(&SM), LangOpts(&LO) {} 151 explicit Rewriter() : SourceMgr(0), LangOpts(0) {} 152 153 void setSourceMgr(SourceManager &SM, const LangOptions &LO) { 154 SourceMgr = &SM; 155 LangOpts = &LO; 156 } 157 SourceManager &getSourceMgr() const { return *SourceMgr; } 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. 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 \p 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). 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. 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. 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); 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. 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. 279 buffer_iterator buffer_begin() { return RewriteBuffers.begin(); } 280 buffer_iterator buffer_end() { return RewriteBuffers.end(); } 281 const_buffer_iterator buffer_begin() const { return RewriteBuffers.begin(); } 282 const_buffer_iterator buffer_end() const { return RewriteBuffers.end(); } 283 284 /// overwriteChangedFiles - Save all changed files to disk. 285 /// 286 /// Returns true if any files were not saved successfully. 287 /// Outputs diagnostics via the source manager's diagnostic engine 288 /// in case of an error. 289 bool overwriteChangedFiles(); 290 291private: 292 unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) const; 293}; 294 295} // end namespace clang 296 297#endif 298