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_REWRITE_CORE_REWRITER_H 16 #define LLVM_CLANG_REWRITE_CORE_REWRITER_H 17 18 #include "clang/Basic/LLVM.h" 19 #include "clang/Basic/SourceLocation.h" 20 #include "clang/Rewrite/Core/RewriteBuffer.h" 21 #include "llvm/ADT/StringRef.h" 22 #include <map> 23 #include <string> 24 25 namespace clang { 26 27 class LangOptions; 28 class SourceManager; 29 30 /// Rewriter - This is the main interface to the rewrite buffers. Its primary 31 /// job is to dispatch high-level requests to the low-level RewriteBuffers that 32 /// are involved. 33 class Rewriter { 34 SourceManager *SourceMgr = nullptr; 35 const LangOptions *LangOpts = nullptr; 36 std::map<FileID, RewriteBuffer> RewriteBuffers; 37 38 public: 39 struct RewriteOptions { 40 /// Given a source range, true to include previous inserts at the 41 /// beginning of the range as part of the range itself (true by default). 42 bool IncludeInsertsAtBeginOfRange = true; 43 44 /// Given a source range, true to include previous inserts at the 45 /// end of the range as part of the range itself (true by default). 46 bool IncludeInsertsAtEndOfRange = true; 47 48 /// If true and removing some text leaves a blank line 49 /// also remove the empty line (false by default). 50 bool RemoveLineIfEmpty = false; 51 RewriteOptionsRewriteOptions52 RewriteOptions() {} 53 }; 54 55 using buffer_iterator = std::map<FileID, RewriteBuffer>::iterator; 56 using const_buffer_iterator = std::map<FileID, RewriteBuffer>::const_iterator; 57 58 explicit Rewriter() = default; Rewriter(SourceManager & SM,const LangOptions & LO)59 explicit Rewriter(SourceManager &SM, const LangOptions &LO) 60 : SourceMgr(&SM), LangOpts(&LO) {} 61 setSourceMgr(SourceManager & SM,const LangOptions & LO)62 void setSourceMgr(SourceManager &SM, const LangOptions &LO) { 63 SourceMgr = &SM; 64 LangOpts = &LO; 65 } 66 getSourceMgr()67 SourceManager &getSourceMgr() const { return *SourceMgr; } getLangOpts()68 const LangOptions &getLangOpts() const { return *LangOpts; } 69 70 /// isRewritable - Return true if this location is a raw file location, which 71 /// is rewritable. Locations from macros, etc are not rewritable. isRewritable(SourceLocation Loc)72 static bool isRewritable(SourceLocation Loc) { 73 return Loc.isFileID(); 74 } 75 76 /// getRangeSize - Return the size in bytes of the specified range if they 77 /// are in the same file. If not, this returns -1. 78 int getRangeSize(SourceRange Range, 79 RewriteOptions opts = RewriteOptions()) const; 80 int getRangeSize(const CharSourceRange &Range, 81 RewriteOptions opts = RewriteOptions()) const; 82 83 /// getRewrittenText - Return the rewritten form of the text in the specified 84 /// range. If the start or end of the range was unrewritable or if they are 85 /// in different buffers, this returns an empty string. 86 /// 87 /// Note that this method is not particularly efficient. 88 std::string getRewrittenText(SourceRange Range) const; 89 90 /// InsertText - Insert the specified string at the specified location in the 91 /// original buffer. This method returns true (and does nothing) if the input 92 /// location was not rewritable, false otherwise. 93 /// 94 /// \param indentNewLines if true new lines in the string are indented 95 /// using the indentation of the source line in position \p Loc. 96 bool InsertText(SourceLocation Loc, StringRef Str, 97 bool InsertAfter = true, bool indentNewLines = false); 98 99 /// InsertTextAfter - Insert the specified string at the specified location in 100 /// the original buffer. This method returns true (and does nothing) if 101 /// the input location was not rewritable, false otherwise. Text is 102 /// inserted after any other text that has been previously inserted 103 /// at the some point (the default behavior for InsertText). InsertTextAfter(SourceLocation Loc,StringRef Str)104 bool InsertTextAfter(SourceLocation Loc, StringRef Str) { 105 return InsertText(Loc, Str); 106 } 107 108 /// Insert the specified string after the token in the 109 /// specified location. 110 bool InsertTextAfterToken(SourceLocation Loc, StringRef Str); 111 112 /// InsertText - Insert the specified string at the specified location in the 113 /// original buffer. This method returns true (and does nothing) if the input 114 /// location was not rewritable, false otherwise. Text is 115 /// inserted before any other text that has been previously inserted 116 /// at the some point. InsertTextBefore(SourceLocation Loc,StringRef Str)117 bool InsertTextBefore(SourceLocation Loc, StringRef Str) { 118 return InsertText(Loc, Str, false); 119 } 120 121 /// RemoveText - Remove the specified text region. 122 bool RemoveText(SourceLocation Start, unsigned Length, 123 RewriteOptions opts = RewriteOptions()); 124 125 /// Remove the specified text region. 126 bool RemoveText(CharSourceRange range, 127 RewriteOptions opts = RewriteOptions()) { 128 return RemoveText(range.getBegin(), getRangeSize(range, opts), opts); 129 } 130 131 /// Remove the specified text region. 132 bool RemoveText(SourceRange range, RewriteOptions opts = RewriteOptions()) { 133 return RemoveText(range.getBegin(), getRangeSize(range, opts), opts); 134 } 135 136 /// ReplaceText - This method replaces a range of characters in the input 137 /// buffer with a new string. This is effectively a combined "remove/insert" 138 /// operation. 139 bool ReplaceText(SourceLocation Start, unsigned OrigLength, 140 StringRef NewStr); 141 142 /// ReplaceText - This method replaces a range of characters in the input 143 /// buffer with a new string. This is effectively a combined "remove/insert" 144 /// operation. ReplaceText(SourceRange range,StringRef NewStr)145 bool ReplaceText(SourceRange range, StringRef NewStr) { 146 return ReplaceText(range.getBegin(), getRangeSize(range), NewStr); 147 } 148 149 /// ReplaceText - This method replaces a range of characters in the input 150 /// buffer with a new string. This is effectively a combined "remove/insert" 151 /// operation. 152 bool ReplaceText(SourceRange range, SourceRange replacementRange); 153 154 /// Increase indentation for the lines between the given source range. 155 /// To determine what the indentation should be, 'parentIndent' is used 156 /// that should be at a source location with an indentation one degree 157 /// lower than the given range. 158 bool IncreaseIndentation(CharSourceRange range, SourceLocation parentIndent); IncreaseIndentation(SourceRange range,SourceLocation parentIndent)159 bool IncreaseIndentation(SourceRange range, SourceLocation parentIndent) { 160 return IncreaseIndentation(CharSourceRange::getTokenRange(range), 161 parentIndent); 162 } 163 164 /// getEditBuffer - This is like getRewriteBufferFor, but always returns a 165 /// buffer, and allows you to write on it directly. This is useful if you 166 /// want efficient low-level access to apis for scribbling on one specific 167 /// FileID's buffer. 168 RewriteBuffer &getEditBuffer(FileID FID); 169 170 /// getRewriteBufferFor - Return the rewrite buffer for the specified FileID. 171 /// If no modification has been made to it, return null. getRewriteBufferFor(FileID FID)172 const RewriteBuffer *getRewriteBufferFor(FileID FID) const { 173 std::map<FileID, RewriteBuffer>::const_iterator I = 174 RewriteBuffers.find(FID); 175 return I == RewriteBuffers.end() ? nullptr : &I->second; 176 } 177 178 // Iterators over rewrite buffers. buffer_begin()179 buffer_iterator buffer_begin() { return RewriteBuffers.begin(); } buffer_end()180 buffer_iterator buffer_end() { return RewriteBuffers.end(); } buffer_begin()181 const_buffer_iterator buffer_begin() const { return RewriteBuffers.begin(); } buffer_end()182 const_buffer_iterator buffer_end() const { return RewriteBuffers.end(); } 183 184 /// overwriteChangedFiles - Save all changed files to disk. 185 /// 186 /// Returns true if any files were not saved successfully. 187 /// Outputs diagnostics via the source manager's diagnostic engine 188 /// in case of an error. 189 bool overwriteChangedFiles(); 190 191 private: 192 unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) const; 193 }; 194 195 } // namespace clang 196 197 #endif // LLVM_CLANG_REWRITE_CORE_REWRITER_H 198