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