]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp
MFC r244628:
[FreeBSD/stable/9.git] / contrib / llvm / tools / clang / lib / Edit / EditedSource.cpp
1 //===----- EditedSource.cpp - Collection of source edits ------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "clang/Edit/EditedSource.h"
11 #include "clang/Edit/Commit.h"
12 #include "clang/Edit/EditsReceiver.h"
13 #include "clang/Lex/Lexer.h"
14 #include "clang/Basic/SourceManager.h"
15 #include "llvm/ADT/SmallString.h"
16 #include "llvm/ADT/Twine.h"
17
18 using namespace clang;
19 using namespace edit;
20
21 void EditsReceiver::remove(CharSourceRange range) {
22   replace(range, StringRef());
23 }
24
25 StringRef EditedSource::copyString(const Twine &twine) {
26   llvm::SmallString<128> Data;
27   return copyString(twine.toStringRef(Data));
28 }
29
30 bool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
31   FileEditsTy::iterator FA = getActionForOffset(Offs);
32   if (FA != FileEdits.end()) {
33     if (FA->first != Offs)
34       return false; // position has been removed.
35   }
36
37   if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
38     SourceLocation
39       DefArgLoc = SourceMgr.getImmediateExpansionRange(OrigLoc).first;
40     SourceLocation
41       ExpLoc = SourceMgr.getImmediateExpansionRange(DefArgLoc).first;
42     llvm::DenseMap<unsigned, SourceLocation>::iterator
43       I = ExpansionToArgMap.find(ExpLoc.getRawEncoding());
44     if (I != ExpansionToArgMap.end() && I->second != DefArgLoc)
45       return false; // Trying to write in a macro argument input that has
46                  // already been written for another argument of the same macro. 
47   }
48
49   return true;
50 }
51
52 bool EditedSource::commitInsert(SourceLocation OrigLoc,
53                                 FileOffset Offs, StringRef text,
54                                 bool beforePreviousInsertions) {
55   if (!canInsertInOffset(OrigLoc, Offs))
56     return false;
57   if (text.empty())
58     return true;
59
60   if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
61     SourceLocation
62       DefArgLoc = SourceMgr.getImmediateExpansionRange(OrigLoc).first;
63     SourceLocation
64       ExpLoc = SourceMgr.getImmediateExpansionRange(DefArgLoc).first;
65     ExpansionToArgMap[ExpLoc.getRawEncoding()] = DefArgLoc;
66   }
67   
68   FileEdit &FA = FileEdits[Offs];
69   if (FA.Text.empty()) {
70     FA.Text = copyString(text);
71     return true;
72   }
73
74   Twine concat;
75   if (beforePreviousInsertions)
76     concat = Twine(text) + FA.Text;
77   else
78     concat = Twine(FA.Text) +  text;
79
80   FA.Text = copyString(concat);
81   return true;
82 }
83
84 bool EditedSource::commitInsertFromRange(SourceLocation OrigLoc,
85                                    FileOffset Offs,
86                                    FileOffset InsertFromRangeOffs, unsigned Len,
87                                    bool beforePreviousInsertions) {
88   if (Len == 0)
89     return true;
90
91   llvm::SmallString<128> StrVec;
92   FileOffset BeginOffs = InsertFromRangeOffs;
93   FileOffset EndOffs = BeginOffs.getWithOffset(Len);
94   FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs);
95   if (I != FileEdits.begin())
96     --I;
97
98   for (; I != FileEdits.end(); ++I) {
99     FileEdit &FA = I->second;
100     FileOffset B = I->first;
101     FileOffset E = B.getWithOffset(FA.RemoveLen);
102
103     if (BeginOffs == B)
104       break;
105
106     if (BeginOffs < E) {
107       if (BeginOffs > B) {
108         BeginOffs = E;
109         ++I;
110       }
111       break;
112     }
113   }
114
115   for (; I != FileEdits.end() && EndOffs > I->first; ++I) {
116     FileEdit &FA = I->second;
117     FileOffset B = I->first;
118     FileOffset E = B.getWithOffset(FA.RemoveLen);
119
120     if (BeginOffs < B) {
121       bool Invalid = false;
122       StringRef text = getSourceText(BeginOffs, B, Invalid);
123       if (Invalid)
124         return false;
125       StrVec += text;
126     }
127     StrVec += FA.Text;
128     BeginOffs = E;
129   }
130
131   if (BeginOffs < EndOffs) {
132     bool Invalid = false;
133     StringRef text = getSourceText(BeginOffs, EndOffs, Invalid);
134     if (Invalid)
135       return false;
136     StrVec += text;
137   }
138
139   return commitInsert(OrigLoc, Offs, StrVec.str(), beforePreviousInsertions);
140 }
141
142 void EditedSource::commitRemove(SourceLocation OrigLoc,
143                                 FileOffset BeginOffs, unsigned Len) {
144   if (Len == 0)
145     return;
146
147   FileOffset EndOffs = BeginOffs.getWithOffset(Len);
148   FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs);
149   if (I != FileEdits.begin())
150     --I;
151
152   for (; I != FileEdits.end(); ++I) {
153     FileEdit &FA = I->second;
154     FileOffset B = I->first;
155     FileOffset E = B.getWithOffset(FA.RemoveLen);
156
157     if (BeginOffs < E)
158       break;
159   }
160
161   FileOffset TopBegin, TopEnd;
162   FileEdit *TopFA = 0;
163
164   if (I == FileEdits.end()) {
165     FileEditsTy::iterator
166       NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit()));
167     NewI->second.RemoveLen = Len;
168     return;
169   }
170
171   FileEdit &FA = I->second;
172   FileOffset B = I->first;
173   FileOffset E = B.getWithOffset(FA.RemoveLen);
174   if (BeginOffs < B) {
175     FileEditsTy::iterator
176       NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit()));
177     TopBegin = BeginOffs;
178     TopEnd = EndOffs;
179     TopFA = &NewI->second;
180     TopFA->RemoveLen = Len;
181   } else {
182     TopBegin = B;
183     TopEnd = E;
184     TopFA = &I->second;
185     if (TopEnd >= EndOffs)
186       return;
187     unsigned diff = EndOffs.getOffset() - TopEnd.getOffset();
188     TopEnd = EndOffs;
189     TopFA->RemoveLen += diff;
190     ++I;
191   }
192
193   while (I != FileEdits.end()) {
194     FileEdit &FA = I->second;
195     FileOffset B = I->first;
196     FileOffset E = B.getWithOffset(FA.RemoveLen);
197
198     if (B >= TopEnd)
199       break;
200
201     if (E <= TopEnd) {
202       FileEdits.erase(I++);
203       continue;
204     }
205
206     if (B < TopEnd) {
207       unsigned diff = E.getOffset() - TopEnd.getOffset();
208       TopEnd = E;
209       TopFA->RemoveLen += diff;
210       FileEdits.erase(I);
211     }
212
213     break;
214   }
215 }
216
217 bool EditedSource::commit(const Commit &commit) {
218   if (!commit.isCommitable())
219     return false;
220
221   for (edit::Commit::edit_iterator
222          I = commit.edit_begin(), E = commit.edit_end(); I != E; ++I) {
223     const edit::Commit::Edit &edit = *I;
224     switch (edit.Kind) {
225     case edit::Commit::Act_Insert:
226       commitInsert(edit.OrigLoc, edit.Offset, edit.Text, edit.BeforePrev);
227       break;
228     case edit::Commit::Act_InsertFromRange:
229       commitInsertFromRange(edit.OrigLoc, edit.Offset,
230                             edit.InsertFromRangeOffs, edit.Length,
231                             edit.BeforePrev);
232       break;
233     case edit::Commit::Act_Remove:
234       commitRemove(edit.OrigLoc, edit.Offset, edit.Length);
235       break;
236     }
237   }
238
239   return true;
240 }
241
242 static void applyRewrite(EditsReceiver &receiver,
243                          StringRef text, FileOffset offs, unsigned len,
244                          const SourceManager &SM) {
245   assert(!offs.getFID().isInvalid());
246   SourceLocation Loc = SM.getLocForStartOfFile(offs.getFID());
247   Loc = Loc.getLocWithOffset(offs.getOffset());
248   assert(Loc.isFileID());
249   CharSourceRange range = CharSourceRange::getCharRange(Loc,
250                                                      Loc.getLocWithOffset(len));
251
252   if (text.empty()) {
253     assert(len);
254     receiver.remove(range);
255     return;
256   }
257
258   if (len)
259     receiver.replace(range, text);
260   else
261     receiver.insert(Loc, text);
262 }
263
264 void EditedSource::applyRewrites(EditsReceiver &receiver) {
265   llvm::SmallString<128> StrVec;
266   FileOffset CurOffs, CurEnd;
267   unsigned CurLen;
268
269   if (FileEdits.empty())
270     return;
271
272   FileEditsTy::iterator I = FileEdits.begin();
273   CurOffs = I->first;
274   StrVec = I->second.Text;
275   CurLen = I->second.RemoveLen;
276   CurEnd = CurOffs.getWithOffset(CurLen);
277   ++I;
278
279   for (FileEditsTy::iterator E = FileEdits.end(); I != E; ++I) {
280     FileOffset offs = I->first;
281     FileEdit act = I->second;
282     assert(offs >= CurEnd);
283
284     if (offs == CurEnd) {
285       StrVec += act.Text;
286       CurLen += act.RemoveLen;
287       CurEnd.getWithOffset(act.RemoveLen);
288       continue;
289     }
290
291     applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr);
292     CurOffs = offs;
293     StrVec = act.Text;
294     CurLen = act.RemoveLen;
295     CurEnd = CurOffs.getWithOffset(CurLen);
296   }
297
298   applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr);
299 }
300
301 void EditedSource::clearRewrites() {
302   FileEdits.clear();
303   StrAlloc.Reset();
304 }
305
306 StringRef EditedSource::getSourceText(FileOffset BeginOffs, FileOffset EndOffs,
307                                       bool &Invalid) {
308   assert(BeginOffs.getFID() == EndOffs.getFID());
309   assert(BeginOffs <= EndOffs);
310   SourceLocation BLoc = SourceMgr.getLocForStartOfFile(BeginOffs.getFID());
311   BLoc = BLoc.getLocWithOffset(BeginOffs.getOffset());
312   assert(BLoc.isFileID());
313   SourceLocation
314     ELoc = BLoc.getLocWithOffset(EndOffs.getOffset() - BeginOffs.getOffset());
315   return Lexer::getSourceText(CharSourceRange::getCharRange(BLoc, ELoc),
316                               SourceMgr, LangOpts, &Invalid);
317 }
318
319 EditedSource::FileEditsTy::iterator
320 EditedSource::getActionForOffset(FileOffset Offs) {
321   FileEditsTy::iterator I = FileEdits.upper_bound(Offs);
322   if (I == FileEdits.begin())
323     return FileEdits.end();
324   --I;
325   FileEdit &FA = I->second;
326   FileOffset B = I->first;
327   FileOffset E = B.getWithOffset(FA.RemoveLen);
328   if (Offs >= B && Offs < E)
329     return I;
330
331   return FileEdits.end();
332 }