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