1243791Sdim//===--- Rewriter.h - Code rewriting interface ------------------*- C++ -*-===// 2243791Sdim// 3243791Sdim// The LLVM Compiler Infrastructure 4243791Sdim// 5243791Sdim// This file is distributed under the University of Illinois Open Source 6243791Sdim// License. See LICENSE.TXT for details. 7243791Sdim// 8243791Sdim//===----------------------------------------------------------------------===// 9243791Sdim// 10243791Sdim// This file defines the Rewriter class, which is used for code 11243791Sdim// transformations. 12243791Sdim// 13243791Sdim//===----------------------------------------------------------------------===// 14243791Sdim 15243791Sdim#ifndef LLVM_CLANG_REWRITER_H 16243791Sdim#define LLVM_CLANG_REWRITER_H 17243791Sdim 18243791Sdim#include "clang/Basic/SourceLocation.h" 19243791Sdim#include "clang/Rewrite/Core/DeltaTree.h" 20243791Sdim#include "clang/Rewrite/Core/RewriteRope.h" 21243791Sdim#include "llvm/ADT/StringRef.h" 22243791Sdim#include <cstring> 23243791Sdim#include <map> 24243791Sdim#include <string> 25243791Sdim 26243791Sdimnamespace clang { 27243791Sdim class LangOptions; 28243791Sdim class Rewriter; 29243791Sdim class SourceManager; 30243791Sdim class Stmt; 31243791Sdim 32243791Sdim/// RewriteBuffer - As code is rewritten, SourceBuffer's from the original 33243791Sdim/// input with modifications get a new RewriteBuffer associated with them. The 34243791Sdim/// RewriteBuffer captures the modified text itself as well as information used 35243791Sdim/// to map between SourceLocation's in the original input and offsets in the 36243791Sdim/// RewriteBuffer. For example, if text is inserted into the buffer, any 37243791Sdim/// locations after the insertion point have to be mapped. 38243791Sdimclass RewriteBuffer { 39243791Sdim friend class Rewriter; 40243791Sdim /// Deltas - Keep track of all the deltas in the source code due to insertions 41243791Sdim /// and deletions. 42243791Sdim DeltaTree Deltas; 43243791Sdim 44243791Sdim /// Buffer - This is the actual buffer itself. Note that using a vector or 45243791Sdim /// string is a horribly inefficient way to do this, we should use a rope 46243791Sdim /// instead. 47243791Sdim typedef RewriteRope BufferTy; 48243791Sdim BufferTy Buffer; 49243791Sdimpublic: 50243791Sdim typedef BufferTy::const_iterator iterator; 51243791Sdim iterator begin() const { return Buffer.begin(); } 52243791Sdim iterator end() const { return Buffer.end(); } 53243791Sdim unsigned size() const { return Buffer.size(); } 54243791Sdim 55249423Sdim /// \brief Write to \p Stream the result of applying all changes to the 56249423Sdim /// original buffer. 57249423Sdim /// 58249423Sdim /// The original buffer is not actually changed. 59249423Sdim raw_ostream &write(raw_ostream &Stream) const; 60243791Sdim 61243791Sdim /// RemoveText - Remove the specified text. 62243791Sdim void RemoveText(unsigned OrigOffset, unsigned Size, 63243791Sdim bool removeLineIfEmpty = false); 64243791Sdim 65243791Sdim /// InsertText - Insert some text at the specified point, where the offset in 66243791Sdim /// the buffer is specified relative to the original SourceBuffer. The 67243791Sdim /// text is inserted after the specified location. 68243791Sdim /// 69243791Sdim void InsertText(unsigned OrigOffset, StringRef Str, 70243791Sdim bool InsertAfter = true); 71243791Sdim 72243791Sdim 73243791Sdim /// InsertTextBefore - Insert some text before the specified point, where the 74243791Sdim /// offset in the buffer is specified relative to the original 75243791Sdim /// SourceBuffer. The text is inserted before the specified location. This is 76243791Sdim /// method is the same as InsertText with "InsertAfter == false". 77243791Sdim void InsertTextBefore(unsigned OrigOffset, StringRef Str) { 78243791Sdim InsertText(OrigOffset, Str, false); 79243791Sdim } 80243791Sdim 81243791Sdim /// InsertTextAfter - Insert some text at the specified point, where the 82243791Sdim /// offset in the buffer is specified relative to the original SourceBuffer. 83243791Sdim /// The text is inserted after the specified location. 84243791Sdim void InsertTextAfter(unsigned OrigOffset, StringRef Str) { 85243791Sdim InsertText(OrigOffset, Str); 86243791Sdim } 87243791Sdim 88243791Sdim /// ReplaceText - This method replaces a range of characters in the input 89243791Sdim /// buffer with a new string. This is effectively a combined "remove/insert" 90243791Sdim /// operation. 91243791Sdim void ReplaceText(unsigned OrigOffset, unsigned OrigLength, 92243791Sdim StringRef NewStr); 93243791Sdim 94243791Sdimprivate: // Methods only usable by Rewriter. 95243791Sdim 96243791Sdim /// Initialize - Start this rewrite buffer out with a copy of the unmodified 97243791Sdim /// input buffer. 98243791Sdim void Initialize(const char *BufStart, const char *BufEnd) { 99243791Sdim Buffer.assign(BufStart, BufEnd); 100243791Sdim } 101243791Sdim 102243791Sdim /// getMappedOffset - Given an offset into the original SourceBuffer that this 103243791Sdim /// RewriteBuffer is based on, map it into the offset space of the 104243791Sdim /// RewriteBuffer. If AfterInserts is true and if the OrigOffset indicates a 105243791Sdim /// position where text is inserted, the location returned will be after any 106243791Sdim /// inserted text at the position. 107243791Sdim unsigned getMappedOffset(unsigned OrigOffset, 108243791Sdim bool AfterInserts = false) const{ 109243791Sdim return Deltas.getDeltaAt(2*OrigOffset+AfterInserts)+OrigOffset; 110243791Sdim } 111243791Sdim 112243791Sdim /// AddInsertDelta - When an insertion is made at a position, this 113243791Sdim /// method is used to record that information. 114243791Sdim void AddInsertDelta(unsigned OrigOffset, int Change) { 115243791Sdim return Deltas.AddDelta(2*OrigOffset, Change); 116243791Sdim } 117243791Sdim 118243791Sdim /// AddReplaceDelta - When a replacement/deletion is made at a position, this 119243791Sdim /// method is used to record that information. 120243791Sdim void AddReplaceDelta(unsigned OrigOffset, int Change) { 121243791Sdim return Deltas.AddDelta(2*OrigOffset+1, Change); 122243791Sdim } 123243791Sdim}; 124243791Sdim 125243791Sdim 126243791Sdim/// Rewriter - This is the main interface to the rewrite buffers. Its primary 127243791Sdim/// job is to dispatch high-level requests to the low-level RewriteBuffers that 128243791Sdim/// are involved. 129243791Sdimclass Rewriter { 130243791Sdim SourceManager *SourceMgr; 131243791Sdim const LangOptions *LangOpts; 132243791Sdim std::map<FileID, RewriteBuffer> RewriteBuffers; 133243791Sdimpublic: 134243791Sdim struct RewriteOptions { 135243791Sdim /// \brief Given a source range, true to include previous inserts at the 136243791Sdim /// beginning of the range as part of the range itself (true by default). 137243791Sdim bool IncludeInsertsAtBeginOfRange; 138243791Sdim /// \brief Given a source range, true to include previous inserts at the 139243791Sdim /// end of the range as part of the range itself (true by default). 140243791Sdim bool IncludeInsertsAtEndOfRange; 141243791Sdim /// \brief If true and removing some text leaves a blank line 142243791Sdim /// also remove the empty line (false by default). 143243791Sdim bool RemoveLineIfEmpty; 144243791Sdim 145243791Sdim RewriteOptions() 146243791Sdim : IncludeInsertsAtBeginOfRange(true), 147243791Sdim IncludeInsertsAtEndOfRange(true), 148243791Sdim RemoveLineIfEmpty(false) { } 149243791Sdim }; 150243791Sdim 151243791Sdim typedef std::map<FileID, RewriteBuffer>::iterator buffer_iterator; 152243791Sdim 153243791Sdim explicit Rewriter(SourceManager &SM, const LangOptions &LO) 154243791Sdim : SourceMgr(&SM), LangOpts(&LO) {} 155243791Sdim explicit Rewriter() : SourceMgr(0), LangOpts(0) {} 156243791Sdim 157243791Sdim void setSourceMgr(SourceManager &SM, const LangOptions &LO) { 158243791Sdim SourceMgr = &SM; 159243791Sdim LangOpts = &LO; 160243791Sdim } 161243791Sdim SourceManager &getSourceMgr() const { return *SourceMgr; } 162243791Sdim const LangOptions &getLangOpts() const { return *LangOpts; } 163243791Sdim 164243791Sdim /// isRewritable - Return true if this location is a raw file location, which 165243791Sdim /// is rewritable. Locations from macros, etc are not rewritable. 166243791Sdim static bool isRewritable(SourceLocation Loc) { 167243791Sdim return Loc.isFileID(); 168243791Sdim } 169243791Sdim 170243791Sdim /// getRangeSize - Return the size in bytes of the specified range if they 171243791Sdim /// are in the same file. If not, this returns -1. 172243791Sdim int getRangeSize(SourceRange Range, 173243791Sdim RewriteOptions opts = RewriteOptions()) const; 174243791Sdim int getRangeSize(const CharSourceRange &Range, 175243791Sdim RewriteOptions opts = RewriteOptions()) const; 176243791Sdim 177243791Sdim /// getRewrittenText - Return the rewritten form of the text in the specified 178243791Sdim /// range. If the start or end of the range was unrewritable or if they are 179243791Sdim /// in different buffers, this returns an empty string. 180243791Sdim /// 181243791Sdim /// Note that this method is not particularly efficient. 182243791Sdim /// 183243791Sdim std::string getRewrittenText(SourceRange Range) const; 184243791Sdim 185243791Sdim /// InsertText - Insert the specified string at the specified location in the 186243791Sdim /// original buffer. This method returns true (and does nothing) if the input 187243791Sdim /// location was not rewritable, false otherwise. 188243791Sdim /// 189243791Sdim /// \param indentNewLines if true new lines in the string are indented 190243791Sdim /// using the indentation of the source line in position \p Loc. 191243791Sdim bool InsertText(SourceLocation Loc, StringRef Str, 192243791Sdim bool InsertAfter = true, bool indentNewLines = false); 193243791Sdim 194243791Sdim /// InsertTextAfter - Insert the specified string at the specified location in 195243791Sdim /// the original buffer. This method returns true (and does nothing) if 196243791Sdim /// the input location was not rewritable, false otherwise. Text is 197243791Sdim /// inserted after any other text that has been previously inserted 198243791Sdim /// at the some point (the default behavior for InsertText). 199243791Sdim bool InsertTextAfter(SourceLocation Loc, StringRef Str) { 200243791Sdim return InsertText(Loc, Str); 201243791Sdim } 202243791Sdim 203243791Sdim /// \brief Insert the specified string after the token in the 204243791Sdim /// specified location. 205243791Sdim bool InsertTextAfterToken(SourceLocation Loc, StringRef Str); 206243791Sdim 207243791Sdim /// InsertText - Insert the specified string at the specified location in the 208243791Sdim /// original buffer. This method returns true (and does nothing) if the input 209243791Sdim /// location was not rewritable, false otherwise. Text is 210243791Sdim /// inserted before any other text that has been previously inserted 211243791Sdim /// at the some point. 212243791Sdim bool InsertTextBefore(SourceLocation Loc, StringRef Str) { 213243791Sdim return InsertText(Loc, Str, false); 214243791Sdim } 215243791Sdim 216243791Sdim /// RemoveText - Remove the specified text region. 217243791Sdim bool RemoveText(SourceLocation Start, unsigned Length, 218243791Sdim RewriteOptions opts = RewriteOptions()); 219243791Sdim 220243791Sdim /// \brief Remove the specified text region. 221243791Sdim bool RemoveText(CharSourceRange range, 222243791Sdim RewriteOptions opts = RewriteOptions()) { 223243791Sdim return RemoveText(range.getBegin(), getRangeSize(range, opts), opts); 224243791Sdim } 225243791Sdim 226243791Sdim /// \brief Remove the specified text region. 227243791Sdim bool RemoveText(SourceRange range, RewriteOptions opts = RewriteOptions()) { 228243791Sdim return RemoveText(range.getBegin(), getRangeSize(range, opts), opts); 229243791Sdim } 230243791Sdim 231243791Sdim /// ReplaceText - This method replaces a range of characters in the input 232243791Sdim /// buffer with a new string. This is effectively a combined "remove/insert" 233243791Sdim /// operation. 234243791Sdim bool ReplaceText(SourceLocation Start, unsigned OrigLength, 235243791Sdim StringRef NewStr); 236243791Sdim 237243791Sdim /// ReplaceText - This method replaces a range of characters in the input 238243791Sdim /// buffer with a new string. This is effectively a combined "remove/insert" 239243791Sdim /// operation. 240243791Sdim bool ReplaceText(SourceRange range, StringRef NewStr) { 241243791Sdim return ReplaceText(range.getBegin(), getRangeSize(range), NewStr); 242243791Sdim } 243243791Sdim 244243791Sdim /// ReplaceText - This method replaces a range of characters in the input 245243791Sdim /// buffer with a new string. This is effectively a combined "remove/insert" 246243791Sdim /// operation. 247243791Sdim bool ReplaceText(SourceRange range, SourceRange replacementRange); 248243791Sdim 249243791Sdim /// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty 250243791Sdim /// printer to generate the replacement code. This returns true if the input 251243791Sdim /// could not be rewritten, or false if successful. 252243791Sdim bool ReplaceStmt(Stmt *From, Stmt *To); 253243791Sdim 254243791Sdim /// \brief Increase indentation for the lines between the given source range. 255243791Sdim /// To determine what the indentation should be, 'parentIndent' is used 256243791Sdim /// that should be at a source location with an indentation one degree 257243791Sdim /// lower than the given range. 258243791Sdim bool IncreaseIndentation(CharSourceRange range, SourceLocation parentIndent); 259243791Sdim bool IncreaseIndentation(SourceRange range, SourceLocation parentIndent) { 260243791Sdim return IncreaseIndentation(CharSourceRange::getTokenRange(range), 261243791Sdim parentIndent); 262243791Sdim } 263243791Sdim 264243791Sdim /// ConvertToString converts statement 'From' to a string using the 265243791Sdim /// pretty printer. 266243791Sdim std::string ConvertToString(Stmt *From); 267243791Sdim 268243791Sdim /// getEditBuffer - This is like getRewriteBufferFor, but always returns a 269243791Sdim /// buffer, and allows you to write on it directly. This is useful if you 270243791Sdim /// want efficient low-level access to apis for scribbling on one specific 271243791Sdim /// FileID's buffer. 272243791Sdim RewriteBuffer &getEditBuffer(FileID FID); 273243791Sdim 274243791Sdim /// getRewriteBufferFor - Return the rewrite buffer for the specified FileID. 275243791Sdim /// If no modification has been made to it, return null. 276243791Sdim const RewriteBuffer *getRewriteBufferFor(FileID FID) const { 277243791Sdim std::map<FileID, RewriteBuffer>::const_iterator I = 278243791Sdim RewriteBuffers.find(FID); 279243791Sdim return I == RewriteBuffers.end() ? 0 : &I->second; 280243791Sdim } 281243791Sdim 282243791Sdim // Iterators over rewrite buffers. 283243791Sdim buffer_iterator buffer_begin() { return RewriteBuffers.begin(); } 284243791Sdim buffer_iterator buffer_end() { return RewriteBuffers.end(); } 285243791Sdim 286249423Sdim /// overwriteChangedFiles - Save all changed files to disk. 287243791Sdim /// 288243791Sdim /// Returns whether not all changes were saved successfully. 289243791Sdim /// Outputs diagnostics via the source manager's diagnostic engine 290243791Sdim /// in case of an error. 291243791Sdim bool overwriteChangedFiles(); 292243791Sdim 293243791Sdimprivate: 294243791Sdim unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) const; 295243791Sdim}; 296243791Sdim 297243791Sdim} // end namespace clang 298243791Sdim 299243791Sdim#endif 300