1f4a2713aSLionel Sambuc //===----- Commit.cpp - A unit of edits -----------------------------------===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc 
10f4a2713aSLionel Sambuc #include "clang/Edit/Commit.h"
11f4a2713aSLionel Sambuc #include "clang/Basic/SourceManager.h"
12f4a2713aSLionel Sambuc #include "clang/Edit/EditedSource.h"
13f4a2713aSLionel Sambuc #include "clang/Lex/Lexer.h"
14f4a2713aSLionel Sambuc #include "clang/Lex/PPConditionalDirectiveRecord.h"
15f4a2713aSLionel Sambuc 
16f4a2713aSLionel Sambuc using namespace clang;
17f4a2713aSLionel Sambuc using namespace edit;
18f4a2713aSLionel Sambuc 
getFileLocation(SourceManager & SM) const19f4a2713aSLionel Sambuc SourceLocation Commit::Edit::getFileLocation(SourceManager &SM) const {
20f4a2713aSLionel Sambuc   SourceLocation Loc = SM.getLocForStartOfFile(Offset.getFID());
21f4a2713aSLionel Sambuc   Loc = Loc.getLocWithOffset(Offset.getOffset());
22f4a2713aSLionel Sambuc   assert(Loc.isFileID());
23f4a2713aSLionel Sambuc   return Loc;
24f4a2713aSLionel Sambuc }
25f4a2713aSLionel Sambuc 
getFileRange(SourceManager & SM) const26f4a2713aSLionel Sambuc CharSourceRange Commit::Edit::getFileRange(SourceManager &SM) const {
27f4a2713aSLionel Sambuc   SourceLocation Loc = getFileLocation(SM);
28f4a2713aSLionel Sambuc   return CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(Length));
29f4a2713aSLionel Sambuc }
30f4a2713aSLionel Sambuc 
getInsertFromRange(SourceManager & SM) const31f4a2713aSLionel Sambuc CharSourceRange Commit::Edit::getInsertFromRange(SourceManager &SM) const {
32f4a2713aSLionel Sambuc   SourceLocation Loc = SM.getLocForStartOfFile(InsertFromRangeOffs.getFID());
33f4a2713aSLionel Sambuc   Loc = Loc.getLocWithOffset(InsertFromRangeOffs.getOffset());
34f4a2713aSLionel Sambuc   assert(Loc.isFileID());
35f4a2713aSLionel Sambuc   return CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(Length));
36f4a2713aSLionel Sambuc }
37f4a2713aSLionel Sambuc 
Commit(EditedSource & Editor)38f4a2713aSLionel Sambuc Commit::Commit(EditedSource &Editor)
39f4a2713aSLionel Sambuc   : SourceMgr(Editor.getSourceManager()), LangOpts(Editor.getLangOpts()),
40f4a2713aSLionel Sambuc     PPRec(Editor.getPPCondDirectiveRecord()),
41*0a6a1f1dSLionel Sambuc     Editor(&Editor), IsCommitable(true) { }
42f4a2713aSLionel Sambuc 
insert(SourceLocation loc,StringRef text,bool afterToken,bool beforePreviousInsertions)43f4a2713aSLionel Sambuc bool Commit::insert(SourceLocation loc, StringRef text,
44f4a2713aSLionel Sambuc                     bool afterToken, bool beforePreviousInsertions) {
45f4a2713aSLionel Sambuc   if (text.empty())
46f4a2713aSLionel Sambuc     return true;
47f4a2713aSLionel Sambuc 
48f4a2713aSLionel Sambuc   FileOffset Offs;
49f4a2713aSLionel Sambuc   if ((!afterToken && !canInsert(loc, Offs)) ||
50f4a2713aSLionel Sambuc       ( afterToken && !canInsertAfterToken(loc, Offs, loc))) {
51f4a2713aSLionel Sambuc     IsCommitable = false;
52f4a2713aSLionel Sambuc     return false;
53f4a2713aSLionel Sambuc   }
54f4a2713aSLionel Sambuc 
55f4a2713aSLionel Sambuc   addInsert(loc, Offs, text, beforePreviousInsertions);
56f4a2713aSLionel Sambuc   return true;
57f4a2713aSLionel Sambuc }
58f4a2713aSLionel Sambuc 
insertFromRange(SourceLocation loc,CharSourceRange range,bool afterToken,bool beforePreviousInsertions)59f4a2713aSLionel Sambuc bool Commit::insertFromRange(SourceLocation loc,
60f4a2713aSLionel Sambuc                              CharSourceRange range,
61f4a2713aSLionel Sambuc                              bool afterToken, bool beforePreviousInsertions) {
62f4a2713aSLionel Sambuc   FileOffset RangeOffs;
63f4a2713aSLionel Sambuc   unsigned RangeLen;
64f4a2713aSLionel Sambuc   if (!canRemoveRange(range, RangeOffs, RangeLen)) {
65f4a2713aSLionel Sambuc     IsCommitable = false;
66f4a2713aSLionel Sambuc     return false;
67f4a2713aSLionel Sambuc   }
68f4a2713aSLionel Sambuc 
69f4a2713aSLionel Sambuc   FileOffset Offs;
70f4a2713aSLionel Sambuc   if ((!afterToken && !canInsert(loc, Offs)) ||
71f4a2713aSLionel Sambuc       ( afterToken && !canInsertAfterToken(loc, Offs, loc))) {
72f4a2713aSLionel Sambuc     IsCommitable = false;
73f4a2713aSLionel Sambuc     return false;
74f4a2713aSLionel Sambuc   }
75f4a2713aSLionel Sambuc 
76f4a2713aSLionel Sambuc   if (PPRec &&
77f4a2713aSLionel Sambuc       PPRec->areInDifferentConditionalDirectiveRegion(loc, range.getBegin())) {
78f4a2713aSLionel Sambuc     IsCommitable = false;
79f4a2713aSLionel Sambuc     return false;
80f4a2713aSLionel Sambuc   }
81f4a2713aSLionel Sambuc 
82f4a2713aSLionel Sambuc   addInsertFromRange(loc, Offs, RangeOffs, RangeLen, beforePreviousInsertions);
83f4a2713aSLionel Sambuc   return true;
84f4a2713aSLionel Sambuc }
85f4a2713aSLionel Sambuc 
remove(CharSourceRange range)86f4a2713aSLionel Sambuc bool Commit::remove(CharSourceRange range) {
87f4a2713aSLionel Sambuc   FileOffset Offs;
88f4a2713aSLionel Sambuc   unsigned Len;
89f4a2713aSLionel Sambuc   if (!canRemoveRange(range, Offs, Len)) {
90f4a2713aSLionel Sambuc     IsCommitable = false;
91f4a2713aSLionel Sambuc     return false;
92f4a2713aSLionel Sambuc   }
93f4a2713aSLionel Sambuc 
94f4a2713aSLionel Sambuc   addRemove(range.getBegin(), Offs, Len);
95f4a2713aSLionel Sambuc   return true;
96f4a2713aSLionel Sambuc }
97f4a2713aSLionel Sambuc 
insertWrap(StringRef before,CharSourceRange range,StringRef after)98f4a2713aSLionel Sambuc bool Commit::insertWrap(StringRef before, CharSourceRange range,
99f4a2713aSLionel Sambuc                         StringRef after) {
100f4a2713aSLionel Sambuc   bool commitableBefore = insert(range.getBegin(), before, /*afterToken=*/false,
101f4a2713aSLionel Sambuc                                  /*beforePreviousInsertions=*/true);
102f4a2713aSLionel Sambuc   bool commitableAfter;
103f4a2713aSLionel Sambuc   if (range.isTokenRange())
104f4a2713aSLionel Sambuc     commitableAfter = insertAfterToken(range.getEnd(), after);
105f4a2713aSLionel Sambuc   else
106f4a2713aSLionel Sambuc     commitableAfter = insert(range.getEnd(), after);
107f4a2713aSLionel Sambuc 
108f4a2713aSLionel Sambuc   return commitableBefore && commitableAfter;
109f4a2713aSLionel Sambuc }
110f4a2713aSLionel Sambuc 
replace(CharSourceRange range,StringRef text)111f4a2713aSLionel Sambuc bool Commit::replace(CharSourceRange range, StringRef text) {
112f4a2713aSLionel Sambuc   if (text.empty())
113f4a2713aSLionel Sambuc     return remove(range);
114f4a2713aSLionel Sambuc 
115f4a2713aSLionel Sambuc   FileOffset Offs;
116f4a2713aSLionel Sambuc   unsigned Len;
117f4a2713aSLionel Sambuc   if (!canInsert(range.getBegin(), Offs) || !canRemoveRange(range, Offs, Len)) {
118f4a2713aSLionel Sambuc     IsCommitable = false;
119f4a2713aSLionel Sambuc     return false;
120f4a2713aSLionel Sambuc   }
121f4a2713aSLionel Sambuc 
122f4a2713aSLionel Sambuc   addRemove(range.getBegin(), Offs, Len);
123f4a2713aSLionel Sambuc   addInsert(range.getBegin(), Offs, text, false);
124f4a2713aSLionel Sambuc   return true;
125f4a2713aSLionel Sambuc }
126f4a2713aSLionel Sambuc 
replaceWithInner(CharSourceRange range,CharSourceRange replacementRange)127f4a2713aSLionel Sambuc bool Commit::replaceWithInner(CharSourceRange range,
128f4a2713aSLionel Sambuc                               CharSourceRange replacementRange) {
129f4a2713aSLionel Sambuc   FileOffset OuterBegin;
130f4a2713aSLionel Sambuc   unsigned OuterLen;
131f4a2713aSLionel Sambuc   if (!canRemoveRange(range, OuterBegin, OuterLen)) {
132f4a2713aSLionel Sambuc     IsCommitable = false;
133f4a2713aSLionel Sambuc     return false;
134f4a2713aSLionel Sambuc   }
135f4a2713aSLionel Sambuc 
136f4a2713aSLionel Sambuc   FileOffset InnerBegin;
137f4a2713aSLionel Sambuc   unsigned InnerLen;
138f4a2713aSLionel Sambuc   if (!canRemoveRange(replacementRange, InnerBegin, InnerLen)) {
139f4a2713aSLionel Sambuc     IsCommitable = false;
140f4a2713aSLionel Sambuc     return false;
141f4a2713aSLionel Sambuc   }
142f4a2713aSLionel Sambuc 
143f4a2713aSLionel Sambuc   FileOffset OuterEnd = OuterBegin.getWithOffset(OuterLen);
144f4a2713aSLionel Sambuc   FileOffset InnerEnd = InnerBegin.getWithOffset(InnerLen);
145f4a2713aSLionel Sambuc   if (OuterBegin.getFID() != InnerBegin.getFID() ||
146f4a2713aSLionel Sambuc       InnerBegin < OuterBegin ||
147f4a2713aSLionel Sambuc       InnerBegin > OuterEnd ||
148f4a2713aSLionel Sambuc       InnerEnd > OuterEnd) {
149f4a2713aSLionel Sambuc     IsCommitable = false;
150f4a2713aSLionel Sambuc     return false;
151f4a2713aSLionel Sambuc   }
152f4a2713aSLionel Sambuc 
153f4a2713aSLionel Sambuc   addRemove(range.getBegin(),
154f4a2713aSLionel Sambuc             OuterBegin, InnerBegin.getOffset() - OuterBegin.getOffset());
155f4a2713aSLionel Sambuc   addRemove(replacementRange.getEnd(),
156f4a2713aSLionel Sambuc             InnerEnd, OuterEnd.getOffset() - InnerEnd.getOffset());
157f4a2713aSLionel Sambuc   return true;
158f4a2713aSLionel Sambuc }
159f4a2713aSLionel Sambuc 
replaceText(SourceLocation loc,StringRef text,StringRef replacementText)160f4a2713aSLionel Sambuc bool Commit::replaceText(SourceLocation loc, StringRef text,
161f4a2713aSLionel Sambuc                          StringRef replacementText) {
162f4a2713aSLionel Sambuc   if (text.empty() || replacementText.empty())
163f4a2713aSLionel Sambuc     return true;
164f4a2713aSLionel Sambuc 
165f4a2713aSLionel Sambuc   FileOffset Offs;
166f4a2713aSLionel Sambuc   unsigned Len;
167f4a2713aSLionel Sambuc   if (!canReplaceText(loc, replacementText, Offs, Len)) {
168f4a2713aSLionel Sambuc     IsCommitable = false;
169f4a2713aSLionel Sambuc     return false;
170f4a2713aSLionel Sambuc   }
171f4a2713aSLionel Sambuc 
172f4a2713aSLionel Sambuc   addRemove(loc, Offs, Len);
173f4a2713aSLionel Sambuc   addInsert(loc, Offs, text, false);
174f4a2713aSLionel Sambuc   return true;
175f4a2713aSLionel Sambuc }
176f4a2713aSLionel Sambuc 
addInsert(SourceLocation OrigLoc,FileOffset Offs,StringRef text,bool beforePreviousInsertions)177f4a2713aSLionel Sambuc void Commit::addInsert(SourceLocation OrigLoc, FileOffset Offs, StringRef text,
178f4a2713aSLionel Sambuc                        bool beforePreviousInsertions) {
179f4a2713aSLionel Sambuc   if (text.empty())
180f4a2713aSLionel Sambuc     return;
181f4a2713aSLionel Sambuc 
182f4a2713aSLionel Sambuc   Edit data;
183f4a2713aSLionel Sambuc   data.Kind = Act_Insert;
184f4a2713aSLionel Sambuc   data.OrigLoc = OrigLoc;
185f4a2713aSLionel Sambuc   data.Offset = Offs;
186f4a2713aSLionel Sambuc   data.Text = copyString(text);
187f4a2713aSLionel Sambuc   data.BeforePrev = beforePreviousInsertions;
188f4a2713aSLionel Sambuc   CachedEdits.push_back(data);
189f4a2713aSLionel Sambuc }
190f4a2713aSLionel Sambuc 
addInsertFromRange(SourceLocation OrigLoc,FileOffset Offs,FileOffset RangeOffs,unsigned RangeLen,bool beforePreviousInsertions)191f4a2713aSLionel Sambuc void Commit::addInsertFromRange(SourceLocation OrigLoc, FileOffset Offs,
192f4a2713aSLionel Sambuc                                 FileOffset RangeOffs, unsigned RangeLen,
193f4a2713aSLionel Sambuc                                 bool beforePreviousInsertions) {
194f4a2713aSLionel Sambuc   if (RangeLen == 0)
195f4a2713aSLionel Sambuc     return;
196f4a2713aSLionel Sambuc 
197f4a2713aSLionel Sambuc   Edit data;
198f4a2713aSLionel Sambuc   data.Kind = Act_InsertFromRange;
199f4a2713aSLionel Sambuc   data.OrigLoc = OrigLoc;
200f4a2713aSLionel Sambuc   data.Offset = Offs;
201f4a2713aSLionel Sambuc   data.InsertFromRangeOffs = RangeOffs;
202f4a2713aSLionel Sambuc   data.Length = RangeLen;
203f4a2713aSLionel Sambuc   data.BeforePrev = beforePreviousInsertions;
204f4a2713aSLionel Sambuc   CachedEdits.push_back(data);
205f4a2713aSLionel Sambuc }
206f4a2713aSLionel Sambuc 
addRemove(SourceLocation OrigLoc,FileOffset Offs,unsigned Len)207f4a2713aSLionel Sambuc void Commit::addRemove(SourceLocation OrigLoc,
208f4a2713aSLionel Sambuc                        FileOffset Offs, unsigned Len) {
209f4a2713aSLionel Sambuc   if (Len == 0)
210f4a2713aSLionel Sambuc     return;
211f4a2713aSLionel Sambuc 
212f4a2713aSLionel Sambuc   Edit data;
213f4a2713aSLionel Sambuc   data.Kind = Act_Remove;
214f4a2713aSLionel Sambuc   data.OrigLoc = OrigLoc;
215f4a2713aSLionel Sambuc   data.Offset = Offs;
216f4a2713aSLionel Sambuc   data.Length = Len;
217f4a2713aSLionel Sambuc   CachedEdits.push_back(data);
218f4a2713aSLionel Sambuc }
219f4a2713aSLionel Sambuc 
canInsert(SourceLocation loc,FileOffset & offs)220f4a2713aSLionel Sambuc bool Commit::canInsert(SourceLocation loc, FileOffset &offs) {
221f4a2713aSLionel Sambuc   if (loc.isInvalid())
222f4a2713aSLionel Sambuc     return false;
223f4a2713aSLionel Sambuc 
224f4a2713aSLionel Sambuc   if (loc.isMacroID())
225f4a2713aSLionel Sambuc     isAtStartOfMacroExpansion(loc, &loc);
226f4a2713aSLionel Sambuc 
227f4a2713aSLionel Sambuc   const SourceManager &SM = SourceMgr;
228f4a2713aSLionel Sambuc   while (SM.isMacroArgExpansion(loc))
229f4a2713aSLionel Sambuc     loc = SM.getImmediateSpellingLoc(loc);
230f4a2713aSLionel Sambuc 
231f4a2713aSLionel Sambuc   if (loc.isMacroID())
232f4a2713aSLionel Sambuc     if (!isAtStartOfMacroExpansion(loc, &loc))
233f4a2713aSLionel Sambuc       return false;
234f4a2713aSLionel Sambuc 
235*0a6a1f1dSLionel Sambuc   if (SM.isInSystemHeader(loc))
236f4a2713aSLionel Sambuc     return false;
237f4a2713aSLionel Sambuc 
238f4a2713aSLionel Sambuc   std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
239f4a2713aSLionel Sambuc   if (locInfo.first.isInvalid())
240f4a2713aSLionel Sambuc     return false;
241f4a2713aSLionel Sambuc   offs = FileOffset(locInfo.first, locInfo.second);
242f4a2713aSLionel Sambuc   return canInsertInOffset(loc, offs);
243f4a2713aSLionel Sambuc }
244f4a2713aSLionel Sambuc 
canInsertAfterToken(SourceLocation loc,FileOffset & offs,SourceLocation & AfterLoc)245f4a2713aSLionel Sambuc bool Commit::canInsertAfterToken(SourceLocation loc, FileOffset &offs,
246f4a2713aSLionel Sambuc                                  SourceLocation &AfterLoc) {
247f4a2713aSLionel Sambuc   if (loc.isInvalid())
248f4a2713aSLionel Sambuc 
249f4a2713aSLionel Sambuc     return false;
250f4a2713aSLionel Sambuc 
251f4a2713aSLionel Sambuc   SourceLocation spellLoc = SourceMgr.getSpellingLoc(loc);
252f4a2713aSLionel Sambuc   unsigned tokLen = Lexer::MeasureTokenLength(spellLoc, SourceMgr, LangOpts);
253f4a2713aSLionel Sambuc   AfterLoc = loc.getLocWithOffset(tokLen);
254f4a2713aSLionel Sambuc 
255f4a2713aSLionel Sambuc   if (loc.isMacroID())
256f4a2713aSLionel Sambuc     isAtEndOfMacroExpansion(loc, &loc);
257f4a2713aSLionel Sambuc 
258f4a2713aSLionel Sambuc   const SourceManager &SM = SourceMgr;
259f4a2713aSLionel Sambuc   while (SM.isMacroArgExpansion(loc))
260f4a2713aSLionel Sambuc     loc = SM.getImmediateSpellingLoc(loc);
261f4a2713aSLionel Sambuc 
262f4a2713aSLionel Sambuc   if (loc.isMacroID())
263f4a2713aSLionel Sambuc     if (!isAtEndOfMacroExpansion(loc, &loc))
264f4a2713aSLionel Sambuc       return false;
265f4a2713aSLionel Sambuc 
266*0a6a1f1dSLionel Sambuc   if (SM.isInSystemHeader(loc))
267f4a2713aSLionel Sambuc     return false;
268f4a2713aSLionel Sambuc 
269f4a2713aSLionel Sambuc   loc = Lexer::getLocForEndOfToken(loc, 0, SourceMgr, LangOpts);
270f4a2713aSLionel Sambuc   if (loc.isInvalid())
271f4a2713aSLionel Sambuc     return false;
272f4a2713aSLionel Sambuc 
273f4a2713aSLionel Sambuc   std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
274f4a2713aSLionel Sambuc   if (locInfo.first.isInvalid())
275f4a2713aSLionel Sambuc     return false;
276f4a2713aSLionel Sambuc   offs = FileOffset(locInfo.first, locInfo.second);
277f4a2713aSLionel Sambuc   return canInsertInOffset(loc, offs);
278f4a2713aSLionel Sambuc }
279f4a2713aSLionel Sambuc 
canInsertInOffset(SourceLocation OrigLoc,FileOffset Offs)280f4a2713aSLionel Sambuc bool Commit::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
281f4a2713aSLionel Sambuc   for (unsigned i = 0, e = CachedEdits.size(); i != e; ++i) {
282f4a2713aSLionel Sambuc     Edit &act = CachedEdits[i];
283f4a2713aSLionel Sambuc     if (act.Kind == Act_Remove) {
284f4a2713aSLionel Sambuc       if (act.Offset.getFID() == Offs.getFID() &&
285f4a2713aSLionel Sambuc           Offs > act.Offset && Offs < act.Offset.getWithOffset(act.Length))
286f4a2713aSLionel Sambuc         return false; // position has been removed.
287f4a2713aSLionel Sambuc     }
288f4a2713aSLionel Sambuc   }
289f4a2713aSLionel Sambuc 
290f4a2713aSLionel Sambuc   if (!Editor)
291f4a2713aSLionel Sambuc     return true;
292f4a2713aSLionel Sambuc   return Editor->canInsertInOffset(OrigLoc, Offs);
293f4a2713aSLionel Sambuc }
294f4a2713aSLionel Sambuc 
canRemoveRange(CharSourceRange range,FileOffset & Offs,unsigned & Len)295f4a2713aSLionel Sambuc bool Commit::canRemoveRange(CharSourceRange range,
296f4a2713aSLionel Sambuc                             FileOffset &Offs, unsigned &Len) {
297f4a2713aSLionel Sambuc   const SourceManager &SM = SourceMgr;
298f4a2713aSLionel Sambuc   range = Lexer::makeFileCharRange(range, SM, LangOpts);
299f4a2713aSLionel Sambuc   if (range.isInvalid())
300f4a2713aSLionel Sambuc     return false;
301f4a2713aSLionel Sambuc 
302f4a2713aSLionel Sambuc   if (range.getBegin().isMacroID() || range.getEnd().isMacroID())
303f4a2713aSLionel Sambuc     return false;
304*0a6a1f1dSLionel Sambuc   if (SM.isInSystemHeader(range.getBegin()) ||
305*0a6a1f1dSLionel Sambuc       SM.isInSystemHeader(range.getEnd()))
306f4a2713aSLionel Sambuc     return false;
307f4a2713aSLionel Sambuc 
308f4a2713aSLionel Sambuc   if (PPRec && PPRec->rangeIntersectsConditionalDirective(range.getAsRange()))
309f4a2713aSLionel Sambuc     return false;
310f4a2713aSLionel Sambuc 
311f4a2713aSLionel Sambuc   std::pair<FileID, unsigned> beginInfo = SM.getDecomposedLoc(range.getBegin());
312f4a2713aSLionel Sambuc   std::pair<FileID, unsigned> endInfo = SM.getDecomposedLoc(range.getEnd());
313f4a2713aSLionel Sambuc   if (beginInfo.first != endInfo.first ||
314f4a2713aSLionel Sambuc       beginInfo.second > endInfo.second)
315f4a2713aSLionel Sambuc     return false;
316f4a2713aSLionel Sambuc 
317f4a2713aSLionel Sambuc   Offs = FileOffset(beginInfo.first, beginInfo.second);
318f4a2713aSLionel Sambuc   Len = endInfo.second - beginInfo.second;
319f4a2713aSLionel Sambuc   return true;
320f4a2713aSLionel Sambuc }
321f4a2713aSLionel Sambuc 
canReplaceText(SourceLocation loc,StringRef text,FileOffset & Offs,unsigned & Len)322f4a2713aSLionel Sambuc bool Commit::canReplaceText(SourceLocation loc, StringRef text,
323f4a2713aSLionel Sambuc                             FileOffset &Offs, unsigned &Len) {
324f4a2713aSLionel Sambuc   assert(!text.empty());
325f4a2713aSLionel Sambuc 
326f4a2713aSLionel Sambuc   if (!canInsert(loc, Offs))
327f4a2713aSLionel Sambuc     return false;
328f4a2713aSLionel Sambuc 
329f4a2713aSLionel Sambuc   // Try to load the file buffer.
330f4a2713aSLionel Sambuc   bool invalidTemp = false;
331f4a2713aSLionel Sambuc   StringRef file = SourceMgr.getBufferData(Offs.getFID(), &invalidTemp);
332f4a2713aSLionel Sambuc   if (invalidTemp)
333f4a2713aSLionel Sambuc     return false;
334f4a2713aSLionel Sambuc 
335f4a2713aSLionel Sambuc   Len = text.size();
336f4a2713aSLionel Sambuc   return file.substr(Offs.getOffset()).startswith(text);
337f4a2713aSLionel Sambuc }
338f4a2713aSLionel Sambuc 
isAtStartOfMacroExpansion(SourceLocation loc,SourceLocation * MacroBegin) const339f4a2713aSLionel Sambuc bool Commit::isAtStartOfMacroExpansion(SourceLocation loc,
340f4a2713aSLionel Sambuc                                        SourceLocation *MacroBegin) const {
341f4a2713aSLionel Sambuc   return Lexer::isAtStartOfMacroExpansion(loc, SourceMgr, LangOpts, MacroBegin);
342f4a2713aSLionel Sambuc }
isAtEndOfMacroExpansion(SourceLocation loc,SourceLocation * MacroEnd) const343f4a2713aSLionel Sambuc bool Commit::isAtEndOfMacroExpansion(SourceLocation loc,
344f4a2713aSLionel Sambuc                                      SourceLocation *MacroEnd) const {
345f4a2713aSLionel Sambuc   return Lexer::isAtEndOfMacroExpansion(loc, SourceMgr, LangOpts, MacroEnd);
346f4a2713aSLionel Sambuc }
347