]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-before/core refactoring/org/eclipse/jdt/internal/corext/refactoring/util/TextEditUtil.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / core refactoring / org / eclipse / jdt / internal / corext / refactoring / util / TextEditUtil.java
CommitLineData
1b2798f6
EK
1/*******************************************************************************
2 * Copyright (c) 2007, 2008 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11package org.eclipse.jdt.internal.corext.refactoring.util;
12
13import org.eclipse.text.edits.MalformedTreeException;
14import org.eclipse.text.edits.MultiTextEdit;
15import org.eclipse.text.edits.TextEdit;
16
17import org.eclipse.jdt.internal.corext.refactoring.changes.TextChangeCompatibility;
18
19/**
20 * @since 3.4
21 */
22public class TextEditUtil {
23
24 /**
25 * Inserts the <code>edit</code> into <code>parent</code>.
26 *
27 * @param parent the target of the operation
28 * @param edit the edit to insert into parent
29 * @throws MalformedTreeException is edit can't be inserted int parent
30 */
31 public static void insert(TextEdit parent, TextEdit edit) {
32 TextChangeCompatibility.insert(parent, edit);
33 }
34
35 /**
36 * Returns true if the given <code>edit</code> is minimal.
37 * <p>
38 * That is if:
39 * <ul>
40 * <li><b>true</b> if <code>edit</code> is a leaf</li>
41 * <li>if <code>edit</code> is a inner node then <b>true</b> if
42 * <ul>
43 * <li><code>edit</code> has same size as all its children</li>
44 * <li><code>isPacked</code> is <b>true</b> for all children</li>
45 * </ul>
46 * </li>
47 * </ul>
48 * </p>
49 *
50 * @param edit the edit to verify
51 * @return true if edit is minimal
52 * @since 3.4
53 */
54 public static boolean isPacked(TextEdit edit) {
55 if (!(edit instanceof MultiTextEdit))
56 return true;
57
58 if (!edit.hasChildren())
59 return true;
60
61 TextEdit[] children= edit.getChildren();
62 if (edit.getOffset() != children[0].getOffset())
63 return false;
64
65 if (edit.getExclusiveEnd() != children[children.length - 1].getExclusiveEnd())
66 return false;
67
68 for (int i= 0; i < children.length; i++) {
69 if (!isPacked(children[i]))
70 return false;
71 }
72
73 return true;
74 }
75
76 /**
77 * Degenerates the given edit tree into a list.<br>
78 * All nodes of the result are leafs.<br>
79 * <strong>The given edit is modified and can no longer be used.</strong>
80 *
81 * @param edit the edit tree to flatten
82 * @return a list of edits
83 * @since 3.4
84 */
85 public static MultiTextEdit flatten(TextEdit edit) {
86 MultiTextEdit result= new MultiTextEdit();
87 flatten(edit, result);
88 return result;
89 }
90
91 private static void flatten(TextEdit edit, MultiTextEdit result) {
92 if (!edit.hasChildren()) {
93 result.addChild(edit);
94 } else {
95 TextEdit[] children= edit.getChildren();
96 for (int i= 0; i < children.length; i++) {
97 TextEdit child= children[i];
98 child.getParent().removeChild(0);
99 flatten(child, result);
100 }
101 }
102 }
103
104 /**
105 * Does any node in <code>edit1</code> overlap with any other node
106 * in <code>edit2</code>.
107 * <p>If this returns true then the two edit trees can be merged into one.</p>
108 *
109 * @param edit1 the edit to compare against edit2
110 * @param edit2 the edit to compare against edit1
111 * @return true of no node overlaps with any other node
112 * @since 3.4
113 */
114 public static boolean overlaps(TextEdit edit1, TextEdit edit2) {
115 if (edit1 instanceof MultiTextEdit && edit2 instanceof MultiTextEdit) {
116 MultiTextEdit multiTextEdit1= (MultiTextEdit)edit1;
117 if (!multiTextEdit1.hasChildren())
118 return false;
119
120 MultiTextEdit multiTextEdit2= (MultiTextEdit)edit2;
121 if (!multiTextEdit2.hasChildren())
122 return false;
123
124 TextEdit[] children1= multiTextEdit1.getChildren();
125 TextEdit[] children2= multiTextEdit2.getChildren();
126
127 int i1= 0;
128 int i2= 0;
129 while (i1 < children1.length && i2 < children2.length) {
130 while (children1[i1].getExclusiveEnd() < children2[i2].getOffset()) {
131 i1++;
132 if (i1 >= children1.length)
133 return false;
134 }
135 while (children2[i2].getExclusiveEnd() < children1[i1].getOffset()) {
136 i2++;
137 if (i2 >= children2.length)
138 return false;
139 }
140
141 if (children1[i1].getExclusiveEnd() < children2[i2].getOffset())
142 continue;
143
144 if (overlaps(children1[i1], children2[i2]))
145 return true;
146
147 int mergeEnd= Math.max(children1[i1].getExclusiveEnd(), children2[i2].getExclusiveEnd());
148
149 i1++;
150 i2++;
151
152 if (i1 < children1.length && children1[i1].getOffset() < mergeEnd) {
153 return true;
154 }
155 if (i2 < children2.length && children2[i2].getOffset() < mergeEnd) {
156 return true;
157 }
158 }
159
160 return false;
161 } else if (edit1 instanceof MultiTextEdit) {
162 MultiTextEdit multiTextEdit1= (MultiTextEdit)edit1;
163 if (!multiTextEdit1.hasChildren())
164 return false;
165
166 TextEdit[] children= multiTextEdit1.getChildren();
167
168 int i= 0;
169 while (children[i].getExclusiveEnd() < edit2.getOffset()) {
170 i++;
171 if (i >= children.length)
172 return false;
173 }
174
175
176
177 if (overlaps(children[i], edit2))
178 return true;
179
180 return false;
181 } else if (edit2 instanceof MultiTextEdit) {
182 MultiTextEdit multiTextEdit2= (MultiTextEdit)edit2;
183 if (!multiTextEdit2.hasChildren())
184 return false;
185
186 TextEdit[] children= multiTextEdit2.getChildren();
187
188 int i= 0;
189 while (children[i].getExclusiveEnd() < edit1.getOffset()) {
190 i++;
191 if (i >= children.length)
192 return false;
193 }
194
195 if (overlaps(children[i], edit1))
196 return true;
197
198 return false;
199 } else {
200 int start1= edit1.getOffset();
201 int end1= start1 + edit1.getLength();
202 int start2= edit2.getOffset();
203 int end2= start2 + edit2.getLength();
204
205 if (start1 > end2)
206 return false;
207
208 if (start2 > end1)
209 return false;
210
211 return true;
212 }
213 }
214
215 /**
216 * Create an edit which contains <code>edit1</code> and <code>edit2</code>
217 * <p>If <code>edit1</code> overlaps <code>edit2</code> this method fails with a {@link MalformedTreeException}</p>
218 * <p><strong>The given edits are modified and they can no longer be used.</strong></p>
219 *
220 * @param edit1 the edit to merge with edit2
221 * @param edit2 the edit to merge with edit1
222 * @return the merged tree
223 * @throws MalformedTreeException if {@link #overlaps(TextEdit, TextEdit)} returns <b>true</b>
224 * @see #overlaps(TextEdit, TextEdit)
225 * @since 3.4
226 */
227 public static TextEdit merge(TextEdit edit1, TextEdit edit2) {
228 if (edit1 instanceof MultiTextEdit && !edit1.hasChildren()) {
229 return edit2;
230 }
231
232 if (edit2 instanceof MultiTextEdit && !edit2.hasChildren()) {
233 return edit1;
234 }
235
236 MultiTextEdit result= new MultiTextEdit();
237 merge(edit1, edit2, result);
238 return result;
239 }
240
241 private static void merge(TextEdit edit1, TextEdit edit2, MultiTextEdit result) {
242 if (edit1 instanceof MultiTextEdit && edit2 instanceof MultiTextEdit) {
243 MultiTextEdit multiTextEdit1= (MultiTextEdit)edit1;
244 if (!multiTextEdit1.hasChildren()) {
245 result.addChild(edit2);
246 return;
247 }
248
249 MultiTextEdit multiTextEdit2= (MultiTextEdit) edit2;
250 if (!multiTextEdit2.hasChildren()) {
251 result.addChild(edit1);
252 return;
253 }
254
255 TextEdit[] children1= multiTextEdit1.getChildren();
256 TextEdit[] children2= multiTextEdit2.getChildren();
257
258 int i1= 0;
259 int i2= 0;
260 while (i1 < children1.length && i2 < children2.length) {
261
262 while (i1 < children1.length && children1[i1].getExclusiveEnd() < children2[i2].getOffset()) {
263 edit1.removeChild(0);
264 result.addChild(children1[i1]);
265 i1++;
266 }
267 if (i1 >= children1.length)
268 break;
269
270 while (i2 < children2.length && children2[i2].getExclusiveEnd() < children1[i1].getOffset()) {
271 edit2.removeChild(0);
272 result.addChild(children2[i2]);
273 i2++;
274 }
275 if (i2 >= children2.length)
276 break;
277
278 if (children1[i1].getExclusiveEnd() < children2[i2].getOffset())
279 continue;
280
281 edit1.removeChild(0);
282 edit2.removeChild(0);
283 merge(children1[i1], children2[i2], result);
284
285 i1++;
286 i2++;
287 }
288
289 while (i1 < children1.length) {
290 edit1.removeChild(0);
291 result.addChild(children1[i1]);
292 i1++;
293 }
294
295 while (i2 < children2.length) {
296 edit2.removeChild(0);
297 result.addChild(children2[i2]);
298 i2++;
299 }
300 } else if (edit1 instanceof MultiTextEdit) {
301 TextEdit[] children= edit1.getChildren();
302
303 int i= 0;
304 while (children[i].getExclusiveEnd() < edit2.getOffset()) {
305 edit1.removeChild(0);
306 result.addChild(children[i]);
307 i++;
308 if (i >= children.length) {
309 result.addChild(edit2);
310 return;
311 }
312 }
313 edit1.removeChild(0);
314 merge(children[i], edit2, result);
315 i++;
316 while (i < children.length) {
317 edit1.removeChild(0);
318 result.addChild(children[i]);
319 i++;
320 }
321 } else if (edit2 instanceof MultiTextEdit) {
322 TextEdit[] children= edit2.getChildren();
323
324 int i= 0;
325 while (children[i].getExclusiveEnd() < edit1.getOffset()) {
326 edit2.removeChild(0);
327 result.addChild(children[i]);
328 i++;
329 if (i >= children.length) {
330 result.addChild(edit1);
331 return;
332 }
333 }
334 edit2.removeChild(0);
335 merge(edit1, children[i], result);
336 i++;
337 while (i < children.length) {
338 edit2.removeChild(0);
339 result.addChild(children[i]);
340 i++;
341 }
342 } else {
343 if (edit1.getExclusiveEnd() < edit2.getOffset()) {
344 result.addChild(edit1);
345 result.addChild(edit2);
346 } else {
347 result.addChild(edit2);
348 result.addChild(edit1);
349 }
350 }
351 }
352
353}