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