clang: lib/Edit/Commit.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
17#include "llvm/ADT/StringRef.h"
18#include
19
20using namespace clang;
21using namespace edit;
22
29
34
41
43 : SourceMgr(Editor.getSourceManager()), LangOpts(Editor.getLangOpts()),
44 PPRec(Editor.getPPCondDirectiveRecord()),
45 Editor(&Editor) {}
46
48 bool afterToken, bool beforePreviousInsertions) {
49 if (text.empty())
50 return true;
51
53 if ((!afterToken && !canInsert(loc, Offs)) ||
54 ( afterToken && !canInsertAfterToken(loc, Offs, loc))) {
55 IsCommitable = false;
56 return false;
57 }
58
59 addInsert(loc, Offs, text, beforePreviousInsertions);
60 return true;
61}
62
65 bool afterToken, bool beforePreviousInsertions) {
67 unsigned RangeLen;
68 if (!canRemoveRange(range, RangeOffs, RangeLen)) {
69 IsCommitable = false;
70 return false;
71 }
72
74 if ((!afterToken && !canInsert(loc, Offs)) ||
75 ( afterToken && !canInsertAfterToken(loc, Offs, loc))) {
76 IsCommitable = false;
77 return false;
78 }
79
80 if (PPRec &&
81 PPRec->areInDifferentConditionalDirectiveRegion(loc, range.getBegin())) {
82 IsCommitable = false;
83 return false;
84 }
85
86 addInsertFromRange(loc, Offs, RangeOffs, RangeLen, beforePreviousInsertions);
87 return true;
88}
89
92 unsigned Len;
93 if (!canRemoveRange(range, Offs, Len)) {
94 IsCommitable = false;
95 return false;
96 }
97
98 addRemove(range.getBegin(), Offs, Len);
99 return true;
100}
101
103 StringRef after) {
104 bool commitableBefore = insert(range.getBegin(), before, false,
105 true);
106 bool commitableAfter;
107 if (range.isTokenRange())
109 else
110 commitableAfter = insert(range.getEnd(), after);
111
112 return commitableBefore && commitableAfter;
113}
114
116 if (text.empty())
117 return remove(range);
118
120 unsigned Len;
121 if (!canInsert(range.getBegin(), Offs) || !canRemoveRange(range, Offs, Len)) {
122 IsCommitable = false;
123 return false;
124 }
125
126 addRemove(range.getBegin(), Offs, Len);
127 addInsert(range.getBegin(), Offs, text, false);
128 return true;
129}
130
134 unsigned OuterLen;
135 if (!canRemoveRange(range, OuterBegin, OuterLen)) {
136 IsCommitable = false;
137 return false;
138 }
139
141 unsigned InnerLen;
142 if (!canRemoveRange(replacementRange, InnerBegin, InnerLen)) {
143 IsCommitable = false;
144 return false;
145 }
146
149 if (OuterBegin.getFID() != InnerBegin.getFID() ||
150 InnerBegin < OuterBegin ||
151 InnerBegin > OuterEnd ||
152 InnerEnd > OuterEnd) {
153 IsCommitable = false;
154 return false;
155 }
156
157 addRemove(range.getBegin(),
159 addRemove(replacementRange.getEnd(),
161 return true;
162}
163
165 StringRef replacementText) {
166 if (text.empty() || replacementText.empty())
167 return true;
168
170 unsigned Len;
171 if (!canReplaceText(loc, replacementText, Offs, Len)) {
172 IsCommitable = false;
173 return false;
174 }
175
176 addRemove(loc, Offs, Len);
177 addInsert(loc, Offs, text, false);
178 return true;
179}
180
182 bool beforePreviousInsertions) {
183 if (text.empty())
184 return;
185
186 Edit data;
188 data.OrigLoc = OrigLoc;
189 data.Offset = Offs;
190 data.Text = text.copy(StrAlloc);
191 data.BeforePrev = beforePreviousInsertions;
192 CachedEdits.push_back(data);
193}
194
196 FileOffset RangeOffs, unsigned RangeLen,
197 bool beforePreviousInsertions) {
198 if (RangeLen == 0)
199 return;
200
201 Edit data;
203 data.OrigLoc = OrigLoc;
204 data.Offset = Offs;
205 data.InsertFromRangeOffs = RangeOffs;
206 data.Length = RangeLen;
207 data.BeforePrev = beforePreviousInsertions;
208 CachedEdits.push_back(data);
209}
210
213 if (Len == 0)
214 return;
215
216 Edit data;
218 data.OrigLoc = OrigLoc;
219 data.Offset = Offs;
220 data.Length = Len;
221 CachedEdits.push_back(data);
222}
223
224bool Commit::canInsert(SourceLocation loc, FileOffset &offs) {
226 return false;
227
229 isAtStartOfMacroExpansion(loc, &loc);
230
231 const SourceManager &SM = SourceMgr;
232 loc = SM.getTopMacroCallerLoc(loc);
233
235 if (!isAtStartOfMacroExpansion(loc, &loc))
236 return false;
237
238 if (SM.isInSystemHeader(loc))
239 return false;
240
242 if (locInfo.first.isInvalid())
243 return false;
244 offs = FileOffset(locInfo.first, locInfo.second);
245 return canInsertInOffset(loc, offs);
246}
247
248bool Commit::canInsertAfterToken(SourceLocation loc, FileOffset &offs,
249 SourceLocation &AfterLoc) {
251
252 return false;
253
254 SourceLocation spellLoc = SourceMgr.getSpellingLoc(loc);
257
259 isAtEndOfMacroExpansion(loc, &loc);
260
261 const SourceManager &SM = SourceMgr;
262 loc = SM.getTopMacroCallerLoc(loc);
263
265 if (!isAtEndOfMacroExpansion(loc, &loc))
266 return false;
267
268 if (SM.isInSystemHeader(loc))
269 return false;
270
273 return false;
274
276 if (locInfo.first.isInvalid())
277 return false;
278 offs = FileOffset(locInfo.first, locInfo.second);
279 return canInsertInOffset(loc, offs);
280}
281
282bool Commit::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
283 for (const auto &act : CachedEdits)
285 if (act.Offset.getFID() == Offs.getFID() &&
286 Offs > act.Offset && Offs < act.Offset.getWithOffset(act.Length))
287 return false;
288 }
289
290 if (!Editor)
291 return true;
292 return Editor->canInsertInOffset(OrigLoc, Offs);
293}
294
295bool Commit::canRemoveRange(CharSourceRange range,
297 const SourceManager &SM = SourceMgr;
299 if (range.isInvalid())
300 return false;
301
302 if (range.getBegin().isMacroID() || range.getEnd().isMacroID())
303 return false;
304 if (SM.isInSystemHeader(range.getBegin()) ||
305 SM.isInSystemHeader(range.getEnd()))
306 return false;
307
308 if (PPRec && PPRec->rangeIntersectsConditionalDirective(range.getAsRange()))
309 return false;
310
313 if (beginInfo.first != endInfo.first ||
314 beginInfo.second > endInfo.second)
315 return false;
316
317 Offs = FileOffset(beginInfo.first, beginInfo.second);
318 Len = endInfo.second - beginInfo.second;
319 return true;
320}
321
322bool Commit::canReplaceText(SourceLocation loc, StringRef text,
324 assert(.empty());
325
326 if (!canInsert(loc, Offs))
327 return false;
328
329
330 bool invalidTemp = false;
331 StringRef file = SourceMgr.getBufferData(Offs.getFID(), &invalidTemp);
332 if (invalidTemp)
333 return false;
334
335 Len = text.size();
336 return file.substr(Offs.getOffset()).starts_with(text);
337}
338
339bool Commit::isAtStartOfMacroExpansion(SourceLocation loc,
340 SourceLocation *MacroBegin) const {
342}
343
344bool Commit::isAtEndOfMacroExpansion(SourceLocation loc,
345 SourceLocation *MacroEnd) const {
347}
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Represents a character-granular source range.
static CharSourceRange getCharRange(SourceRange R)
SourceLocation getEnd() const
static bool isAtStartOfMacroExpansion(SourceLocation loc, const SourceManager &SM, const LangOptions &LangOpts, SourceLocation *MacroBegin=nullptr)
Returns true if the given MacroID location points at the first token of the macro expansion.
static bool isAtEndOfMacroExpansion(SourceLocation loc, const SourceManager &SM, const LangOptions &LangOpts, SourceLocation *MacroEnd=nullptr)
Returns true if the given MacroID location points at the last token of the macro expansion.
static CharSourceRange makeFileCharRange(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts)
Accepts a range and returns a character range with file locations.
static unsigned MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
MeasureTokenLength - Relex the token at the specified location and return its length in bytes in the ...
static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts)
Computes the source location just past the end of the token at this source location.
Encodes a location in the source.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
bool replaceWithInner(CharSourceRange range, CharSourceRange innerRange)
Definition Commit.cpp:131
bool insertWrap(StringRef before, CharSourceRange range, StringRef after)
Definition Commit.cpp:102
bool insertFromRange(SourceLocation loc, CharSourceRange range, bool afterToken=false, bool beforePreviousInsertions=false)
Definition Commit.cpp:63
bool insert(SourceLocation loc, StringRef text, bool afterToken=false, bool beforePreviousInsertions=false)
Definition Commit.cpp:47
Commit(EditedSource &Editor)
Definition Commit.cpp:42
bool insertAfterToken(SourceLocation loc, StringRef text, bool beforePreviousInsertions=false)
bool remove(CharSourceRange range)
Definition Commit.cpp:90
bool replace(CharSourceRange range, StringRef text)
Definition Commit.cpp:115
bool replaceText(SourceLocation loc, StringRef text, StringRef replacementText)
Definition Commit.cpp:164
FileOffset getWithOffset(unsigned offset) const
unsigned getOffset() const
RangeSelector range(RangeSelector Begin, RangeSelector End)
DEPRECATED. Use enclose.
The JSON file list parser is used to communicate input to InstallAPI.
std::pair< FileID, unsigned > FileIDAndOffset
SourceLocation getFileLocation(SourceManager &SM) const
Definition Commit.cpp:23
CharSourceRange getFileRange(SourceManager &SM) const
Definition Commit.cpp:30
FileOffset InsertFromRangeOffs
CharSourceRange getInsertFromRange(SourceManager &SM) const
Definition Commit.cpp:35