KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > source > save > CasualDiff


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.java.source.save;
20
21 import com.sun.source.tree.*;
22 import static com.sun.source.tree.Tree.*;
23 import java.io.IOException JavaDoc;
24 import javax.swing.text.BadLocationException JavaDoc;
25 import org.netbeans.api.java.lexer.JavaTokenId;
26 import org.netbeans.api.lexer.TokenSequence;
27 import org.netbeans.modules.java.source.builder.CommentHandlerService;
28 import org.netbeans.modules.java.source.builder.ASTService;
29 import org.netbeans.modules.java.source.builder.UndoListService;
30 import org.netbeans.api.java.source.transform.UndoList;
31 import org.netbeans.api.java.source.Comment;
32 import org.netbeans.api.java.source.query.CommentHandler;
33 import org.netbeans.api.java.source.query.CommentSet;
34 import org.netbeans.modules.java.source.engine.ASTModel;
35 import org.netbeans.api.java.source.query.Query;
36 import com.sun.tools.javac.code.*;
37 import com.sun.tools.javac.tree.JCTree;
38 import com.sun.tools.javac.tree.JCTree.*;
39 import com.sun.tools.javac.tree.Pretty;
40 import com.sun.tools.javac.tree.TreeInfo;
41 import com.sun.tools.javac.util.Context;
42 import com.sun.tools.javac.util.ListBuffer;
43 import com.sun.tools.javac.util.Name;
44 import com.sun.tools.javac.util.Position;
45 import java.util.ArrayList JavaDoc;
46 import java.util.EnumSet JavaDoc;
47 import java.util.HashMap JavaDoc;
48 import java.util.Iterator JavaDoc;
49 import java.util.List JavaDoc;
50 import java.util.Map JavaDoc;
51 import java.util.logging.Level JavaDoc;
52 import java.util.logging.Logger JavaDoc;
53 import org.netbeans.api.java.lexer.JavaTokenId;
54 import org.netbeans.api.java.source.WorkingCopy;
55 import org.netbeans.api.lexer.TokenHierarchy;
56 import org.netbeans.modules.java.source.engine.SourceRewriter;
57 import org.netbeans.modules.java.source.engine.StringSourceRewriter;
58 import org.netbeans.modules.java.source.engine.JavaFormatOptions;
59 import org.netbeans.modules.java.source.JavaSourceAccessor;
60 import org.netbeans.modules.java.source.pretty.VeryPretty;
61 import org.netbeans.modules.java.source.save.ListMatcher;
62 import static org.netbeans.modules.java.source.save.TreeDiff.LineInsertionType.*;
63 import static org.netbeans.modules.java.source.save.ListMatcher.*;
64 import static com.sun.tools.javac.code.Flags.*;
65 import static org.netbeans.modules.java.source.save.TreeDiff.*;
66 import static org.netbeans.modules.java.source.save.PositionEstimator.*;
67
68 public class CasualDiff {
69     protected ListBuffer<Diff> diffs;
70     protected CommentHandler comments;
71     protected ASTModel model;
72     protected UndoList undo;
73     protected JCTree oldParent;
74     protected JCTree newParent;
75     protected JCCompilationUnit oldTopLevel;
76     
77     private WorkingCopy workingCopy;
78     private TokenSequence<JavaTokenId> tokenSequence;
79     private SourceRewriter output;
80     private String JavaDoc origText;
81     private VeryPretty printer;
82     private int pointer;
83     private Context context;
84
85     private Map JavaDoc<Integer JavaDoc, String JavaDoc> diffInfo = new HashMap JavaDoc<Integer JavaDoc, String JavaDoc>();
86     
87     /** provided for test only */
88     public CasualDiff() {
89     }
90
91     protected CasualDiff(Context context, WorkingCopy workingCopy) {
92         diffs = new ListBuffer<Diff>();
93         comments = CommentHandlerService.instance(context);
94         model = ASTService.instance(context);
95         undo = UndoListService.instance(context);
96         this.workingCopy = workingCopy;
97         this.tokenSequence = workingCopy.getTokenHierarchy().tokenSequence();
98         this.output = new StringSourceRewriter();
99         this.origText = workingCopy.getText();
100         this.context = context;
101         printer = new VeryPretty(context, JavaFormatOptions.getDefault());
102     }
103     
104     public com.sun.tools.javac.util.List<Diff> getDiffs() {
105         return diffs.toList();
106     }
107     
108     public static com.sun.tools.javac.util.List<Diff> diff(Context context,
109             WorkingCopy copy,
110             JCTree oldTree,
111             JCTree newTree)
112     {
113         CasualDiff td = new CasualDiff(context, copy);
114         try {
115             td.diffTree(oldTree, newTree, new int[] { -1, -1});
116             String JavaDoc resultSrc = td.output.toString();
117             td.makeListMatch(td.workingCopy.getText(), resultSrc);
118             JavaSourceAccessor.INSTANCE.getCommandEnvironment(td.workingCopy).setResult(td.diffInfo, "user-info");
119         }
120         catch (Exception JavaDoc e) {
121             e.printStackTrace();
122         }
123         
124         return td.getDiffs();
125     }
126     
127     private void append(Diff diff) {
128         // check if diff already found -- true for variables that share
129
// fields, such as the mods for "public int foo, bar;"
130
for (Diff d : diffs)
131             if (d.equals(diff))
132                 return;
133         diffs.append(diff);
134     }
135     
136     // todo (#pf): Is this really needed? -- Seems it duplicates the work
137
// in SourcePositions, but in different way. Uses map of endPositions.
138
// Look into the implementation and try to use SourcePositions!
139
private int endPos(JCTree t) {
140         return model.getEndPos(t, oldTopLevel);
141     }
142     
143     private int endPos(com.sun.tools.javac.util.List<? extends JCTree> trees) {
144         int result = -1;
145     if (trees.nonEmpty()) {
146         result = endPos(trees.head);
147         for (com.sun.tools.javac.util.List <? extends JCTree> l = trees.tail; l.nonEmpty(); l = l.tail) {
148         result = endPos(l.head);
149         }
150     }
151         return result;
152     }
153     
154     private int endPos(List<? extends JCTree> trees) {
155         if (trees.isEmpty())
156             return -1;
157         JCTree tree;
158         return endPos(trees.get(trees.size()-1));
159     }
160
161     protected void diffTopLevel(JCCompilationUnit oldT, JCCompilationUnit newT) {
162         oldTopLevel = oldT;
163         // todo (#pf): make package annotation diffing correctly
164
// diffList(oldT.packageAnnotations, newT.packageAnnotations, LineInsertionType.NONE, 0);
165
int posHint = 0;
166         try {
167             posHint = diffPackageStatement(oldT, newT, pointer);
168             PositionEstimator est = EstimatorFactory.imports(((CompilationUnitTree) oldT).getImports(), ((CompilationUnitTree) newT).getImports(), workingCopy);
169             pointer = diffListImports(oldT.getImports(), newT.getImports(), posHint, est, Measure.DEFAULT, printer);
170             if (oldT.getTypeDecls().nonEmpty()) {
171                 posHint = getOldPos(oldT.getTypeDecls().head);
172             } else {
173                 // todo (#pf): this has to be fixed, missing code here.
174
}
175             output.writeTo(printer.toString());
176             printer.reset(0);
177             est = EstimatorFactory.toplevel(((CompilationUnitTree) oldT).getTypeDecls(), ((CompilationUnitTree) newT).getTypeDecls(), workingCopy);
178             int[] pos = diffList(oldT.getTypeDecls(), newT.getTypeDecls(), posHint, est, Measure.DEFAULT, printer);
179             if (pointer < pos[0])
180                 output.writeTo(origText.substring(pointer, pos[0]));
181             if (pos[1] > pointer) {
182                 pointer = pos[1];
183             }
184             output.writeTo(printer.toString());
185             output.writeTo(origText.substring(pointer));
186         } catch (Exception JavaDoc e) {
187             // report an exception and do not any change in source to prevent deletion of code!
188
Logger.getLogger("global").log(Level.SEVERE, "Error during generating!", e);
189             this.output = new StringSourceRewriter();
190             try {
191                 this.output.writeTo(origText);
192             } catch (BadLocationException JavaDoc ex) {
193             } catch (IOException JavaDoc ex) {
194             }
195         }
196     }
197     
198     private static enum ChangeKind {
199         INSERT,
200         DELETE,
201         MODIFY,
202         NOCHANGE;
203     }
204     
205     private ChangeKind getChangeKind(Tree oldT, Tree newT) {
206         if (oldT == newT) {
207             return ChangeKind.NOCHANGE;
208         }
209         if (oldT != null && newT != null) {
210             return ChangeKind.MODIFY;
211         }
212         if (oldT != null) {
213             return ChangeKind.DELETE;
214         } else {
215             return ChangeKind.INSERT;
216         }
217     }
218     
219     private int diffPackageStatement(JCCompilationUnit oldT, JCCompilationUnit newT, int localPointer) {
220         ChangeKind change = getChangeKind(oldT.pid, newT.pid);
221         switch (change) {
222             // packages are the same or not available, i.e. both are null
223
case NOCHANGE:
224                 break;
225                 
226             // package statement is new, print the keyword and semicolon
227
case INSERT:
228                 printer.print("package ");
229                 printer.print(newT.pid);
230                 printer.print(";");
231                 printer.newline();
232                 break;
233                 
234             // package statement was deleted.
235
case DELETE:
236                 TokenUtilities.movePrevious(tokenSequence, oldT.pid.getStartPosition());
237                 copyTo(localPointer, tokenSequence.offset());
238                 TokenUtilities.moveNext(tokenSequence, endPos(oldT.pid));
239                 localPointer = tokenSequence.offset() + 1;
240                 // todo (#pf): check the declaration:
241
// package org.netbeans /* aa */;
242
break;
243     
244             // package statement was modified.
245
case MODIFY:
246                 copyTo(localPointer, getOldPos(oldT.pid));
247                 localPointer = endPos(oldT.pid);
248                 printer.print(newT.pid);
249                 diffInfo.put(getOldPos(oldT.pid), "Update package statement");
250                 break;
251         }
252         return localPointer;
253     }
254     
255     protected int diffImport(JCImport oldT, JCImport newT, int[] bounds) {
256         int localPointer = bounds[0];
257         
258         int[] qualBounds = getBounds(oldT.getQualifiedIdentifier());
259         copyTo(localPointer, qualBounds[0]);
260         localPointer = diffTree(oldT.getQualifiedIdentifier(), newT.getQualifiedIdentifier(), qualBounds);
261 // if (TreeInfo.fullName(oldT.qualid) != TreeInfo.fullName(newT.qualid))
262
// append(Diff.modify(oldT, getOldPos(oldT), newT)); // includes possible staticImport change
263
// else if (oldT.staticImport != newT.staticImport)
264
// append(Diff.flags(oldT.pos, endPos(oldT),
265
// oldT.staticImport ? Flags.STATIC : 0L,
266
// newT.staticImport ? Flags.STATIC : 0L));
267

268         copyTo(localPointer, bounds[1]);
269         
270         return bounds[1];
271     }
272
273     // need by visitMethodDef - in case of renaming class, we do not know
274
// this name in constructor matcher - save it in diffClassDef() and use
275
// in diffMethodDef(). Probably better to write method with additional
276
// parameter which delegates to original one visitMethodDef().
277
private Name origClassName = null;
278     
279     protected int diffClassDef(JCClassDecl oldT, JCClassDecl newT, int[] bounds) {
280         int localPointer = bounds[0];
281         int insertHint = localPointer;
282         JCTree opar = oldParent;
283         oldParent = oldT;
284         JCTree npar = newParent;
285         newParent = newT;
286         // skip the section when printing anonymous class
287
if (anonClass == false) {
288         tokenSequence.move(oldT.pos);
289         tokenSequence.moveNext(); // First skip as move() does not position to token directly
290
tokenSequence.moveNext();
291         insertHint = TokenUtilities.moveNext(tokenSequence, tokenSequence.offset());
292         localPointer = diffModifiers(oldT.mods, newT.mods, oldT, localPointer);
293         if (nameChanged(oldT.name, newT.name)) {
294             copyTo(localPointer, insertHint);
295             printer.print(newT.name);
296             diffInfo.put(insertHint, "Change class name");
297             localPointer = insertHint += oldT.name.length();
298             origClassName = oldT.name;
299         } else {
300             insertHint += oldT.name.length();
301         }
302         localPointer = diffParameterList(oldT.typarams, newT.typarams, localPointer);
303         if (oldT.typarams.nonEmpty()) {
304             // if type parameters exists, compute correct end of type parameters.
305
// ! specifies the offset for insertHint var.
306
// public class Yerba<E, M>! { ...
307
insertHint = endPos(oldT.typarams.last());
308             TokenUtilities.moveFwdToToken(tokenSequence, insertHint, JavaTokenId.GT);
309             insertHint = tokenSequence.offset() + JavaTokenId.GT.fixedText().length();
310         }
311         switch (getChangeKind(oldT.extending, newT.extending)) {
312             case NOCHANGE:
313                 insertHint = oldT.extending != null ? endPos(oldT.extending) : insertHint;
314                 copyTo(localPointer, localPointer = insertHint);
315                 break;
316             case MODIFY:
317                 copyTo(localPointer, getOldPos(oldT.extending));
318                 localPointer = diffTree(oldT.extending, newT.extending, getBounds(oldT.extending));
319                 break;
320                 
321             case INSERT:
322                 copyTo(localPointer, insertHint);
323                 printer.print(" extends ");
324                 printer.print(newT.extending);
325                 localPointer = insertHint;
326                 break;
327             case DELETE:
328                 copyTo(localPointer, insertHint);
329                 localPointer = endPos(oldT.extending);
330                 break;
331         }
332         // TODO (#pf): there is some space for optimization. If the new list
333
// is also empty, we can skip this computation.
334
if (oldT.implementing.isEmpty()) {
335             // if there is not any implementing part, we need to adjust position
336
// from different place. Look at the examples in all if branches.
337
// | represents current adjustment and ! where we want to point to
338
if (oldT.extending != null)
339                 // public class Yerba<E>| extends Object! { ...
340
insertHint = endPos(oldT.extending);
341             else {
342                 // currently no need to adjust anything here:
343
// public class Yerba<E>|! { ...
344
}
345         } else {
346             // we already have any implements, adjust position to first
347
// public class Yerba<E>| implements !Mate { ...
348
// Note: in case of all implements classes are removed,
349
// diffing mechanism will solve the implements keyword.
350
insertHint = oldT.implementing.iterator().next().getStartPosition();
351         }
352         long flags = oldT.sym != null ? oldT.sym.flags() : oldT.mods.flags;
353         PositionEstimator estimator = (flags & INTERFACE) == 0 ?
354             EstimatorFactory.implementz(((ClassTree) oldT).getImplementsClause(), ((ClassTree) newT).getImplementsClause(), workingCopy) :
355             EstimatorFactory.extendz(((ClassTree) oldT).getImplementsClause(), ((ClassTree) newT).getImplementsClause(), workingCopy);
356         if (!newT.implementing.isEmpty())
357             copyTo(localPointer, insertHint);
358         localPointer = diffList2(oldT.implementing, newT.implementing, insertHint, estimator);
359         insertHint = endPos(oldT) - 1;
360
361         if (oldT.defs.isEmpty()) {
362             // if there is nothing in class declaration, use position
363
// before the closing curly.
364
// TODO (#pf): optimize new lines, this will look ugly. --
365
// do before the last new line character before the closing curly.
366
insertHint = endPos(oldT) - 1;
367         } else {
368             // XXX hack: be careful, syntetic constructor in head has the
369
// same position as class declaration too - go to the next feature.
370
// do not be upset to me for the next line, I will replace it
371
// with some better and final solution soon, hopefully :-).
372
JCTree t = oldT.defs.head.pos == oldT.pos ? oldT.defs.tail.head : oldT.defs.head;
373             if (t != null) insertHint = t.getStartPosition();
374         }
375         } else {
376             insertHint = TokenUtilities.moveFwdToToken(tokenSequence, getOldPos(oldT), JavaTokenId.LBRACE);
377             tokenSequence.moveNext();
378             insertHint = tokenSequence.offset();
379         }
380         int old = printer.indent();
381         VeryPretty mujPrinter = new VeryPretty(context, JavaFormatOptions.getDefault());
382         mujPrinter.reset(old);
383         mujPrinter.indent();
384         mujPrinter.enclClassName = newT.getSimpleName();
385         PositionEstimator est = EstimatorFactory.members(filterHidden(oldT.defs), filterHidden(newT.defs), workingCopy);
386         int[] pos = diffList(filterHidden(oldT.defs), filterHidden(newT.defs), insertHint, est, Measure.DEFAULT, mujPrinter);
387         if (localPointer < pos[0])
388             copyTo(localPointer, pos[0]);
389         printer.print(mujPrinter.toString());
390         if (pos[1] != -1)
391             copyTo(pos[1], bounds[1]);
392         else
393             copyTo(localPointer, bounds[1]);
394         //pointer = bounds[1];
395
oldParent = opar;
396         newParent = npar;
397         // the reference is no longer needed.
398
origClassName = null;
399         printer.undent(old);
400         return bounds[1];
401     }
402
403     private boolean hasModifiers(JCModifiers mods) {
404         return mods != null && (!mods.getFlags().isEmpty() || !mods.getAnnotations().isEmpty());
405     }
406     
407     protected int diffMethodDef(JCMethodDecl oldT, JCMethodDecl newT, int[] bounds) {
408         int localPointer = bounds[0];
409         // match modifiers and annotations
410
if (!matchModifiers(oldT.mods, newT.mods)) {
411             // if new tree has modifiers, print them
412
if (hasModifiers(newT.mods)) {
413                 localPointer = diffModifiers(oldT.mods, newT.mods, oldT, localPointer);
414             } else {
415                 // there are no new modifiers, just skip after existing. --
416
// endPos of modifiers are not usable, we have to remove also
417
// space. Go to return type in case of method, in case of
418
// constructor use whole tree start.
419
int oldPos = getOldPos(oldT.mods);
420                 copyTo(localPointer, oldPos);
421                 localPointer = oldT.restype != null ? getOldPos(oldT.restype) : oldT.pos;
422             }
423         }
424         // compute the position for type parameters - if type param is empty,
425
// use in case of
426
// i) method - start position of return type,
427
// ii) constructor - start position of tree - i.e. first token after
428
// modifiers.
429
int pos = oldT.typarams.isEmpty() ?
430             oldT.restype != null ?
431                 getOldPos(oldT.restype) :
432                 oldT.pos :
433             getOldPos(oldT.typarams.head);
434         
435         if (!listsMatch(oldT.typarams, newT.typarams)) {
436             if (newT.typarams.nonEmpty())
437                 copyTo(localPointer, pos);
438             else
439                 if (hasModifiers(oldT.mods))
440                     copyTo(localPointer, endPos(oldT.mods));
441             VeryPretty locBuf = new VeryPretty(context);
442             localPointer = diffParameterList(oldT.typarams,
443                     newT.typarams,
444                     oldT.typarams.isEmpty() || newT.typarams.isEmpty(),
445                     pos,
446                     locBuf
447             );
448             printer.print(locBuf.toString());
449         }
450         if (oldT.restype != null) { // means constructor, skip return type gen.
451
int[] restypeBounds = getBounds(oldT.restype);
452             copyTo(localPointer, restypeBounds[0]);
453             localPointer = diffTree(oldT.restype, newT.restype, restypeBounds);
454             copyTo(localPointer, localPointer = restypeBounds[1]);
455         }
456         int posHint;
457         if (oldT.typarams.isEmpty()) {
458             posHint = oldT.restype != null ? oldT.restype.getStartPosition() : oldT.getStartPosition();
459         } else {
460             posHint = oldT.typarams.iterator().next().getStartPosition();
461         }
462         if (!oldT.sym.isConstructor() || origClassName != null) {
463             if (nameChanged(oldT.name, newT.name)) {
464                 copyTo(localPointer, oldT.pos);
465                 // use orig class name in case of constructor
466
if (oldT.sym.isConstructor() && (origClassName != null)) {
467                     printer.print(newT.name);
468                     localPointer = oldT.pos + origClassName.length();
469                 }
470                 else {
471                     printer.print(newT.name);
472                     diffInfo.put(oldT.pos, "Rename method " + oldT.name);
473                     localPointer = oldT.pos + oldT.name.length();
474                 }
475             } else {
476                 copyTo(localPointer, localPointer = (oldT.pos + oldT.name.length()));
477             }
478         }
479         if (oldT.params.isEmpty()) {
480             // compute the position. Find the parameters closing ')', its
481
// start position is important for us. This is used when
482
// there was not any parameter in original tree.
483
int startOffset = oldT.restype != null ? oldT.restype.getStartPosition() : oldT.getStartPosition();
484             
485             TokenUtilities.moveFwdToToken(tokenSequence, startOffset, JavaTokenId.RPAREN);
486             posHint = tokenSequence.offset();
487         } else {
488             // take the position of the first old parameter
489
posHint = oldT.params.iterator().next().getStartPosition();
490         }
491         if (!listsMatch(oldT.params, newT.params)) {
492             copyTo(localPointer, posHint);
493             VeryPretty locBuf = new VeryPretty(context);
494             locBuf.setPrec(TreeInfo.noPrec);
495             localPointer = diffParameterList(oldT.params, newT.params, false, posHint, locBuf);
496             printer.print(locBuf.toString());
497         }
498         // temporary
499
tokenSequence.moveNext();
500         posHint = tokenSequence.offset();
501         if (localPointer < posHint)
502             copyTo(localPointer, localPointer = posHint);
503         // if abstract, hint is before ending semi-colon, otherwise before method body
504
if (oldT.thrown.isEmpty()) {
505             posHint = (oldT.body == null ? endPos(oldT) : oldT.body.pos) - 1;
506             // now check, that there is a whitespace. It is not mandatory, we
507
// have to ensure. If whitespace is not present, take body beginning
508
tokenSequence.move(posHint);
509             tokenSequence.moveNext();
510             if (tokenSequence.token().id() != JavaTokenId.WHITESPACE) {
511                 ++posHint;
512             }
513         } else {
514             posHint = oldT.thrown.iterator().next().getStartPosition();
515         }
516         copyTo(localPointer, localPointer = posHint);
517         PositionEstimator est = EstimatorFactory.throwz(((MethodTree) oldT).getThrows(), ((MethodTree) newT).getThrows(), workingCopy);
518         localPointer = diffList2(oldT.thrown, newT.thrown, posHint, est);
519         posHint = endPos(oldT) - 1;
520         localPointer = diffTree(oldT.body, newT.body, localPointer);
521         //diffTree(oldT.defaultValue, newT.defaultValue);
522
copyTo(localPointer, bounds[1]);
523         return bounds[1];
524     }
525
526     protected int diffVarDef(JCVariableDecl oldT, JCVariableDecl newT, int[] bounds) {
527        int localPointer = bounds[0];
528         if (!matchModifiers(oldT.mods, newT.mods)) {
529             // if new tree has modifiers, print them
530
if (hasModifiers(newT.mods)) {
531                 localPointer = diffModifiers(oldT.mods, newT.mods, oldT, localPointer);
532             } else {
533                 int oldPos = getOldPos(oldT.mods);
534                 copyTo(localPointer, oldPos);
535                 localPointer = getOldPos(oldT.vartype);
536             }
537         }
538         int[] vartypeBounds = getBounds(oldT.vartype);
539         copyTo(localPointer, vartypeBounds[0]);
540         localPointer = diffTree(oldT.vartype, newT.vartype, vartypeBounds);
541         if (nameChanged(oldT.name, newT.name)) {
542             copyTo(localPointer, oldT.pos);
543             printer.print(newT.name);
544             diffInfo.put(oldT.pos, "Rename variable " + oldT.name);
545             localPointer = oldT.pos + oldT.name.length();
546         }
547         if (newT.init != null && oldT.init != null) {
548             copyTo(localPointer, localPointer = getOldPos(oldT.init));
549             localPointer = diffTree(oldT.init, newT.init, new int[] { localPointer, endPos(oldT.init) });
550         } else {
551             if (oldT.init != null && newT.init == null) {
552                 // remove initial value
553
int pos = getOldPos(oldT.init);
554                 tokenSequence.move(pos);
555                 moveToSrcRelevant(tokenSequence, Direction.BACKWARD);
556                 moveToSrcRelevant(tokenSequence, Direction.BACKWARD);
557                 tokenSequence.moveNext();
558                 int to = tokenSequence.offset();
559                 copyTo(localPointer, to);
560                 localPointer = endPos(oldT.init);
561             }
562             if (oldT.init == null && newT.init != null) {
563                 copyTo(localPointer, localPointer = endPos(oldT.init));
564                 printer.print(newT.init);
565             }
566         }
567         copyTo(localPointer, bounds[1]);
568         return bounds[1];
569     }
570
571     protected int diffBlock(JCBlock oldT, JCBlock newT, int lastPrinted) {
572         int localPointer = lastPrinted;
573         if (oldT.flags != newT.flags)
574             append(Diff.flags(oldT.pos, endPos(oldT), oldT.flags, newT.flags));
575         VeryPretty bodyPrinter = new VeryPretty(context, JavaFormatOptions.getDefault());
576         int oldIndent = printer.indent();
577         bodyPrinter.reset(oldIndent);
578         bodyPrinter.indent();
579         // syntetic super() found, skip it
580
if (oldT.stats.head != null && oldT.stats.head.pos == oldT.pos) {
581             oldT.stats = oldT.stats.tail;
582         }
583         if (newT.stats.head != null && newT.stats.head.pos == oldT.pos) {
584             newT.stats = newT.stats.tail;
585         }
586         PositionEstimator est = EstimatorFactory.members(((BlockTree) oldT).getStatements(), ((BlockTree) newT).getStatements(), workingCopy);
587         int[] pos = diffList(oldT.stats, newT.stats, oldT.pos + 1, est, Measure.DEFAULT, bodyPrinter); // hint after open brace
588
if (localPointer < pos[0]) {
589             copyTo(localPointer, pos[0]);
590         }
591         localPointer = pos[1];
592         printer.print(bodyPrinter.toString());
593         if (localPointer < endPos(oldT)) {
594             copyTo(localPointer, localPointer = endPos(oldT));
595         }
596         printer.undent(oldIndent);
597         return localPointer;
598     }
599
600     protected int diffDoLoop(JCDoWhileLoop oldT, JCDoWhileLoop newT, int[] bounds) {
601         int localPointer = bounds[0];
602         
603         int[] bodyBounds = getBounds(oldT.body);
604         copyTo(localPointer, bodyBounds[0]);
605         localPointer = diffTree(oldT.body, newT.body, bodyBounds);
606         
607         int[] condBounds = getBounds(oldT.cond);
608         copyTo(localPointer, condBounds[0]);
609         localPointer = diffTree(oldT.cond, newT.cond, condBounds);
610         copyTo(localPointer, bounds[1]);
611         
612         return bounds[1];
613     }
614
615     protected int diffWhileLoop(JCWhileLoop oldT, JCWhileLoop newT, int[] bounds) {
616         int localPointer = bounds[0];
617         // condition
618
int[] condPos = getBounds(oldT.cond);
619         copyTo(localPointer, condPos[0]);
620         localPointer = diffTree(oldT.cond, newT.cond, condPos);
621         // body
622
int[] bodyPos = getBounds(oldT.body);
623         copyTo(localPointer, bodyPos[0]);
624         localPointer = diffTree(oldT.body, newT.body, bodyPos);
625         
626         copyTo(localPointer, bounds[1]);
627         return bounds[1];
628     }
629
630     protected int diffForLoop(JCForLoop oldT, JCForLoop newT, int[] bounds) {
631         int localPointer = bounds[0];
632         int initListHint = oldT.cond != null ? oldT.cond.pos - 1 : Query.NOPOS;
633         int stepListHint = oldT.cond != null ? endPos(oldT.cond) + 1 : Query.NOPOS;
634         copyTo(bounds[0], getOldPos(oldT.init.head));
635         localPointer = diffList(oldT.init, newT.init, LineInsertionType.NONE, initListHint);
636         copyTo(localPointer, getOldPos(oldT.cond));
637         localPointer = diffTree(oldT.cond, newT.cond, getBounds(oldT.cond));
638         if (oldT.step.nonEmpty())
639             copyTo(localPointer, getOldPos(oldT.step.head));
640         else
641             copyTo(localPointer, stepListHint);
642         localPointer = diffList(oldT.step, newT.step, LineInsertionType.NONE, stepListHint);
643         copyTo(localPointer, getOldPos(oldT.body));
644         localPointer = diffTree(oldT.body, newT.body, getBounds(oldT.body));
645         copyTo(localPointer, bounds[1]);
646         return bounds[1];
647     }
648     
649     protected int diffForeachLoop(JCEnhancedForLoop oldT, JCEnhancedForLoop newT, int[] bounds) {
650         int localPointer = bounds[0];
651         // variable
652
int[] varBounds = getBounds(oldT.var);
653         copyTo(localPointer, varBounds[0]);
654         localPointer = diffTree(oldT.var, newT.var, varBounds);
655         // expression
656
int[] exprBounds = getBounds(oldT.expr);
657         copyTo(localPointer, exprBounds[0]);
658         localPointer = diffTree(oldT.expr, newT.expr, exprBounds);
659         // body
660
int[] bodyBounds = getBounds(oldT.body);
661         copyTo(localPointer, bodyBounds[0]);
662         localPointer = diffTree(oldT.body, newT.body, bodyBounds);
663         copyTo(localPointer, bounds[1]);
664         
665         return bounds[1];
666     }
667
668     protected int diffLabelled(JCLabeledStatement oldT, JCLabeledStatement newT, int[] bounds) {
669         int localPointer = bounds[0];
670         if (nameChanged(oldT.label, newT.label)) {
671             copyTo(localPointer, localPointer = getOldPos(oldT));
672             printer.print(newT.label);
673             localPointer += oldT.label.length();
674         }
675         int[] bodyBounds = getBounds(oldT.body);
676         copyTo(localPointer, bodyBounds[0]);
677         localPointer = diffTree(oldT.body, newT.body, bodyBounds);
678         copyTo(localPointer, bounds[1]);
679         
680         return bounds[1];
681     }
682
683     protected int diffSwitch(JCSwitch oldT, JCSwitch newT, int[] bounds) {
684         int localPointer = bounds[0];
685         
686         // rename in switch
687
int[] selectorBounds = getBounds(oldT.selector);
688         copyTo(localPointer, selectorBounds[0]);
689         localPointer = diffTree(oldT.selector, newT.selector, selectorBounds);
690         
691         int castListHint = oldT.cases.size() > 0 ? oldT.cases.head.pos : Query.NOPOS;
692         PositionEstimator est = EstimatorFactory.members(oldT.getCases(), newT.getCases(), workingCopy);
693         copyTo(localPointer, castListHint);
694         int[] pos = diffList(oldT.cases, newT.cases, castListHint, est, Measure.DEFAULT, printer);
695         
696         copyTo(pos[1], bounds[1]);
697         return bounds[1];
698     }
699
700     protected int diffCase(JCCase oldT, JCCase newT, int[] bounds) {
701         int localPointer = bounds[0];
702         if (oldT.pat != null) {
703             int[] patBounds = getBounds(oldT.pat);
704             copyTo(localPointer, patBounds[0]);
705             localPointer = diffTree(oldT.pat, newT.pat, patBounds);
706         }
707         int pos = oldT.stats.head.pos;
708         PositionEstimator est = EstimatorFactory.members(oldT.getStatements(), newT.getStatements(), workingCopy);
709         VeryPretty localPrinter = new VeryPretty(context, JavaFormatOptions.getDefault());
710         int[] stmtPos = diffList(oldT.stats, newT.stats, pos, est, Measure.DEFAULT, localPrinter);
711         if (localPointer < stmtPos[0]) copyTo(localPointer, stmtPos[0]);
712         printer.print(localPrinter.toString());
713         copyTo(stmtPos[1], bounds[1]);
714         
715         return bounds[1];
716     }
717
718     protected int diffSynchronized(JCSynchronized oldT, JCSynchronized newT, int[] bounds) {
719         int localPointer = bounds[0];
720         // lock
721
int[] lockBounds = getBounds(oldT.lock);
722         copyTo(localPointer, lockBounds[0]);
723         localPointer = diffTree(oldT.lock, newT.lock, lockBounds);
724         // body
725
int[] bodyBounds = getBounds(oldT.body);
726         copyTo(localPointer, bodyBounds[0]);
727         localPointer = diffTree(oldT.body, newT.body, bodyBounds);
728         copyTo(localPointer, bounds[1]);
729         
730         return bounds[1];
731     }
732
733     protected int diffTry(JCTry oldT, JCTry newT, int[] bounds) {
734         int localPointer = bounds[0];
735         int[] bodyPos = getBounds(oldT.body);
736         copyTo(localPointer, bodyPos[0]);
737         localPointer = diffTree(oldT.body, newT.body, bodyPos);
738         int pos = oldT.catchers.head != null ? getOldPos(oldT.catchers.head) : oldT.body.endpos + 1;
739         VeryPretty locPrint = new VeryPretty(context);
740         PositionEstimator est = EstimatorFactory.members(((TryTree) oldT).getCatches(), ((TryTree) newT).getCatches(), workingCopy);
741         int[] retPos = diffList(oldT.catchers, newT.catchers, pos, est, Measure.DEFAULT, locPrint);
742         if (localPointer < retPos[0]) {
743             copyTo(localPointer, retPos[0]);
744         }
745         printer.print(locPrint.toString());
746         localPointer = oldT.catchers.head != null ? endPos(oldT.catchers) : pos;
747         if (oldT.finalizer != null) {
748             int[] finalBounds = getBounds(oldT.finalizer);
749             copyTo(localPointer, finalBounds[0]);
750             localPointer = diffTree(oldT.finalizer, newT.finalizer, finalBounds);
751             copyTo(localPointer, bounds[1]);
752         } else if (retPos[1] < bounds[1]) {
753             copyTo(localPointer, bounds[1]);
754         }
755         return bounds[1];
756     }
757
758     protected int diffCatch(JCCatch oldT, JCCatch newT, int[] bounds) {
759         int localPointer = bounds[0];
760         // param
761
int[] paramBounds = getBounds(oldT.param);
762         copyTo(localPointer, paramBounds[0]);
763         localPointer = diffTree(oldT.param, newT.param, paramBounds);
764         // body
765
int[] bodyBounds = getBounds(oldT.body);
766         copyTo(localPointer, bodyBounds[0]);
767         localPointer = diffTree(oldT.body, newT.body, bodyBounds);
768         copyTo(localPointer, bounds[1]);
769         
770         return bounds[1];
771     }
772
773     protected int diffConditional(JCConditional oldT, JCConditional newT, int[] bounds) {
774         int localPointer = bounds[0];
775         // cond
776
int[] condBounds = getBounds(oldT.cond);
777         copyTo(localPointer, condBounds[0]);
778         localPointer = diffTree(oldT.cond, newT.cond, condBounds);
779         // true
780
int[] trueBounds = getBounds(oldT.truepart);
781         copyTo(localPointer, trueBounds[0]);
782         localPointer = diffTree(oldT.truepart, newT.truepart, trueBounds);
783         // false
784
int[] falseBounds = getBounds(oldT.falsepart);
785         copyTo(localPointer, falseBounds[0]);
786         localPointer = diffTree(oldT.falsepart, newT.falsepart, falseBounds);
787         copyTo(localPointer, bounds[1]);
788         
789         return bounds[1];
790     }
791
792     protected int diffIf(JCIf oldT, JCIf newT, int[] bounds) {
793         int localPointer = bounds[0];
794         if (oldT.elsepart == null && newT.elsepart != null ||
795             oldT.elsepart != null && newT.elsepart == null) {
796             // mark the whole if statement to be reformatted, which Commit will refine.
797
append(Diff.modify(oldT, getOldPos(oldT), newT));
798         } else {
799             int[] condBounds = getBounds(oldT.cond);
800             copyTo(localPointer, condBounds[0]);
801             localPointer = diffTree(oldT.cond, newT.cond, condBounds);
802             int[] thenpartBounds = getBounds(oldT.thenpart);
803             copyTo(localPointer, thenpartBounds[0]);
804             localPointer = diffTree(oldT.thenpart, newT.thenpart, thenpartBounds);
805             if (oldT.elsepart != null) {
806                 thenpartBounds = new int[] { getOldPos(oldT.elsepart), endPos(oldT.elsepart) };
807                 copyTo(localPointer, thenpartBounds[0]);
808                 localPointer = diffTree(oldT.elsepart, newT.elsepart, thenpartBounds);
809             }
810         }
811         copyTo(localPointer, bounds[1]);
812         return bounds[1];
813     }
814
815     protected int diffExec(JCExpressionStatement oldT, JCExpressionStatement newT, int[] bounds) {
816         int localPointer = getOldPos(oldT);
817         copyTo(bounds[0], localPointer);
818         localPointer = diffTree(oldT.expr, newT.expr, bounds);
819         copyTo(localPointer, bounds[1]);
820         return bounds[1];
821     }
822
823     protected int diffBreak(JCBreak oldT, JCBreak newT, int[] bounds) {
824         int localPointer = bounds[0];
825         if (nameChanged(oldT.label, newT.label)) {
826             copyTo(localPointer, localPointer = getOldPos(oldT));
827             printer.print("break ");
828             printer.print(newT.label);
829             localPointer += 6 + oldT.label.length();
830         }
831 // int[] targetBounds = getBounds(oldT.target);
832
// copyTo(localPointer, targetBounds[0]);
833
// localPointer = diffTree(oldT.target, newT.target, targetBounds);
834
copyTo(localPointer, bounds[1]);
835         return bounds[1];
836     }
837         
838     protected int diffContinue(JCContinue oldT, JCContinue newT, int[] bounds) {
839         int localPointer = bounds[0];
840         if (nameChanged(oldT.label, newT.label)) {
841             copyTo(localPointer, localPointer = getOldPos(oldT));
842             printer.print("continue ");
843             printer.print(newT.label);
844             localPointer += 9 + oldT.label.length();
845         }
846 // int[] targetBounds = getBounds(oldT.target);
847
// copyTo(localPointer, targetBounds[0]);
848
// localPointer = diffTree(oldT.target, newT.target, targetBounds);
849
copyTo(localPointer, bounds[1]);
850         
851         return bounds[1];
852     }
853
854     protected int diffReturn(JCReturn oldT, JCReturn newT, int[] bounds) {
855         int[] exprBounds = getBounds(oldT.expr);
856         copyTo(bounds[0], exprBounds[0]);
857         int localPointer = diffTree(oldT.expr, newT.expr, exprBounds);
858         copyTo(localPointer, bounds[1]);
859         
860         return bounds[1];
861     }
862
863     protected int diffThrow(JCThrow oldT, JCThrow newT, int[] bounds) {
864         int localPointer = bounds[0];
865         // expr
866
int[] exprBounds = getBounds(oldT.expr);
867         copyTo(localPointer, exprBounds[0]);
868         localPointer = diffTree(oldT.expr, newT.expr, exprBounds);
869         copyTo(localPointer, bounds[1]);
870         
871         return bounds[1];
872     }
873
874     protected int diffAssert(JCAssert oldT, JCAssert newT, int[] bounds) {
875         int localPointer = bounds[0];
876         // cond
877
int[] condBounds = getBounds(oldT.cond);
878         copyTo(localPointer, condBounds[0]);
879         localPointer = diffTree(oldT.cond, newT.cond, condBounds);
880         // detail
881
int[] detailBounds = getBounds(oldT.detail);
882         copyTo(localPointer, detailBounds[0]);
883         localPointer = diffTree(oldT.detail, newT.detail, detailBounds);
884         copyTo(localPointer, bounds[1]);
885         
886         return bounds[1];
887     }
888
889     protected int diffApply(JCMethodInvocation oldT, JCMethodInvocation newT, int[] bounds) {
890         int localPointer = bounds[0];
891         diffParameterList(oldT.typeargs, newT.typeargs, localPointer);
892         int[] methBounds = getBounds(oldT.meth);
893         localPointer = diffTree(oldT.meth, newT.meth, methBounds);
894         if (!listsMatch(oldT.args, newT.args)) {
895             if (oldT.args.nonEmpty()) {
896                 copyTo(localPointer, localPointer = getOldPos(oldT.args.head));
897             } else {
898                 int rParen = TokenUtilities.moveFwdToToken(tokenSequence, getOldPos(oldT.meth), JavaTokenId.RPAREN);
899                 copyTo(localPointer, localPointer = rParen);
900             }
901             VeryPretty buf = new VeryPretty(context, JavaFormatOptions.getDefault());
902             localPointer = diffParameterList(oldT.args, newT.args, false, localPointer, buf);
903             printer.print(buf.toString());
904         }
905         copyTo(localPointer, bounds[1]);
906         
907         return bounds[1];
908     }
909
910     boolean anonClass = false;
911     
912     protected int diffNewClass(JCNewClass oldT, JCNewClass newT, int[] bounds) {
913         int localPointer = bounds[0];
914         if (oldT.encl != null) {
915             int[] enclBounds = getBounds(oldT.encl);
916             localPointer = diffTree(oldT.encl, newT.encl, enclBounds);
917         }
918         diffParameterList(oldT.typeargs, newT.typeargs, localPointer);
919         int[] clazzBounds = getBounds(oldT.clazz);
920         copyTo(localPointer, clazzBounds[0]);
921         localPointer = diffTree(oldT.clazz, newT.clazz, clazzBounds );
922         localPointer = diffParameterList(oldT.args, newT.args, localPointer);
923         // let diffClassDef() method notified that anonymous class is printed.
924
if (oldT.def != null) {
925             copyTo(localPointer, getOldPos(oldT.def));
926             if (newT.def != null) {
927                 anonClass = true;
928                 localPointer = diffTree(oldT.def, newT.def, getBounds(oldT.def));
929                 anonClass = false;
930             } else {
931                 localPointer = endPos(oldT.def);
932             }
933         }
934         copyTo(localPointer, bounds[1]);
935         return bounds[1];
936     }
937
938     protected int diffNewArray(JCNewArray oldT, JCNewArray newT, int[] bounds) {
939         int localPointer = bounds[0];
940         // elemtype
941
if (oldT.elemtype != null) {
942             int[] elemtypeBounds = getBounds(oldT.elemtype);
943             copyTo(localPointer, elemtypeBounds[0]);
944             localPointer = diffTree(oldT.elemtype, newT.elemtype, elemtypeBounds);
945         }
946 // diffParameterList(oldT.dims, newT.dims, endPos(oldT.dims));
947
if (oldT.elems != null && oldT.elems.head != null) {
948             copyTo(localPointer, getOldPos(oldT.elems.head));
949             localPointer = diffParameterList(oldT.elems, newT.elems, getOldPos(oldT.elems.head));
950         }
951         copyTo(localPointer, bounds[1]);
952         return bounds[1];
953     }
954
955     protected int diffParens(JCParens oldT, JCParens newT, int[] bounds) {
956         int localPointer = bounds[0];
957         copyTo(localPointer, getOldPos(oldT.expr));
958         localPointer = diffTree(oldT.expr, newT.expr, getBounds(oldT.expr));
959         return localPointer;
960     }
961
962     protected int diffAssign(JCAssign oldT, JCAssign newT, int[] bounds) {
963         int localPointer = bounds[0];
964         // lhs
965
int[] lhsBounds = getBounds(oldT.lhs);
966         copyTo(localPointer, lhsBounds[0]);
967         localPointer = diffTree(oldT.lhs, newT.lhs, lhsBounds);
968         // rhs
969
int[] rhsBounds = getBounds(oldT.rhs);
970         copyTo(localPointer, rhsBounds[0]);
971         localPointer = diffTree(oldT.rhs, newT.rhs, rhsBounds);
972         
973         copyTo(localPointer, bounds[1]);
974         return bounds[1];
975     }
976
977     protected int diffAssignop(JCAssignOp oldT, JCAssignOp newT, int[] bounds) {
978         int localPointer = bounds[0];
979         // lhs
980
int[] lhsBounds = getBounds(oldT.lhs);
981         copyTo(localPointer, lhsBounds[0]);
982         localPointer = diffTree(oldT.lhs, newT.lhs, lhsBounds);
983         if (oldT.tag != newT.tag) { // todo (#pf): operatorName() does not work
984
copyTo(localPointer, oldT.pos);
985             printer.print(getAssignementOperator(newT));
986             localPointer = oldT.pos + getAssignementOperator(oldT).length();
987         }
988         // rhs
989
int[] rhsBounds = getBounds(oldT.rhs);
990         copyTo(localPointer, rhsBounds[0]);
991         localPointer = diffTree(oldT.rhs, newT.rhs, rhsBounds);
992         
993         copyTo(localPointer, bounds[1]);
994         return bounds[1];
995     }
996     
997     String JavaDoc getAssignementOperator(Tree t) {
998         String JavaDoc name;
999         switch (t.getKind()) {
1000            case MULTIPLY_ASSIGNMENT: return "*=";
1001            case DIVIDE_ASSIGNMENT: return "/=";
1002            case REMAINDER_ASSIGNMENT: return "%=";
1003            case PLUS_ASSIGNMENT: return "+=";
1004            case MINUS_ASSIGNMENT: return "-=";
1005            case LEFT_SHIFT_ASSIGNMENT: return "<<=";
1006            case RIGHT_SHIFT_ASSIGNMENT: return ">>=";
1007            case AND_ASSIGNMENT: return "&=";
1008            case XOR_ASSIGNMENT: return "^=";
1009            case OR_ASSIGNMENT: return "|=";
1010            case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT: return ">>>=";
1011            default:
1012                throw new IllegalArgumentException JavaDoc("Illegal kind " + t.getKind());
1013        }
1014    }
1015
1016    protected int diffUnary(JCUnary oldT, JCUnary newT, int[] bounds) {
1017        int localPointer = bounds[0];
1018        int[] argBounds = getBounds(oldT.arg);
1019        copyTo(localPointer, argBounds[0]);
1020        localPointer = diffTree(oldT.arg, newT.arg, argBounds);
1021        if (oldT.tag != newT.tag) {
1022            copyTo(localPointer, oldT.pos);
1023            printer.print(operatorName(newT.tag));
1024            localPointer = oldT.pos + operatorName(oldT.tag).length();
1025        }
1026        copyTo(localPointer, bounds[1]);
1027        return bounds[1];
1028    }
1029
1030    protected int diffBinary(JCBinary oldT, JCBinary newT, int[] bounds) {
1031        int localPointer = bounds[0];
1032        
1033        int[] lhsBounds = getBounds(oldT.lhs);
1034        copyTo(localPointer, lhsBounds[0]);
1035        localPointer = diffTree(oldT.lhs, newT.lhs, lhsBounds);
1036        if (oldT.tag != newT.tag) {
1037            copyTo(localPointer, oldT.pos);
1038            printer.print(operatorName(newT.tag));
1039            localPointer = oldT.pos + operatorName(oldT.tag).toString().length();
1040        }
1041        int[] rhsBounds = getBounds(oldT.rhs);
1042        copyTo(localPointer, rhsBounds[0]);
1043        localPointer = diffTree(oldT.rhs, newT.rhs, rhsBounds);
1044        copyTo(localPointer, bounds[1]);
1045        return bounds[1];
1046    }
1047    
1048    private String JavaDoc operatorName(int tag) {
1049        // dummy instance, just to access a public method which should be static
1050
return new Pretty(null, false).operatorName(tag);
1051    }
1052
1053    protected int diffTypeCast(JCTypeCast oldT, JCTypeCast newT, int[] bounds) {
1054        int localPointer = bounds[0];
1055        // indexed
1056
int[] clazzBounds = getBounds(oldT.clazz);
1057        copyTo(localPointer, clazzBounds[0]);
1058        localPointer = diffTree(oldT.clazz, newT.clazz, clazzBounds);
1059        // expression
1060
int[] exprBounds = getBounds(oldT.expr);
1061        copyTo(localPointer, exprBounds[0]);
1062        localPointer = diffTree(oldT.expr, newT.expr, exprBounds);
1063        copyTo(localPointer, bounds[1]);
1064        
1065        return bounds[1];
1066    }
1067
1068    protected int diffTypeTest(JCInstanceOf oldT, JCInstanceOf newT, int[] bounds) {
1069        int localPointer = bounds[0];
1070        // expr
1071
int[] exprBounds = getBounds(oldT.expr);
1072        copyTo(localPointer, exprBounds[0]);
1073        localPointer = diffTree(oldT.expr, newT.expr, exprBounds);
1074        // clazz
1075
int[] clazzBounds = getBounds(oldT.clazz);
1076        copyTo(localPointer, clazzBounds[0]);
1077        localPointer = diffTree(oldT.clazz, newT.clazz, clazzBounds);
1078        copyTo(localPointer, bounds[1]);
1079        
1080        return bounds[1];
1081    }
1082
1083    protected int diffIndexed(JCArrayAccess oldT, JCArrayAccess newT, int[] bounds) {
1084        int localPointer = bounds[0];
1085        // indexed
1086
int[] indexedBounds = getBounds(oldT.indexed);
1087        copyTo(localPointer, indexedBounds[0]);
1088        localPointer = diffTree(oldT.indexed, newT.indexed, indexedBounds);
1089        // index
1090
int[] indexBounds = getBounds(oldT.index);
1091        copyTo(localPointer, indexBounds[0]);
1092        localPointer = diffTree(oldT.index, newT.index, indexBounds);
1093        copyTo(localPointer, bounds[1]);
1094        
1095        return bounds[1];
1096    }
1097
1098    protected int diffSelect(JCFieldAccess oldT, JCFieldAccess newT, int[] bounds) {
1099        int localPointer = bounds[0];
1100        copyTo(localPointer, getOldPos(oldT.selected));
1101        localPointer = diffTree(oldT.selected, newT.selected, getBounds(oldT.selected));
1102        if (nameChanged(oldT.name, newT.name)) {
1103            copyTo(localPointer, endPos(oldT.selected));
1104            printer.print(".");
1105            printer.print(newT.name);
1106            diffInfo.put(endPos(oldT.selected) + 1, "Update reference to " + oldT.name);
1107            localPointer = endPos(oldT.selected) + 1 +oldT.name.length();
1108        }
1109        copyTo(localPointer, bounds[1]);
1110        return bounds[1];
1111    }
1112
1113    protected int diffIdent(JCIdent oldT, JCIdent newT, int lastPrinted) {
1114        if (nameChanged(oldT.name, newT.name)) {
1115            copyTo(lastPrinted, oldT.pos);
1116            printer.print(newT.name);
1117            diffInfo.put(oldT.pos, "Update reference to " + oldT.name);
1118            return endPos(oldT);
1119        }
1120        return lastPrinted;
1121    }
1122
1123    protected int diffLiteral(JCLiteral oldT, JCLiteral newT, int[] bounds) {
1124        if (oldT.typetag != newT.typetag || !oldT.value.equals(newT.value)) {
1125            int localPointer = bounds[0];
1126            // literal
1127
int[] literalBounds = getBounds(oldT);
1128            copyTo(localPointer, literalBounds[0]);
1129            printer.print(newT);
1130            copyTo(literalBounds[1], bounds[1]);
1131        } else {
1132            copyTo(bounds[0], bounds[1]);
1133        }
1134        return bounds[1];
1135    }
1136
1137    protected void diffTypeIdent(JCPrimitiveTypeTree oldT, JCPrimitiveTypeTree newT) {
1138        if (oldT.typetag != newT.typetag)
1139            append(Diff.modify(oldT, getOldPos(oldT), newT));
1140    }
1141
1142    protected int diffTypeArray(JCArrayTypeTree oldT, JCArrayTypeTree newT, int[] bounds) {
1143        int localPointer = bounds[0];
1144        copyTo(localPointer, bounds[0]);
1145        int[] elemtypeBounds = getBounds(oldT.elemtype);
1146        localPointer = diffTree(oldT.elemtype, newT.elemtype, elemtypeBounds);
1147        copyTo(localPointer, bounds[1]);
1148        return bounds[1];
1149    }
1150
1151    protected int diffTypeApply(JCTypeApply oldT, JCTypeApply newT, int[] bounds) {
1152        int localPointer = bounds[0];
1153        int[] clazzBounds = getBounds(oldT.clazz);
1154        copyTo(localPointer, clazzBounds[0]);
1155        localPointer = diffTree(oldT.clazz, newT.clazz, clazzBounds);
1156        if (!listsMatch(oldT.arguments, newT.arguments)) {
1157            int pos = oldT.arguments.nonEmpty() ? getOldPos(oldT.arguments.head) : endPos(oldT.clazz);
1158            if (newT.arguments.nonEmpty())
1159                copyTo(localPointer, pos);
1160            VeryPretty locBuf = new VeryPretty(context);
1161            localPointer = diffParameterList(
1162                    oldT.arguments,
1163                    newT.arguments,
1164                    oldT.arguments.isEmpty() || newT.arguments.isEmpty(),
1165                    pos,
1166                    locBuf
1167            );
1168            printer.print(locBuf.toString());
1169        }
1170        copyTo(localPointer, bounds[1]);
1171        return bounds[1];
1172    }
1173
1174    protected int diffTypeParameter(JCTypeParameter oldT, JCTypeParameter newT, int[] bounds) {
1175        int localPointer = bounds[0];
1176        copyTo(localPointer, getOldPos(oldT));
1177        if (nameChanged(oldT.name, newT.name)) {
1178            printer.print(newT.name);
1179            localPointer += oldT.name.length();
1180        }
1181        // todo: finish parameters!
1182
// diffParameterList(oldT.bounds, newT.bounds, -1);
1183
copyTo(localPointer, bounds[1]);
1184        return bounds[1];
1185    }
1186    
1187    protected int diffWildcard(JCWildcard oldT, JCWildcard newT, int[] bounds) {
1188        int localPointer = bounds[0];
1189        if (oldT.kind != newT.kind) {
1190            copyTo(localPointer, oldT.pos);
1191            printer.print(newT.kind.toString());
1192            localPointer = oldT.pos + oldT.kind.toString().length();
1193        }
1194        int[] innerBounds = getBounds(oldT.inner);
1195        copyTo(localPointer, innerBounds[0]);
1196        localPointer = diffTree(oldT.inner, newT.inner, innerBounds);
1197        copyTo(localPointer, bounds[1]);
1198        
1199        return bounds[1];
1200    }
1201    
1202    protected int diffTypeBoundKind(TypeBoundKind oldT, TypeBoundKind newT, int[] bounds) {
1203        int localPointer = bounds[0];
1204        if (oldT.kind != newT.kind) {
1205            copyTo(localPointer, oldT.pos);
1206            printer.print(newT.kind.toString());
1207            localPointer = oldT.pos + oldT.kind.toString().length();
1208        }
1209        copyTo(localPointer, bounds[1]);
1210        return bounds[1];
1211    }
1212    
1213    protected int diffAnnotation(JCAnnotation oldT, JCAnnotation newT, int[] bounds) {
1214        int localPointer = bounds[0];
1215        int[] annotationBounds = getBounds(oldT.annotationType);
1216        copyTo(localPointer,annotationBounds[0]);
1217        localPointer = diffTree(oldT.annotationType, newT.annotationType, annotationBounds);
1218        diffParameterList(oldT.args, newT.args, -1);
1219        copyTo(localPointer, bounds[1]);
1220        
1221        return bounds[1];
1222    }
1223    
1224    protected int diffModifiers(JCModifiers oldT, JCModifiers newT, JCTree parent, int lastPrinted) {
1225        if (oldT == newT) {
1226            // modifiers wasn't changed, return the position lastPrinted.
1227
return lastPrinted;
1228        }
1229        int result = endPos(oldT.annotations);
1230        int oldPos = oldT.pos != Position.NOPOS ? getOldPos(oldT) : getOldPos(parent);
1231        if (listsMatch(oldT.annotations, newT.annotations)) {
1232            copyTo(lastPrinted, lastPrinted = oldPos);
1233            if (result > 0) {
1234                copyTo(lastPrinted, lastPrinted = result);
1235            } else {
1236            }
1237        } else {
1238            if (oldT.annotations.isEmpty()) copyTo(lastPrinted, oldPos);
1239            PositionEstimator est = EstimatorFactory.members(((ModifiersTree) oldT).getAnnotations(), ((ModifiersTree) newT).getAnnotations(), workingCopy);
1240            int[] res = diffList(oldT.annotations, newT.annotations, oldPos, est, Measure.DEFAULT, printer);
1241            lastPrinted = res[1];
1242            //printer.printAnnotations(newT.annotations);
1243
// if (result > 0) {
1244
// copyTo(lastPrinted, lastPrinted = result);
1245
// }
1246
}
1247        if (oldT.flags != newT.flags) {
1248            int endPos = endPos(oldT);
1249            if (endPos > 0) {
1250                printer.print(newT.toString().trim());
1251                lastPrinted = endPos;
1252            } else {
1253                printer.print(newT.toString());
1254            }
1255        }
1256        if (endPos(oldT) > 0) {
1257            copyTo(lastPrinted, endPos(oldT));
1258            return endPos(oldT);
1259        } else {
1260            return lastPrinted;
1261        }
1262    }
1263    
1264    protected void diffLetExpr(LetExpr oldT, LetExpr newT) {
1265        diffList(oldT.defs, newT.defs, LineInsertionType.NONE, Query.NOPOS);
1266        diffTree(oldT.expr, newT.expr, getBounds(oldT.expr));
1267    }
1268    
1269    protected void diffErroneous(JCErroneous oldT, JCErroneous newT) {
1270        diffList(oldT.errs, newT.errs, LineInsertionType.BEFORE, Query.NOPOS);
1271    }
1272
1273    protected boolean listContains(List<? extends JCTree> list, JCTree tree) {
1274        for (JCTree t : list)
1275            if (treesMatch(t, tree))
1276                return true;
1277        return false;
1278    }
1279
1280    protected boolean treesMatch(JCTree t1, JCTree t2) {
1281        return treesMatch(t1, t2, true);
1282    }
1283    
1284    public boolean treesMatch(JCTree t1, JCTree t2, boolean deepMatch) {
1285        if (t1 == t2)
1286            return true;
1287        if (t1 == null || t2 == null)
1288            return false;
1289        if (t1.tag != t2.tag)
1290            return false;
1291        if (!deepMatch)
1292            return true;
1293        
1294        // don't use visitor, since we want fast-fail behavior
1295
switch (t1.tag) {
1296          case JCTree.TOPLEVEL:
1297              return ((JCCompilationUnit)t1).sourcefile.equals(((JCCompilationUnit)t2).sourcefile);
1298          case JCTree.IMPORT:
1299              return matchImport((JCImport)t1, (JCImport)t2);
1300          case JCTree.CLASSDEF:
1301              return ((JCClassDecl)t1).sym == ((JCClassDecl)t2).sym;
1302          case JCTree.METHODDEF:
1303              return ((JCMethodDecl)t1).sym == ((JCMethodDecl)t2).sym;
1304          case JCTree.VARDEF:
1305              return ((JCVariableDecl)t1).sym == ((JCVariableDecl)t2).sym;
1306          case JCTree.SKIP:
1307              return true;
1308          case JCTree.BLOCK:
1309              return matchBlock((JCBlock)t1, (JCBlock)t2);
1310          case JCTree.DOLOOP:
1311              return matchDoLoop((JCDoWhileLoop)t1, (JCDoWhileLoop)t2);
1312          case JCTree.WHILELOOP:
1313              return matchWhileLoop((JCWhileLoop)t1, (JCWhileLoop)t2);
1314          case JCTree.FORLOOP:
1315              return matchForLoop((JCForLoop)t1, (JCForLoop)t2);
1316          case JCTree.FOREACHLOOP:
1317              return matchForeachLoop((JCEnhancedForLoop)t1, (JCEnhancedForLoop)t2);
1318          case JCTree.LABELLED:
1319              return matchLabelled((JCLabeledStatement)t1, (JCLabeledStatement)t2);
1320          case JCTree.SWITCH:
1321              return matchSwitch((JCSwitch)t1, (JCSwitch)t2);
1322          case JCTree.CASE:
1323              return matchCase((JCCase)t1, (JCCase)t2);
1324          case JCTree.SYNCHRONIZED:
1325              return matchSynchronized((JCSynchronized)t1, (JCSynchronized)t2);
1326          case JCTree.TRY:
1327              return matchTry((JCTry)t1, (JCTry)t2);
1328          case JCTree.CATCH:
1329              return matchCatch((JCCatch)t1, (JCCatch)t2);
1330          case JCTree.CONDEXPR:
1331              return matchConditional((JCConditional)t1, (JCConditional)t2);
1332          case JCTree.IF:
1333              return matchIf((JCIf)t1, (JCIf)t2);
1334          case JCTree.EXEC:
1335              return treesMatch(((JCExpressionStatement)t1).expr, ((JCExpressionStatement)t2).expr);
1336          case JCTree.BREAK:
1337              return matchBreak((JCBreak)t1, (JCBreak)t2);
1338          case JCTree.CONTINUE:
1339              return matchContinue((JCContinue)t1, (JCContinue)t2);
1340          case JCTree.RETURN:
1341              return treesMatch(((JCReturn)t1).expr, ((JCReturn)t2).expr);
1342          case JCTree.THROW:
1343              return treesMatch(((JCThrow)t1).expr, ((JCThrow)t2).expr);
1344          case JCTree.ASSERT:
1345              return matchAssert((JCAssert)t1, (JCAssert)t2);
1346          case JCTree.APPLY:
1347              return matchApply((JCMethodInvocation)t1, (JCMethodInvocation)t2);
1348          case JCTree.NEWCLASS:
1349              // #97501: workaround. Not sure about comparing symbols and their
1350
// copying in ImmutableTreeTranslator, making workaround with
1351
// minimal impact - issue has to be fixed correctly in the future.
1352
if (((JCNewClass)t2).def != null) ((JCNewClass)t2).def.sym = null;
1353              return matchNewClass((JCNewClass)t1, (JCNewClass)t2);
1354          case JCTree.NEWARRAY:
1355              return matchNewArray((JCNewArray)t1, (JCNewArray)t2);
1356          case JCTree.PARENS:
1357              return treesMatch(((JCParens)t1).expr, ((JCParens)t2).expr);
1358          case JCTree.ASSIGN:
1359              return matchAssign((JCAssign)t1, (JCAssign)t2);
1360          case JCTree.TYPECAST:
1361              return matchTypeCast((JCTypeCast)t1, (JCTypeCast)t2);
1362          case JCTree.TYPETEST:
1363              return matchTypeTest((JCInstanceOf)t1, (JCInstanceOf)t2);
1364          case JCTree.INDEXED:
1365              return matchIndexed((JCArrayAccess)t1, (JCArrayAccess)t2);
1366          case JCTree.SELECT:
1367              return matchSelect((JCFieldAccess) t1, (JCFieldAccess) t2);
1368          case JCTree.IDENT:
1369              return ((JCIdent)t1).sym == ((JCIdent)t2).sym;
1370          case JCTree.LITERAL:
1371              return matchLiteral((JCLiteral)t1, (JCLiteral)t2);
1372          case JCTree.TYPEIDENT:
1373              return ((JCPrimitiveTypeTree)t1).typetag == ((JCPrimitiveTypeTree)t2).typetag;
1374          case JCTree.TYPEARRAY:
1375              return treesMatch(((JCArrayTypeTree)t1).elemtype, ((JCArrayTypeTree)t2).elemtype);
1376          case JCTree.TYPEAPPLY:
1377              return matchTypeApply((JCTypeApply)t1, (JCTypeApply)t2);
1378          case JCTree.TYPEPARAMETER:
1379              return matchTypeParameter((JCTypeParameter)t1, (JCTypeParameter)t2);
1380          case JCTree.WILDCARD:
1381              return matchWildcard((JCWildcard)t1, (JCWildcard)t2);
1382          case JCTree.TYPEBOUNDKIND:
1383              return ((TypeBoundKind)t1).kind == ((TypeBoundKind)t2).kind;
1384          case JCTree.ANNOTATION:
1385              return matchAnnotation((JCAnnotation)t1, (JCAnnotation)t2);
1386          case JCTree.LETEXPR:
1387              return matchLetExpr((LetExpr)t1, (LetExpr)t2);
1388          case JCTree.POS:
1389          case JCTree.NEG:
1390          case JCTree.NOT:
1391          case JCTree.COMPL:
1392          case JCTree.PREINC:
1393          case JCTree.PREDEC:
1394          case JCTree.POSTINC:
1395          case JCTree.POSTDEC:
1396          case JCTree.NULLCHK:
1397              return matchUnary((JCUnary)t1, (JCUnary)t2);
1398          case JCTree.OR:
1399          case JCTree.AND:
1400          case JCTree.BITOR:
1401          case JCTree.BITXOR:
1402          case JCTree.BITAND:
1403          case JCTree.EQ:
1404          case JCTree.NE:
1405          case JCTree.LT:
1406          case JCTree.GT:
1407          case JCTree.LE:
1408          case JCTree.GE:
1409          case JCTree.SL:
1410          case JCTree.SR:
1411          case JCTree.USR:
1412          case JCTree.PLUS:
1413          case JCTree.MINUS:
1414          case JCTree.MUL:
1415          case JCTree.DIV:
1416          case JCTree.MOD:
1417              return matchBinary((JCBinary)t1, (JCBinary)t2);
1418          case JCTree.BITOR_ASG:
1419          case JCTree.BITXOR_ASG:
1420          case JCTree.BITAND_ASG:
1421          case JCTree.SL_ASG:
1422          case JCTree.SR_ASG:
1423          case JCTree.USR_ASG:
1424          case JCTree.PLUS_ASG:
1425          case JCTree.MINUS_ASG:
1426          case JCTree.MUL_ASG:
1427          case JCTree.DIV_ASG:
1428          case JCTree.MOD_ASG:
1429              return matchAssignop((JCAssignOp)t1, (JCAssignOp)t2);
1430          default:
1431              String JavaDoc msg = ((com.sun.source.tree.Tree)t1).getKind().toString() +
1432                      " " + t1.getClass().getName();
1433              throw new AssertionError JavaDoc(msg);
1434        }
1435    }
1436
1437    protected boolean nameChanged(Name oldName, Name newName) {
1438        if (oldName == newName)
1439            return false;
1440        byte[] arr1 = oldName.toUtf();
1441        byte[] arr2 = newName.toUtf();
1442        int len = arr1.length;
1443        if (len != arr2.length)
1444            return true;
1445        for (int i = 0; i < len; i++)
1446            if (arr1[i] != arr2[i])
1447                return true;
1448        return false;
1449    }
1450
1451    /**
1452     * Diff an unordered list, which may contain insertions and deletions.
1453     * REMOVE IT WHEN CORRECT LIST MATCHING WILL BE IMPLEMENTED
1454     */

1455    protected int diffList(List<? extends JCTree> oldList,
1456                            List<? extends JCTree> newList,
1457                            LineInsertionType newLine, int insertHint) {
1458        int lastPrinted = insertHint;
1459        if (oldList == newList)
1460            return insertHint;
1461        assert oldList != null && newList != null;
1462        int lastOldPos = insertHint;
1463        Iterator JavaDoc<? extends JCTree> oldIter = oldList.iterator();
1464        Iterator JavaDoc<? extends JCTree> newIter = newList.iterator();
1465        JCTree oldT = safeNext(oldIter);
1466        JCTree newT = safeNext(newIter);
1467        while (oldT != null && newT != null) {
1468            if (oldTopLevel != null) {
1469                int endPos = model.getEndPos(oldT, oldTopLevel);
1470
1471                if (endPos != Position.NOPOS)
1472                    lastOldPos = endPos;
1473            }
1474            if (treesMatch(oldT, newT, false)) {
1475                lastPrinted = diffTree(oldT, newT, new int[] { getOldPos(oldT), endPos(oldT) });
1476                oldT = safeNext(oldIter);
1477                newT = safeNext(newIter);
1478            }
1479            else if (!listContains(newList, oldT) && !listContains(oldList, newT)) {
1480                append(Diff.modify(oldT, getOldPos(oldT), newT));
1481                oldT = safeNext(oldIter);
1482                newT = safeNext(newIter);
1483            }
1484            else if (!listContains(newList, oldT)) {
1485                if (!isHidden(oldT, oldParent))
1486                    append(Diff.delete(oldT, getOldPos(oldT)));
1487                oldT = safeNext(oldIter);
1488            }
1489            else {
1490                if (!isHidden(newT, newParent))
1491                    append(Diff.insert(newT, getOldPos(oldT), newLine, null));
1492                newT = safeNext(newIter);
1493            }
1494        }
1495        while (oldT != null) {
1496            if (!isHidden(oldT, oldParent))
1497                append(Diff.delete(oldT, getOldPos(oldT)));
1498            if (oldTopLevel != null)
1499                lastOldPos = model.getEndPos(oldT, oldTopLevel);
1500            oldT = safeNext(oldIter);
1501        }
1502        while (newT != null) {
1503            if (!isHidden(newT, newParent))
1504                append(Diff.insert(newT, lastOldPos, newLine, null));
1505            newT = safeNext(newIter);
1506        }
1507        return lastPrinted;
1508    }
1509    
1510    private JCTree safeNext(Iterator JavaDoc<? extends JCTree> iter) {
1511        return iter.hasNext() ? iter.next() : null;
1512    }
1513
1514    // XXX: this method should be removed later when all call will be
1515
// refactored and will use new list matching
1516
protected int diffParameterList(List<? extends JCTree> oldList, List<? extends JCTree> newList, int localPointer) {
1517        if (oldList == newList)
1518            return localPointer;
1519        assert oldList != null && newList != null;
1520        int lastOldPos = Query.NOPOS;
1521        Iterator JavaDoc<? extends JCTree> oldIter = oldList.iterator();
1522        Iterator JavaDoc<? extends JCTree> newIter = newList.iterator();
1523        while (oldIter.hasNext() && newIter.hasNext()) {
1524            JCTree oldT = oldIter.next();
1525            copyTo(localPointer, localPointer = getOldPos(oldT));
1526            localPointer = diffTree(oldT, newIter.next(), new int[] { localPointer, endPos(oldT) });
1527            if (oldTopLevel != null)
1528                lastOldPos = model.getEndPos(oldT, oldTopLevel);
1529        }
1530        while (oldIter.hasNext()) {
1531            JCTree oldT = oldIter.next();
1532            append(Diff.delete(oldT, getOldPos(oldT)));
1533        }
1534        while (newIter.hasNext()) {
1535            append(Diff.insert(newIter.next(), lastOldPos, LineInsertionType.BEFORE));
1536        }
1537        return localPointer;
1538    }
1539    
1540    /**
1541     * Diff a ordered list for differences.
1542     */

1543    protected int diffList2(
1544        List<? extends JCTree> oldList, List<? extends JCTree> newList,
1545        int initialPos, PositionEstimator estimator)
1546    {
1547        if (oldList == newList)
1548            return initialPos;
1549        assert oldList != null && newList != null;
1550        int lastOldPos = initialPos;
1551        
1552        ListMatcher<JCTree> matcher = ListMatcher.<JCTree>instance(
1553                (List<JCTree>) oldList,
1554                (List<JCTree>) newList
1555        );
1556        if (!matcher.match()) {
1557            return initialPos;
1558        }
1559        Iterator JavaDoc<? extends JCTree> oldIter = oldList.iterator();
1560        ResultItem<JCTree>[] result = matcher.getTransformedResult();
1561        Separator s = matcher.separatorInstance();
1562        s.compute();
1563        int[][] matrix = estimator.getMatrix();
1564        int testPos = initialPos;
1565        int i = 0;
1566        for (int j = 0; j < result.length; j++) {
1567            JCTree oldT;
1568            ResultItem<JCTree> item = result[j];
1569            switch (item.operation) {
1570                case MODIFY: {
1571                    // perhaps I shouldn't support this!
1572
tokenSequence.moveIndex(matrix[i][4]);
1573                    if (tokenSequence.moveNext()) {
1574                        testPos = tokenSequence.offset();
1575                        if (JavaTokenId.COMMA == tokenSequence.token().id())
1576                            testPos += JavaTokenId.COMMA.fixedText().length();
1577                    }
1578                    oldT = oldIter.next(); ++i;
1579                    copyTo(lastOldPos, getOldPos(oldT));
1580                    if (treesMatch(oldT, item.element, false)) {
1581                        lastOldPos = diffTree(oldT, item.element, getBounds(oldT));
1582                    } else {
1583                        printer.print(item.element);
1584                        lastOldPos = endPos(oldT);
1585                    }
1586                    break;
1587                }
1588                case INSERT: {
1589                    String JavaDoc prec = s.head(j) ? estimator.head() : s.prev(j) ? estimator.sep() : null;
1590                    String JavaDoc tail = s.next(j) ? estimator.sep() : null;
1591                    if (estimator.getIndentString() != null && !estimator.getIndentString().equals(" ")) {
1592                        prec += estimator.getIndentString();
1593                    }
1594                    copyTo(lastOldPos, testPos);
1595                    printer.print(prec);
1596                    printer.print(item.element);
1597                    printer.print(tail);
1598                    //append(Diff.insert(testPos, prec, item.element, tail, LineInsertionType.NONE));
1599
break;
1600                }
1601                case DELETE: {
1602                    // compute offsets for removal (tree bounds are not enough
1603
// in this case, we have to remove also tokens around like
1604
// preceding keyword, i.e. throws, implements etc. and also
1605
// separators like commas.
1606

1607                    // this is a hack: be careful when removing the first:
1608
// throws Exception,IOException... do not remove the space
1609
// after throws keyword, there is not space after comma!
1610
int delta = 0;
1611                    if (i == 0 && matrix[i+1][2] != -1 && matrix[i+1][2] == matrix[i+1][3]) {
1612                        ++delta;
1613                    }
1614                    int startOffset = toOff(s.head(j) || s.prev(j) ? matrix[i][1] : matrix[i][2+delta]);
1615                    int endOffset = toOff(s.tail(j) || s.next(j) ? matrix[i+1][2] : matrix[i][4]);
1616                    assert startOffset != -1 && endOffset != -1 : "Invalid offset!";
1617                    //printer.print(origText.substring(lastOldPos, startOffset));
1618
//append(Diff.delete(startOffset, endOffset));
1619
tokenSequence.moveIndex(matrix[i][4]);
1620                    if (tokenSequence.moveNext()) {
1621                        testPos = tokenSequence.offset();
1622                        if (JavaTokenId.COMMA == tokenSequence.token().id())
1623                            testPos += JavaTokenId.COMMA.fixedText().length();
1624                    }
1625                    if (i == 0 && !newList.isEmpty()) {
1626                        lastOldPos = endOffset;
1627                    } else {
1628                        lastOldPos = endPos(item.element);
1629                    }
1630                    oldT = oldIter.next(); ++i;
1631                    break;
1632                }
1633                case NOCHANGE: {
1634                    tokenSequence.moveIndex(matrix[i][4]);
1635                    if (tokenSequence.moveNext()) {
1636                        testPos = tokenSequence.offset();
1637                        if (JavaTokenId.COMMA == tokenSequence.token().id())
1638                            testPos += JavaTokenId.COMMA.fixedText().length();
1639                    }
1640                    oldT = oldIter.next(); ++i;
1641                    copyTo(lastOldPos, lastOldPos = endPos(oldT));
1642                    break;
1643                }
1644            }
1645        }
1646        return lastOldPos;
1647    }
1648
1649    private int toOff(int tokenIndex) {
1650        if (tokenIndex == -1) {
1651            return -1;
1652        }
1653        tokenSequence.moveIndex(tokenIndex);
1654        tokenSequence.moveNext();
1655        return tokenSequence.offset();
1656    }
1657    
1658    /**
1659     * Diff two lists of parameters separated by comma. It is used e.g.
1660     * from type parameters and method parameters.
1661     *
1662     */

1663    private int diffParameterList(
1664            List<? extends JCTree> oldList,
1665            List<? extends JCTree> newList,
1666            boolean printParen,
1667            int pos,
1668            VeryPretty buf)
1669    {
1670        if (oldList == newList || (oldList.isEmpty() && newList.isEmpty()))
1671            return pos; // they match perfectly or no need to do anything
1672

1673        assert oldList != null && newList != null;
1674        
1675        if (newList.isEmpty()) {
1676            int endPos = endPos(oldList);
1677            if (printParen) {
1678                tokenSequence.move(endPos);
1679                TokenUtilities.moveFwdToToken(tokenSequence, endPos, JavaTokenId.GT);
1680                tokenSequence.moveNext();
1681                endPos = tokenSequence.offset();
1682                if (!PositionEstimator.nonRelevant.contains(tokenSequence.token()))
1683                    buf.print(" "); // use options, if mods should be at new line
1684
}
1685            return endPos;
1686        }
1687        ListMatcher<JCTree> matcher = ListMatcher.<JCTree>instance(
1688                (List<JCTree>) oldList,
1689                (List<JCTree>) newList
1690        );
1691        if (!matcher.match()) {
1692            // nothing in the list, no need to print and nothing was printed
1693
return pos;
1694        }
1695        ResultItem<JCTree>[] result = matcher.getResult();
1696        if (printParen && oldList.isEmpty()) {
1697            buf.print(JavaTokenId.LT.fixedText());
1698        }
1699        JCTree lastDeleted = null;
1700        for (int index = 0, j = 0; j < result.length; j++) {
1701            ResultItem<JCTree> item = result[j];
1702            switch (item.operation) {
1703                // insert new element
1704
case INSERT:
1705                    if (index++ > 0) buf.print(",");
1706                    if (lastDeleted != null && treesMatch(lastDeleted, item.element, false)) {
1707                        VeryPretty mainPrint = this.printer;
1708                        this.printer = buf;
1709                        diffTree(lastDeleted, item.element, getBounds(lastDeleted));
1710                        this.printer = mainPrint;
1711                    } else {
1712                        buf.print(item.element);
1713                    }
1714                    lastDeleted = null;
1715                    break;
1716                case DELETE:
1717                    lastDeleted = item.element;
1718                    break;
1719                // just copy existing element
1720
case NOCHANGE:
1721                    if (index++ > 0) buf.print(",");
1722                    int[] bounds = getBounds(item.element);
1723                    tokenSequence.move(bounds[0]);
1724                    TokenUtilities.movePrevious(tokenSequence, bounds[0]);
1725                    tokenSequence.moveNext();
1726                    int start = tokenSequence.offset();
1727                    TokenUtilities.moveNext(tokenSequence, bounds[1]);
1728                    int end = tokenSequence.offset();
1729                    copyTo(start, end, buf);
1730                    lastDeleted = null;
1731                    break;
1732                default:
1733                    break;
1734            }
1735        }
1736        if (printParen && oldList.isEmpty()) {
1737            buf.print(JavaTokenId.GT.fixedText());
1738            buf.print(" "); // part of options?
1739
}
1740        return oldList.isEmpty() ? pos : endPos(oldList);
1741    }
1742    
1743    /**
1744     * Used for diffing lists which does not contain any separator.
1745     * (Currently for imports and members diffing.)
1746     */

1747    private int[] diffList(
1748            List<? extends JCTree> oldList,
1749            List<? extends JCTree> newList,
1750            int initialPos,
1751            PositionEstimator estimator,
1752            Measure measure,
1753            VeryPretty printer)
1754    {
1755        int[] ret = new int[] { -1, -1 };
1756        if (oldList == newList) {
1757            return ret;
1758        }
1759        assert oldList != null && newList != null;
1760        
1761        ListMatcher<JCTree> matcher = ListMatcher.instance(
1762                oldList,
1763                newList,
1764                measure
1765        );
1766        if (!matcher.match()) {
1767            return ret;
1768        }
1769        JCTree lastdel = null; // last deleted element
1770
ResultItem<JCTree>[] result = matcher.getResult();
1771        int posHint = initialPos;
1772        int i = 0;
1773        for (int j = 0; j < result.length; j++) {
1774            ResultItem<JCTree> item = result[j];
1775            switch (item.operation) {
1776                case MODIFY: {
1777                    assert true : "Modify is no longer operated!";
1778                    break;
1779                }
1780                case INSERT: {
1781                    int pos = estimator.getInsertPos(i);
1782                    // estimator couldn't compute the position - probably
1783
// first element is inserted to the collection
1784
String JavaDoc head = "", tail = "";
1785                    if (pos < 0 && oldList.isEmpty() && i == 0) {
1786                        pos = initialPos;
1787                        StringBuilder JavaDoc aHead = new StringBuilder JavaDoc(), aTail = new StringBuilder JavaDoc();
1788                        pos = estimator.prepare(initialPos, aHead, aTail);
1789                        if (j+1 == result.length) {
1790                            tail = aTail.toString();
1791                        }
1792                        head = aHead.toString();
1793                        posHint = pos;
1794                        if (ret[0] < 0) ret[0] = posHint;
1795                        if (ret[1] < 0) ret[1] = posHint;
1796                    } else {
1797                        if (ret[0] < 0) ret[0] = posHint;
1798                        if (ret[1] < 0) ret[1] = posHint;
1799                    }
1800                    int oldPos = item.element.getKind() != Kind.VARIABLE ? getOldPos(item.element) : item.element.pos;
1801                    boolean found = false;
1802                    if (oldPos > 0) {
1803                        for (JCTree oldT : oldList) {
1804                            int oldNodePos = oldT.getKind() != Kind.VARIABLE ? getOldPos(oldT) : oldT.pos;
1805                            if (oldPos == oldNodePos) {
1806                                found = true;
1807                                VeryPretty oldPrinter = this.printer;
1808                                int old = oldPrinter.indent();
1809                                this.printer = new VeryPretty(context, JavaFormatOptions.getDefault());
1810                                this.printer.reset(old);
1811                                int index = oldList.indexOf(oldT);
1812                                int[] poss = estimator.getPositions(index);
1813                                diffTree(oldT, item.element, poss);
1814                                printer.print(this.printer.toString());
1815// if (pointer < poss[1])
1816
// printer.print(origText.substring(pointer, pointer = poss[1]));
1817
this.printer = oldPrinter;
1818                                this.printer.undent(old);
1819                                break;
1820                            }
1821                        }
1822                    }
1823                    if (!found) {
1824                        if (lastdel != null && treesMatch(item.element, lastdel, false)) {
1825                            VeryPretty oldPrinter = this.printer;
1826                            int old = oldPrinter.indent();
1827                            this.printer = new VeryPretty(context, JavaFormatOptions.getDefault());
1828                            this.printer.reset(old);
1829                            int index = oldList.indexOf(lastdel);
1830                            int[] poss = estimator.getPositions(index);
1831                            diffTree(lastdel, item.element, poss);
1832                            printer.print(this.printer.toString());
1833                            this.printer = oldPrinter;
1834                            this.printer.undent(old);
1835                            break;
1836                        }
1837                        if (j == 0 && !oldList.isEmpty()) {
1838                            posHint = estimator.getPositions(0)[0];
1839                        }
1840                        printer.print(head);
1841                        int old = printer.indent();
1842                        VeryPretty inPrint = new VeryPretty(context, JavaFormatOptions.getDefault());
1843                        inPrint.reset(old);
1844                        inPrint.enclClassName = printer.enclClassName;
1845// inPrint.indent();
1846
inPrint.print(item.element);
1847                            inPrint.newline();
1848                        printer.print(inPrint.toString());
1849                        printer.undent(old);
1850                        //printer.print(tail);
1851
// if (j+1 != result.length) {
1852
// printer.toColExactly(currentIndentLevel);
1853
// }
1854
}
1855                    break;
1856                }
1857                case DELETE: {
1858                    int[] pos = estimator.getPositions(i);
1859                    lastdel = oldList.get(i);
1860                    if (ret[0] < 0) {
1861                        ret[0] = pos[0];
1862                    }
1863                     ++i;
1864                    ret[1] = pos[1];
1865                    posHint = pos[1];
1866                    break;
1867                }
1868                case NOCHANGE: {
1869                    int[] pos = estimator.getPositions(i);
1870                    if (ret[0] < 0) {
1871                        ret[0] = pos[0];
1872                    }
1873                    copyTo(pos[0], pos[1], printer);
1874                    ret[1] = pos[1];
1875                    ++i;
1876                    break;
1877                }
1878            }
1879        }
1880        if (!oldList.isEmpty()) {
1881            Iterator JavaDoc<? extends JCTree> it = oldList.iterator();
1882            for (i = 0; it.hasNext(); i++, it.next()) ;
1883            int[] pos = estimator.getPositions(i);
1884            ret[1] = pos[1];
1885        }
1886        return ret;
1887    }
1888    
1889    private List filterHidden(List<JCTree> list) {
1890        List<JCTree> result = new ArrayList JavaDoc<JCTree>(); // todo (#pf): capacity?
1891
for (JCTree tree : list) {
1892            if (Kind.METHOD == tree.getKind()) {
1893                // filter syntetic constructors, i.e. constructors which are in
1894
// the tree, but not available in the source.
1895
if ((((JCMethodDecl)tree).mods.flags & Flags.GENERATEDCONSTR) != 0)
1896                    continue;
1897            }
1898            result.add(tree);
1899        }
1900        return result;
1901    }
1902    
1903    
1904    /**
1905     * Used for diffing lists which does not contain any separator, currently
1906     * just for imports.
1907     */

1908    private int diffListImports(
1909            List<? extends JCTree> oldList,
1910            List<? extends JCTree> newList,
1911            int localPointer,
1912            PositionEstimator estimator,
1913            Measure measure,
1914            VeryPretty printer)
1915    {
1916        if (oldList == newList) {
1917            return localPointer;
1918        }
1919        assert oldList != null && newList != null;
1920        
1921        ListMatcher<JCTree> matcher = ListMatcher.instance(
1922                oldList,
1923                newList,
1924                measure
1925        );
1926        if (!matcher.match()) {
1927            return localPointer;
1928        }
1929        JCTree lastdel = null; // last deleted element
1930
ResultItem<JCTree>[] result = matcher.getResult();
1931
1932        // if there hasn't been import but at least one is added
1933
if (oldList.isEmpty() && !newList.isEmpty()) {
1934            // such a situation needs special handling. It is difficult to
1935
// obtain a correct position.
1936
StringBuilder JavaDoc aHead = new StringBuilder JavaDoc(), aTail = new StringBuilder JavaDoc();
1937            int pos = estimator.prepare(0, aHead, aTail);
1938            copyTo(localPointer, pos, printer);
1939            printer.print(aHead.toString());
1940            for (JCTree item : newList) {
1941                if (BEFORE == estimator.lineInsertType()) printer.newline();
1942                printer.printExpr(item);
1943                if (AFTER == estimator.lineInsertType()) printer.newline();
1944            }
1945            // this should be uncommented! -- support of empty line when
1946
// first import is added and there is only one empty line between
1947
// package statement and type decl 0.
1948
// printer.print(aTail.toString());
1949
return pos;
1950        }
1951
1952        // if there has been imports which is removed now
1953
if (newList.isEmpty() && !oldList.isEmpty()) {
1954            int[] removalBounds = estimator.sectionRemovalBounds(null);
1955            copyTo(localPointer, removalBounds[0]);
1956            return removalBounds[1];
1957        }
1958        int i = 0;
1959        // copy to start position
1960
copyTo(localPointer, localPointer = estimator.getInsertPos(0), printer);
1961        // go on, match it!
1962
for (int j = 0; j < result.length; j++) {
1963            ResultItem<JCTree> item = result[j];
1964            switch (item.operation) {
1965                case INSERT: {
1966                    int pos = estimator.getInsertPos(i);
1967                    // estimator couldn't compute the position - probably
1968
// first element is inserted to the collection
1969
String JavaDoc head = "", tail = "";
1970                    if (pos < 0 && oldList.isEmpty() && i == 0) {
1971                        pos = localPointer;
1972                        StringBuilder JavaDoc aHead = new StringBuilder JavaDoc(), aTail = new StringBuilder JavaDoc();
1973                        pos = estimator.prepare(localPointer, aHead, aTail);
1974                        if (j+1 == result.length) {
1975                            tail = aTail.toString();
1976                        }
1977                        head = aHead.toString();
1978                    }
1979                    int oldPos = item.element.getKind() != Kind.VARIABLE ? getOldPos(item.element) : item.element.pos;
1980                    boolean found = false;
1981                    if (oldPos > 0) {
1982                        for (JCTree oldT : oldList) {
1983                            int oldNodePos = oldT.getKind() != Kind.VARIABLE ? getOldPos(oldT) : oldT.pos;
1984                            if (oldPos == oldNodePos) {
1985                                found = true;
1986                                VeryPretty oldPrinter = this.printer;
1987                                int old = oldPrinter.indent();
1988                                this.printer = new VeryPretty(context, JavaFormatOptions.getDefault());
1989                                this.printer.reset(old);
1990                                int index = oldList.indexOf(oldT);
1991                                int[] poss = estimator.getPositions(index);
1992                                diffTree(oldT, item.element, poss);
1993                                printer.print(this.printer.toString());
1994                                this.printer = oldPrinter;
1995                                this.printer.undent(old);
1996                                break;
1997                            }
1998                        }
1999                    }
2000                    if (!found) {
2001                        if (lastdel != null && treesMatch(item.element, lastdel, false)) {
2002                            VeryPretty oldPrinter = this.printer;
2003                            int old = oldPrinter.indent();
2004                            this.printer = new VeryPretty(context, JavaFormatOptions.getDefault());
2005                            this.printer.reset(old);
2006                            int index = oldList.indexOf(lastdel);
2007                            int[] poss = estimator.getPositions(index);
2008                            diffTree(lastdel, item.element, poss);
2009                            printer.print(this.printer.toString());
2010                            this.printer = oldPrinter;
2011                            this.printer.undent(old);
2012                            break;
2013                        }
2014                        printer.print(head);
2015                        int old = printer.indent();
2016                        printer.enclClassName = printer.enclClassName;
2017                        if (LineInsertionType.BEFORE == estimator.lineInsertType()) printer.newline();
2018                        printer.print(item.element);
2019                        if (LineInsertionType.AFTER == estimator.lineInsertType()) printer.newline();
2020                        printer.undent(old);
2021                    }
2022                    break;
2023                }
2024                case DELETE: {
2025                    int[] pos = estimator.getPositions(i);
2026                    if (localPointer < pos[0]) {
2027                        copyTo(localPointer, pos[0], printer);
2028                    }
2029                    lastdel = oldList.get(i);
2030                    ++i;
2031                    localPointer = pos[1];
2032                    break;
2033                }
2034                case NOCHANGE: {
2035                    int[] pos = estimator.getPositions(i);
2036                    if (pos[0] > localPointer && i != 0) {
2037                        // print fill-in
2038
copyTo(localPointer, pos[0], printer);
2039                    }
2040                    copyTo(pos[0], localPointer = pos[1], printer);
2041                    lastdel = null;
2042                    ++i;
2043                    break;
2044                }
2045            }
2046        }
2047        return localPointer;
2048    }
2049    
2050    private boolean isHidden(JCTree t, JCTree parent) {
2051        if (parent == null)
2052            return false;
2053        //TODO: the test was originaly: t.pos == parent.pos, which caused problems when adding
2054
//member into class without non-syntetic constructors. See ConstructorTest.
2055
if (t.pos == Query.NOPOS)
2056            return true;
2057        return model.isSynthetic(t);
2058    }
2059    
2060    protected void diffPrecedingComments(JCTree oldT, JCTree newT) {
2061        CommentSet cs = comments.getComments(newT);
2062        if (!cs.hasChanges())
2063            return;
2064        List<Comment> oldComments = comments.getComments(oldT).getPrecedingComments();
2065        List<Comment> newComments = cs.getPrecedingComments();
2066        diffCommentLists(oldT, newT, oldComments, newComments, false);
2067    }
2068
2069    protected void diffTrailingComments(JCTree oldT, JCTree newT) {
2070        CommentSet cs = comments.getComments(newT);
2071        if (!cs.hasChanges())
2072            return;
2073        List<Comment> oldComments = comments.getComments(oldT).getTrailingComments();
2074        List<Comment> newComments = cs.getTrailingComments();
2075        diffCommentLists(oldT, newT, oldComments, newComments, true);
2076    }
2077    
2078    private void diffCommentLists(JCTree oldT, JCTree newT, List<Comment>oldList,
2079                                  List<Comment>newList, boolean trailing) {
2080        int lastPos = getOldPos(oldT);
2081        Iterator JavaDoc<Comment> oldIter = oldList.iterator();
2082        Iterator JavaDoc<Comment> newIter = newList.iterator();
2083        Comment oldC = safeNext(oldIter);
2084        Comment newC = safeNext(newIter);
2085        while (oldC != null && newC != null) {
2086            lastPos = oldC.pos();
2087            if (commentsMatch(oldC, newC)) {
2088                oldC = safeNext(oldIter);
2089                newC = safeNext(newIter);
2090            }
2091            else if (!listContains(newList, oldC)) {
2092                if (!listContains(oldList, newC)) {
2093                    append(Diff.modify(oldT, newT, oldC, newC));
2094                    oldC = safeNext(oldIter);
2095                    newC = safeNext(newIter);
2096                } else {
2097                    append(Diff.delete(oldT, newT, oldC));
2098                    oldC = safeNext(oldIter);
2099                }
2100            }
2101            else {
2102                append(Diff.insert(lastPos, LineInsertionType.BEFORE, oldT, newT, newC, trailing));
2103                newC = safeNext(newIter);
2104            }
2105        }
2106        while (oldC != null) {
2107            append(Diff.delete(oldT, newT, oldC));
2108            oldC = safeNext(oldIter);
2109        }
2110        while (newC != null) {
2111            append(Diff.insert(lastPos, LineInsertionType.BEFORE, oldT, newT, newC, trailing));
2112            lastPos += newC.endPos() - newC.pos();
2113            newC = safeNext(oldIter);
2114        }
2115    }
2116    
2117    private Comment safeNext(Iterator JavaDoc<Comment> iter) {
2118        return iter.hasNext() ? iter.next() : null;
2119    }
2120    
2121    private boolean commentsMatch(Comment oldC, Comment newC) {
2122        if (oldC == null && newC == null)
2123            return true;
2124        if (oldC == null || newC == null)
2125            return false;
2126        return oldC.equals(newC);
2127    }
2128    
2129    private boolean listContains(List<Comment>list, Comment comment) {
2130        for (Comment c : list)
2131            if (c.equals(comment))
2132                return true;
2133        return false;
2134    }
2135    
2136    // from TreesService
2137
private static JCTree leftMostTree(JCTree tree) {
2138        switch (tree.tag) {
2139            case(JCTree.APPLY):
2140                return leftMostTree(((JCMethodInvocation)tree).meth);
2141            case(JCTree.ASSIGN):
2142                return leftMostTree(((JCAssign)tree).lhs);
2143            case(JCTree.BITOR_ASG): case(JCTree.BITXOR_ASG): case(JCTree.BITAND_ASG):
2144            case(JCTree.SL_ASG): case(JCTree.SR_ASG): case(JCTree.USR_ASG):
2145            case(JCTree.PLUS_ASG): case(JCTree.MINUS_ASG): case(JCTree.MUL_ASG):
2146            case(JCTree.DIV_ASG): case(JCTree.MOD_ASG):
2147                return leftMostTree(((JCAssignOp)tree).lhs);
2148            case(JCTree.OR): case(JCTree.AND): case(JCTree.BITOR):
2149            case(JCTree.BITXOR): case(JCTree.BITAND): case(JCTree.EQ):
2150            case(JCTree.NE): case(JCTree.LT): case(JCTree.GT):
2151            case(JCTree.LE): case(JCTree.GE): case(JCTree.SL):
2152            case(JCTree.SR): case(JCTree.USR): case(JCTree.PLUS):
2153            case(JCTree.MINUS): case(JCTree.MUL): case(JCTree.DIV):
2154            case(JCTree.MOD):
2155                return leftMostTree(((JCBinary)tree).lhs);
2156            case(JCTree.CLASSDEF): {
2157                JCClassDecl node = (JCClassDecl)tree;
2158                if (node.mods.pos != Position.NOPOS)
2159                    return node.mods;
2160                break;
2161            }
2162            case(JCTree.CONDEXPR):
2163                return leftMostTree(((JCConditional)tree).cond);
2164            case(JCTree.EXEC):
2165                return leftMostTree(((JCExpressionStatement)tree).expr);
2166            case(JCTree.INDEXED):
2167                return leftMostTree(((JCArrayAccess)tree).indexed);
2168            case(JCTree.METHODDEF): {
2169                JCMethodDecl node = (JCMethodDecl)tree;
2170                if (node.mods.pos != Position.NOPOS)
2171                    return node.mods;
2172                if (node.restype != null) // true for constructors
2173
return leftMostTree(node.restype);
2174                return node;
2175            }
2176            case(JCTree.SELECT):
2177                return leftMostTree(((JCFieldAccess)tree).selected);
2178            case(JCTree.TYPEAPPLY):
2179                return leftMostTree(((JCTypeApply)tree).clazz);
2180            case(JCTree.TYPEARRAY):
2181                return leftMostTree(((JCArrayTypeTree)tree).elemtype);
2182            case(JCTree.TYPETEST):
2183                return leftMostTree(((JCInstanceOf)tree).expr);
2184            case(JCTree.POSTINC):
2185            case(JCTree.POSTDEC):
2186                return leftMostTree(((JCUnary)tree).arg);
2187            case(JCTree.VARDEF): {
2188                JCVariableDecl node = (JCVariableDecl)tree;
2189                if (node.mods.pos != Position.NOPOS)
2190                    return node.mods;
2191                return leftMostTree(node.vartype);
2192            }
2193            case(JCTree.TOPLEVEL): {
2194                JCCompilationUnit node = (JCCompilationUnit)tree;
2195                assert node.defs.size() > 0;
2196                return node.pid != null ? node.pid : node.defs.head;
2197            }
2198        }
2199        return tree;
2200    }
2201    
2202    private int getOldPos(JCTree oldT) {
2203        return getOldPos(oldT, model, undo);
2204    }
2205    
2206    static int getOldPos(JCTree oldT, ASTModel model, UndoList undo) {
2207        int oldPos = model.getStartPos(oldT);
2208        if (oldPos == Query.NOPOS) {
2209            // see if original tree is available for position
2210
JCTree t = (JCTree)undo.getOld(leftMostTree(oldT));
2211            if (t != null && t != oldT)
2212                // recurse in case there are multiple changes to this tree
2213
oldPos = getOldPos(t, model, undo);
2214        }
2215        if (oldPos == Query.NOPOS)
2216            oldPos = oldT.pos == Query.NOPOS ? leftMostTree(oldT).pos : oldT.pos;
2217        return oldPos;
2218    }
2219    
2220    /**
2221     * Create differences between trees. Old tree has to exist, i.e.
2222     * <code>oldT != null</code>. There is a one exception - when both
2223     * <code>oldT</code> and <code>newT</code> are null, then method
2224     * just returns.
2225     *
2226     * @param oldT original tree in source code
2227     * @param newT tree to repace the original tree
2228     * @return position in original source
2229     */

2230    protected int diffTree(JCTree oldT, JCTree newT, int[] elementBounds) {
2231        if (oldT == null && newT != null)
2232            throw new IllegalArgumentException JavaDoc("Null is not allowed in parameters.");
2233 
2234        if (oldT == newT)
2235            return elementBounds[0];
2236        diffPrecedingComments(oldT, newT);
2237        int retVal = -1;
2238        int oldPos = getOldPos(oldT);
2239
2240        if (oldT.tag != newT.tag) {
2241            if (((compAssign.contains(oldT.getKind()) && compAssign.contains(newT.getKind())) == false) &&
2242                ((binaries.contains(oldT.getKind()) && binaries.contains(newT.getKind())) == false) &&
2243                ((unaries.contains(oldT.getKind()) && unaries.contains(newT.getKind())) == false)) {
2244                // different kind of trees found, print the whole new one.
2245
printer.print(newT);
2246                return endPos(oldT);
2247            }
2248        }
2249
2250        switch (oldT.tag) {
2251          case JCTree.TOPLEVEL:
2252              diffTopLevel((JCCompilationUnit)oldT, (JCCompilationUnit)newT);
2253              break;
2254          case JCTree.IMPORT:
2255              retVal = diffImport((JCImport)oldT, (JCImport)newT, elementBounds);
2256              break;
2257          case JCTree.CLASSDEF:
2258              retVal = diffClassDef((JCClassDecl)oldT, (JCClassDecl)newT, elementBounds);
2259              break;
2260          case JCTree.METHODDEF:
2261              retVal = diffMethodDef((JCMethodDecl)oldT, (JCMethodDecl)newT, elementBounds);
2262              break;
2263          case JCTree.VARDEF:
2264              return diffVarDef((JCVariableDecl)oldT, (JCVariableDecl)newT, elementBounds);
2265          case JCTree.SKIP:
2266              break;
2267          case JCTree.BLOCK:
2268              retVal = diffBlock((JCBlock)oldT, (JCBlock)newT, elementBounds[0]);
2269              break;
2270          case JCTree.DOLOOP:
2271              retVal = diffDoLoop((JCDoWhileLoop)oldT, (JCDoWhileLoop)newT, elementBounds);
2272              break;
2273          case JCTree.WHILELOOP:
2274              retVal = diffWhileLoop((JCWhileLoop)oldT, (JCWhileLoop)newT, elementBounds);
2275              break;
2276          case JCTree.FORLOOP:
2277              retVal = diffForLoop((JCForLoop)oldT, (JCForLoop)newT, elementBounds);
2278              break;
2279          case JCTree.FOREACHLOOP:
2280              retVal = diffForeachLoop((JCEnhancedForLoop)oldT, (JCEnhancedForLoop)newT, elementBounds);
2281              break;
2282          case JCTree.LABELLED:
2283              retVal = diffLabelled((JCLabeledStatement)oldT, (JCLabeledStatement)newT, elementBounds);
2284              break;
2285          case JCTree.SWITCH:
2286              retVal = diffSwitch((JCSwitch)oldT, (JCSwitch)newT, elementBounds);
2287              break;
2288          case JCTree.CASE:
2289              retVal = diffCase((JCCase)oldT, (JCCase)newT, elementBounds);
2290              break;
2291          case JCTree.SYNCHRONIZED:
2292              retVal = diffSynchronized((JCSynchronized)oldT, (JCSynchronized)newT, elementBounds);
2293              break;
2294          case JCTree.TRY:
2295              retVal = diffTry((JCTry)oldT, (JCTry)newT, elementBounds);
2296              break;
2297          case JCTree.CATCH:
2298              retVal = diffCatch((JCCatch)oldT, (JCCatch)newT, elementBounds);
2299              break;
2300          case JCTree.CONDEXPR:
2301              retVal = diffConditional((JCConditional)oldT, (JCConditional)newT, elementBounds);
2302              break;
2303          case JCTree.IF:
2304              retVal = diffIf((JCIf)oldT, (JCIf)newT, elementBounds);
2305              break;
2306          case JCTree.EXEC:
2307              retVal = diffExec((JCExpressionStatement)oldT, (JCExpressionStatement)newT, elementBounds);
2308              break;
2309          case JCTree.BREAK:
2310              retVal = diffBreak((JCBreak)oldT, (JCBreak)newT, elementBounds);
2311              break;
2312          case JCTree.CONTINUE:
2313              retVal = diffContinue((JCContinue)oldT, (JCContinue)newT, elementBounds);
2314              break;
2315          case JCTree.RETURN:
2316              retVal = diffReturn((JCReturn)oldT, (JCReturn)newT, elementBounds);
2317              break;
2318          case JCTree.THROW:
2319              retVal = diffThrow((JCThrow)oldT, (JCThrow)newT,elementBounds);
2320              break;
2321          case JCTree.ASSERT:
2322              retVal = diffAssert((JCAssert)oldT, (JCAssert)newT, elementBounds);
2323              break;
2324          case JCTree.APPLY:
2325              retVal = diffApply((JCMethodInvocation)oldT, (JCMethodInvocation)newT, elementBounds);
2326              break;
2327          case JCTree.NEWCLASS:
2328              retVal = diffNewClass((JCNewClass)oldT, (JCNewClass)newT, elementBounds);
2329              break;
2330          case JCTree.NEWARRAY:
2331              retVal = diffNewArray((JCNewArray)oldT, (JCNewArray)newT, elementBounds);
2332              break;
2333          case JCTree.PARENS:
2334              retVal = diffParens((JCParens)oldT, (JCParens)newT, elementBounds);
2335              break;
2336          case JCTree.ASSIGN:
2337              retVal = diffAssign((JCAssign)oldT, (JCAssign)newT, elementBounds);
2338              break;
2339          case JCTree.TYPECAST:
2340              retVal = diffTypeCast((JCTypeCast)oldT, (JCTypeCast)newT, elementBounds);
2341              break;
2342          case JCTree.TYPETEST:
2343              retVal = diffTypeTest((JCInstanceOf)oldT, (JCInstanceOf)newT, elementBounds);
2344              break;
2345          case JCTree.INDEXED:
2346              retVal = diffIndexed((JCArrayAccess)oldT, (JCArrayAccess)newT, elementBounds);
2347              break;
2348          case JCTree.SELECT:
2349              retVal = diffSelect((JCFieldAccess)oldT, (JCFieldAccess)newT, elementBounds);
2350              break;
2351          case JCTree.IDENT:
2352              retVal = diffIdent((JCIdent)oldT, (JCIdent)newT, elementBounds[0]);
2353              break;
2354          case JCTree.LITERAL:
2355              retVal = diffLiteral((JCLiteral)oldT, (JCLiteral)newT, elementBounds);
2356              break;
2357          case JCTree.TYPEIDENT:
2358              diffTypeIdent((JCPrimitiveTypeTree)oldT, (JCPrimitiveTypeTree)newT);
2359              break;
2360          case JCTree.TYPEARRAY:
2361              retVal = diffTypeArray((JCArrayTypeTree)oldT, (JCArrayTypeTree)newT, elementBounds);
2362              break;
2363          case JCTree.TYPEAPPLY:
2364              retVal = diffTypeApply((JCTypeApply)oldT, (JCTypeApply)newT, elementBounds);
2365              break;
2366          case JCTree.TYPEPARAMETER:
2367              retVal = diffTypeParameter((JCTypeParameter)oldT, (JCTypeParameter)newT, elementBounds);
2368              break;
2369          case JCTree.WILDCARD:
2370              retVal = diffWildcard((JCWildcard)oldT, (JCWildcard)newT, elementBounds);
2371              break;
2372          case JCTree.TYPEBOUNDKIND:
2373              retVal = diffTypeBoundKind((TypeBoundKind)oldT, (TypeBoundKind)newT, elementBounds);
2374              break;
2375          case JCTree.ANNOTATION:
2376              retVal = diffAnnotation((JCAnnotation)oldT, (JCAnnotation)newT, elementBounds);
2377              break;
2378          case JCTree.LETEXPR:
2379              diffLetExpr((LetExpr)oldT, (LetExpr)newT);
2380              break;
2381          case JCTree.POS:
2382          case JCTree.NEG:
2383          case JCTree.NOT:
2384          case JCTree.COMPL:
2385          case JCTree.PREINC:
2386          case JCTree.PREDEC:
2387          case JCTree.POSTINC:
2388          case JCTree.POSTDEC:
2389          case JCTree.NULLCHK:
2390              retVal = diffUnary((JCUnary)oldT, (JCUnary)newT, elementBounds);
2391              break;
2392          case JCTree.OR:
2393          case JCTree.AND:
2394          case JCTree.BITOR:
2395          case JCTree.BITXOR:
2396          case JCTree.BITAND:
2397          case JCTree.EQ:
2398          case JCTree.NE:
2399          case JCTree.LT:
2400          case JCTree.GT:
2401          case JCTree.LE:
2402          case JCTree.GE:
2403          case JCTree.SL:
2404          case JCTree.SR:
2405          case JCTree.USR:
2406          case JCTree.PLUS:
2407          case JCTree.MINUS:
2408          case JCTree.MUL:
2409          case JCTree.DIV:
2410          case JCTree.MOD:
2411              retVal = diffBinary((JCBinary)oldT, (JCBinary)newT, elementBounds);
2412              break;
2413          case JCTree.BITOR_ASG:
2414          case JCTree.BITXOR_ASG:
2415          case JCTree.BITAND_ASG:
2416          case JCTree.SL_ASG:
2417          case JCTree.SR_ASG:
2418          case JCTree.USR_ASG:
2419          case JCTree.PLUS_ASG:
2420          case JCTree.MINUS_ASG:
2421          case JCTree.MUL_ASG:
2422          case JCTree.DIV_ASG:
2423          case JCTree.MOD_ASG:
2424              retVal = diffAssignop((JCAssignOp)oldT, (JCAssignOp)newT, elementBounds);
2425              break;
2426          case JCTree.ERRONEOUS:
2427              diffErroneous((JCErroneous)oldT, (JCErroneous)newT);
2428              break;
2429          default:
2430              String JavaDoc msg = "Diff not implemented: " +
2431                  ((com.sun.source.tree.Tree)oldT).getKind().toString() +
2432                  " " + oldT.getClass().getName();
2433              throw new AssertionError JavaDoc(msg);
2434        }
2435        diffTrailingComments(oldT, newT);
2436        return retVal;
2437    }
2438
2439    /**
2440     * Three sets representing different kind which can be matched. No need
2441     * to rewrite whole expression. Ensure that CompoundAssignementTrees,
2442     * UnaryTrees and BinaryTrees are matched, i.e. diff method is used
2443     * instead of priting whole new tree.
2444     */

2445    private static final EnumSet JavaDoc<Kind> compAssign = EnumSet.of(
2446        Kind.MULTIPLY_ASSIGNMENT,
2447        Kind.DIVIDE_ASSIGNMENT,
2448        Kind.REMAINDER_ASSIGNMENT,
2449        Kind.PLUS_ASSIGNMENT,
2450        Kind.MINUS_ASSIGNMENT,
2451        Kind.LEFT_SHIFT_ASSIGNMENT,
2452        Kind.RIGHT_SHIFT_ASSIGNMENT,
2453        Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT,
2454        Kind.AND_ASSIGNMENT,
2455        Kind.XOR_ASSIGNMENT,
2456        Kind.OR_ASSIGNMENT
2457    );
2458    
2459    private static final EnumSet JavaDoc<Kind> binaries = EnumSet.of(
2460        Kind.MULTIPLY,
2461        Kind.DIVIDE,
2462        Kind.REMAINDER,
2463        Kind.PLUS,
2464        Kind.MINUS,
2465        Kind.LEFT_SHIFT,
2466        Kind.RIGHT_SHIFT,
2467        Kind.UNSIGNED_RIGHT_SHIFT,
2468        Kind.LESS_THAN,
2469        Kind.GREATER_THAN,
2470        Kind.LESS_THAN_EQUAL,
2471        Kind.GREATER_THAN_EQUAL,
2472        Kind.EQUAL_TO,
2473        Kind.NOT_EQUAL_TO,
2474        Kind.AND,
2475        Kind.XOR,
2476        Kind.OR,
2477        Kind.CONDITIONAL_AND,
2478        Kind.CONDITIONAL_OR
2479    );
2480    
2481    private static final EnumSet JavaDoc<Kind> unaries = EnumSet.of(
2482        Kind.POSTFIX_INCREMENT,
2483        Kind.POSTFIX_DECREMENT,
2484        Kind.PREFIX_INCREMENT,
2485        Kind.PREFIX_DECREMENT,
2486        Kind.UNARY_PLUS,
2487        Kind.UNARY_MINUS,
2488        Kind.BITWISE_COMPLEMENT,
2489        Kind.LOGICAL_COMPLEMENT
2490    );
2491
2492    private int diffTree(JCTree oldT, JCTree newT, int lastPrinted) {
2493        return diffTree(oldT, newT, new int[] { lastPrinted, -1 });
2494    }
2495    
2496    protected boolean listsMatch(List<? extends JCTree> oldList, List<? extends JCTree> newList) {
2497        if (oldList == newList)
2498            return true;
2499        int n = oldList.size();
2500        if (newList.size() != n)
2501            return false;
2502        for (int i = 0; i < n; i++)
2503            if (!treesMatch(oldList.get(i), newList.get(i)))
2504                return false;
2505        return true;
2506    }
2507
2508    private boolean matchImport(JCImport t1, JCImport t2) {
2509        return t1.staticImport == t2.staticImport && treesMatch(t1.qualid, t2.qualid);
2510    }
2511
2512    private boolean matchBlock(JCBlock t1, JCBlock t2) {
2513        return t1.flags == t2.flags && listsMatch(t1.stats, t2.stats);
2514    }
2515
2516    private boolean matchDoLoop(JCDoWhileLoop t1, JCDoWhileLoop t2) {
2517        return treesMatch(t1.cond, t2.cond) && treesMatch(t1.body, t2.body);
2518    }
2519
2520    private boolean matchWhileLoop(JCWhileLoop t1, JCWhileLoop t2) {
2521        return treesMatch(t1.cond, t2.cond) && treesMatch(t1.body, t2.body);
2522    }
2523
2524    private boolean matchForLoop(JCForLoop t1, JCForLoop t2) {
2525        return listsMatch(t1.init, t2.init) && treesMatch(t1.cond, t2.cond) &&
2526               listsMatch(t1.step, t2.step) && treesMatch(t1.body, t2.body);
2527    }
2528    
2529    private boolean matchForeachLoop(JCEnhancedForLoop t1, JCEnhancedForLoop t2) {
2530        return treesMatch(t1.var, t2.var) && treesMatch(t1.expr, t2.expr) &&
2531               treesMatch(t1.body, t2.body);
2532    }
2533
2534    private boolean matchLabelled(JCLabeledStatement t1, JCLabeledStatement t2) {
2535        return t1.label == t2.label && treesMatch(t1.body, t2.body);
2536    }
2537
2538    private boolean matchSwitch(JCSwitch t1, JCSwitch t2) {
2539        return treesMatch(t1.selector, t2.selector) && listsMatch(t1.cases, t2.cases);
2540    }
2541
2542    private boolean matchCase(JCCase t1, JCCase t2) {
2543        return treesMatch(t1.pat, t2.pat) && listsMatch(t1.stats, t2.stats);
2544    }
2545
2546    private boolean matchSynchronized(JCSynchronized t1, JCSynchronized t2) {
2547        return treesMatch(t1.lock, t2.lock) && treesMatch(t1.body, t2.body);
2548    }
2549
2550    private boolean matchTry(JCTry t1, JCTry t2) {
2551        return treesMatch(t1.finalizer, t2.finalizer) &&
2552                listsMatch(t1.catchers, t2.catchers) &&
2553                treesMatch(t1.body, t2.body);
2554    }
2555
2556    private boolean matchCatch(JCCatch t1, JCCatch t2) {
2557        return treesMatch(t1.param, t2.param) && treesMatch(t1.body, t2.body);
2558    }
2559    
2560    private boolean matchConditional(JCConditional t1, JCConditional t2) {
2561        return treesMatch(t1.cond, t2.cond) && treesMatch(t1.truepart, t2.truepart) &&
2562               treesMatch(t1.falsepart, t2.falsepart);
2563    }
2564    
2565    private boolean matchIf(JCIf t1, JCIf t2) {
2566        return treesMatch(t1.cond, t2.cond) && treesMatch(t1.thenpart, t2.thenpart) &&
2567               treesMatch(t1.elsepart, t2.elsepart);
2568    }
2569
2570    private boolean matchBreak(JCBreak t1, JCBreak t2) {
2571        return t1.label == t2.label && treesMatch(t1.target, t2.target);
2572    }
2573
2574    private boolean matchContinue(JCContinue t1, JCContinue t2) {
2575        return t1.label == t2.label && treesMatch(t1.target, t2.target);
2576    }
2577
2578    private boolean matchAssert(JCAssert t1, JCAssert t2) {
2579        return treesMatch(t1.cond, t2.cond) && treesMatch(t1.detail, t2.detail);
2580    }
2581    
2582    private boolean matchApply(JCMethodInvocation t1, JCMethodInvocation t2) {
2583        return t1.varargsElement == t2.varargsElement &&
2584               listsMatch(t1.typeargs, t2.typeargs) &&
2585               treesMatch(t1.meth, t2.meth) &&
2586               listsMatch(t1.args, t2.args);
2587    }
2588    
2589    private boolean matchNewClass(JCNewClass t1, JCNewClass t2) {
2590        return t1.constructor == t2.constructor &&
2591               listsMatch(t1.typeargs, t2.typeargs) &&
2592               listsMatch(t1.args, t2.args) &&
2593               (t1.varargsElement == t2.varargsElement) &&
2594               treesMatch(t1.def, t2.def);
2595    }
2596    
2597    private boolean matchNewArray(JCNewArray t1, JCNewArray t2) {
2598        return treesMatch(t1.elemtype, t2.elemtype) &&
2599               listsMatch(t1.dims, t2.dims) && listsMatch(t1.elems, t2.elems);
2600    }
2601
2602    private boolean matchAssign(JCAssign t1, JCAssign t2) {
2603        return treesMatch(t1.lhs, t2.lhs) && treesMatch(t1.rhs, t2.rhs);
2604    }
2605
2606    private boolean matchAssignop(JCAssignOp t1, JCAssignOp t2) {
2607        return t1.operator == t2.operator &&
2608               treesMatch(t1.lhs, t2.lhs) && treesMatch(t1.rhs, t2.rhs);
2609    }
2610
2611    private boolean matchUnary(JCUnary t1, JCUnary t2) {
2612        return t1.operator == t2.operator && treesMatch(t1.arg, t2.arg);
2613    }
2614
2615    private boolean matchBinary(JCBinary t1, JCBinary t2) {
2616        return t1.operator == t2.operator &&
2617               treesMatch(t1.lhs, t2.lhs) && treesMatch(t1.rhs, t2.rhs);
2618    }
2619    
2620    private boolean matchTypeCast(JCTypeCast t1, JCTypeCast t2) {
2621        return treesMatch(t1.clazz, t2.clazz) && treesMatch(t1.expr, t2.expr);
2622    }
2623    
2624    private boolean matchTypeTest(JCInstanceOf t1, JCInstanceOf t2) {
2625        return treesMatch(t1.clazz, t2.clazz) && treesMatch(t1.expr, t2.expr);
2626    }
2627    
2628    private boolean matchIndexed(JCArrayAccess t1, JCArrayAccess t2) {
2629        return treesMatch(t1.indexed, t2.indexed) && treesMatch(t1.index, t2.index);
2630    }
2631    
2632    private boolean matchSelect(JCFieldAccess t1, JCFieldAccess t2) {
2633        return treesMatch(t1.selected, t2.selected) && t1.sym == t2.sym;
2634    }
2635    
2636    private boolean matchLiteral(JCLiteral t1, JCLiteral t2) {
2637        return t1.typetag == t2.typetag && t1.value == t2.value;
2638    }
2639
2640    private boolean matchTypeApply(JCTypeApply t1, JCTypeApply t2) {
2641        return treesMatch(t1.clazz, t2.clazz) &&
2642               listsMatch(t1.arguments, t2.arguments);
2643    }
2644    
2645    private boolean matchTypeParameter(JCTypeParameter t1, JCTypeParameter t2) {
2646        return t1.name == t2.name && listsMatch(t1.bounds, t2.bounds);
2647    }
2648    
2649    private boolean matchWildcard(JCWildcard t1, JCWildcard t2) {
2650        return t1.kind == t2.kind && treesMatch(t1.inner, t2.inner);
2651    }
2652
2653    private boolean matchAnnotation(JCAnnotation t1, JCAnnotation t2) {
2654        return treesMatch(t1.annotationType, t2.annotationType) &&
2655               listsMatch(t1.args, t2.args);
2656    }
2657    
2658    private boolean matchModifiers(JCModifiers t1, JCModifiers t2) {
2659        return t1.flags == t2.flags && listsMatch(t1.annotations, t2.annotations);
2660    }
2661
2662    private boolean matchLetExpr(LetExpr t1, LetExpr t2) {
2663        return listsMatch(t1.defs, t2.defs) && treesMatch(t1.expr, t2.expr);
2664    }
2665
2666    private int[] getBounds(JCTree tree) {
2667        return new int[] { getOldPos(tree), endPos(tree) };
2668    }
2669
2670    private void copyTo(int from, int to) {
2671        copyTo(from, to, printer);
2672    }
2673    
2674    private void copyTo(int from, int to, VeryPretty loc) {
2675        if (from == to) {
2676            return;
2677        } else if (from > to || from < 0 || to < 0) {
2678            throw new IllegalArgumentException JavaDoc("Illegal values: from = " + from + "; to = " + to + ".");
2679        }
2680        loc.print(origText.substring(from, to));
2681    }
2682    
2683    private static class Line {
2684        Line(String JavaDoc data, int start, int end) {
2685            this.start = start;
2686            this.end = end;
2687            this.data = data;
2688        }
2689        
2690        @Override JavaDoc
2691        public String JavaDoc toString() {
2692            return data.toString();
2693        }
2694        
2695        @Override JavaDoc
2696        public boolean equals(Object JavaDoc o) {
2697            if (o instanceof Line) {
2698                return data.equals(((Line) o).data);
2699            } else {
2700                return false;
2701            }
2702        }
2703        
2704        @Override JavaDoc
2705        public int hashCode() {
2706            return data.hashCode();
2707        }
2708        
2709        String JavaDoc data;
2710        int end;
2711        int start;
2712    }
2713    
2714    private List<Line> getLines(String JavaDoc text) {
2715        char[] chars = text.toCharArray();
2716        List<Line> list = new ArrayList JavaDoc<Line>();
2717        int pointer = 0;
2718        for (int i = 0; i < chars.length; i++) {
2719            if (chars[i] == '\n') {
2720                list.add(new Line(new String JavaDoc(chars, pointer, i-pointer+1), pointer, i+1));
2721                pointer = i+1;
2722            }
2723        }
2724        if (pointer < chars.length) {
2725            list.add(new Line(new String JavaDoc(chars, pointer, chars.length-pointer), pointer, chars.length));
2726        }
2727        return list;
2728    }
2729    
2730    public List<Diff> makeListMatch(String JavaDoc text1, String JavaDoc text2) {
2731        List<Line> list1 = getLines(text1);
2732        List<Line> list2 = getLines(text2);
2733        Line[] lines1 = list1.toArray(new Line[list1.size()]);
2734        Line[] lines2 = list2.toArray(new Line[list2.size()]);
2735        
2736        List diffs = new ComputeDiff(lines1, lines2).diff();
2737        for (Object JavaDoc o : diffs) {
2738            Difference diff = (Difference)o; // generify
2739
int delStart = diff.getDeletedStart();
2740            int delEnd = diff.getDeletedEnd();
2741            int addStart = diff.getAddedStart();
2742            int addEnd = diff.getAddedEnd();
2743            
2744            String JavaDoc from = toString(delStart, delEnd);
2745            String JavaDoc to = toString(addStart, addEnd);
2746            char type = delEnd != Difference.NONE && addEnd != Difference.NONE ? 'c' : (delEnd == Difference.NONE ? 'a' : 'd');
2747
2748            if (logDiffs) {
2749                System.out.println(from + type + to);
2750                if (delEnd != Difference.NONE) {
2751                    printLines(delStart, delEnd, "<", lines1);
2752                    if (addEnd != Difference.NONE) {
2753                        System.out.println("---");
2754                    }
2755                }
2756                if (addEnd != Difference.NONE) {
2757                    printLines(addStart, addEnd, ">", lines2);
2758                }
2759            }
2760            // addition
2761
if (type == 'a') {
2762                StringBuilder JavaDoc builder = new StringBuilder JavaDoc();
2763                for (int i = addStart; i <= addEnd; i++) {
2764                    builder.append(lines2[i].data);
2765                }
2766                append(Diff.insert(delEnd == Difference.NONE ? lines1[delStart].start : lines1[delEnd].end,
2767                        builder.toString(), null, "", LineInsertionType.NONE));
2768            }
2769            
2770            // deletion
2771
else if (type == 'd') {
2772                append(Diff.delete(lines1[delStart].start, lines1[delEnd].end));
2773            }
2774            
2775            // change
2776
else { // type == 'c'
2777
StringBuilder JavaDoc builder = new StringBuilder JavaDoc();
2778                for (int i = delStart; i <= delEnd; i++) {
2779                    builder.append(lines1[i].data);
2780                }
2781                String JavaDoc match1 = builder.toString();
2782                builder = new StringBuilder JavaDoc();
2783                for (int i = addStart; i <= addEnd; i++) {
2784                    builder.append(lines2[i].data);
2785                }
2786                String JavaDoc match2 = builder.toString();
2787                makeTokenListMatch(match1, match2, lines1[delStart].start);
2788            }
2789        }
2790        return null;
2791    }
2792    
2793    /**
2794     * Temporary logging variable - just for debugging reason during development.
2795     */

2796    private static boolean logDiffs = false;
2797    
2798    public List<Diff> makeTokenListMatch(String JavaDoc text1, String JavaDoc text2, int currentPos) {
2799        if (logDiffs) System.out.println("----- token match for change -");
2800        TokenSequence<JavaTokenId> seq1 = TokenHierarchy.create(text1, JavaTokenId.language()).tokenSequence(JavaTokenId.language());
2801        TokenSequence<JavaTokenId> seq2 = TokenHierarchy.create(text2, JavaTokenId.language()).tokenSequence(JavaTokenId.language());
2802        List<Line> list1 = new ArrayList JavaDoc<Line>();
2803        List<Line> list2 = new ArrayList JavaDoc<Line>();
2804        while (seq1.moveNext()) {
2805            String JavaDoc data = seq1.token().text().toString();
2806            list1.add(new Line(data, seq1.offset(), seq1.offset() + data.length()));
2807        }
2808        while (seq2.moveNext()) {
2809            String JavaDoc data = seq2.token().text().toString();
2810            list2.add(new Line(data, seq2.offset(), seq2.offset() + data.length()));
2811        }
2812        Line[] lines1 = list1.toArray(new Line[list1.size()]);
2813        Line[] lines2 = list2.toArray(new Line[list2.size()]);
2814        
2815        List diffs = new ComputeDiff(lines1, lines2).diff();
2816        for (Object JavaDoc o : diffs) {
2817            Difference diff = (Difference)o; // generify
2818
int delStart = diff.getDeletedStart();
2819            int delEnd = diff.getDeletedEnd();
2820            int addStart = diff.getAddedStart();
2821            int addEnd = diff.getAddedEnd();
2822            
2823            String JavaDoc from = toString(delStart, delEnd);
2824            String JavaDoc to = toString(addStart, addEnd);
2825            char type = delEnd != Difference.NONE && addEnd != Difference.NONE ? 'c' : (delEnd == Difference.NONE ? 'a' : 'd');
2826
2827            if (logDiffs) {
2828                System.out.println(from + type + to);
2829                if (delEnd != Difference.NONE) {
2830                    printTokens(delStart, delEnd, "<", lines1);
2831                    if (addEnd != Difference.NONE) {
2832                        System.out.println("---");
2833                    }
2834                }
2835                if (addEnd != Difference.NONE) {
2836                    printTokens(addStart, addEnd, ">", lines2);
2837                }
2838            }
2839            // addition
2840
if (type == 'a') {
2841                StringBuilder JavaDoc builder = new StringBuilder JavaDoc();
2842                for (int i = addStart; i <= addEnd; i++) {
2843                    builder.append(lines2[i].data);
2844                }
2845                append(Diff.insert(currentPos + (delEnd == Difference.NONE ? lines1[delStart].start : lines1[delEnd].end),
2846                        builder.toString(), null, "", LineInsertionType.NONE));
2847            }
2848            
2849            // deletion
2850
else if (type == 'd') {
2851                append(Diff.delete(currentPos + lines1[delStart].start, currentPos + lines1[delEnd].end));
2852            }
2853            
2854            // change
2855
else { // type == 'c'
2856
StringBuilder JavaDoc builder = new StringBuilder JavaDoc();
2857                /*for (int i = delStart; i <= delEnd; i++) {
2858                    builder.append(lines1[i].data);
2859                }*/

2860                append(Diff.delete(currentPos + lines1[delStart].start, currentPos + lines1[delEnd].end));
2861                //builder = new StringBuilder();
2862
for (int i = addStart; i <= addEnd; i++) {
2863                    builder.append(lines2[i].data);
2864                }
2865                append(Diff.insert(currentPos + (delEnd == Difference.NONE ? lines1[delStart].start : lines1[delEnd].end),
2866                        builder.toString(), null, "", LineInsertionType.NONE));
2867            }
2868                    
2869        }
2870        if (logDiffs) System.out.println("----- end token match -");
2871        return null;
2872    }
2873    
2874    protected String JavaDoc toString(int start, int end) {
2875        // adjusted, because file lines are one-indexed, not zero.
2876

2877        StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
2878        
2879        // match the line numbering from diff(1):
2880
buf.append(end == Difference.NONE ? start : (1 + start));
2881        
2882        if (end != Difference.NONE && start != end) {
2883            buf.append(",").append(1 + end);
2884        }
2885        return buf.toString();
2886    }
2887    
2888    private void printLines(int start, int end, String JavaDoc ind, Line[] lines) {
2889        for (int lnum = start; lnum <= end; ++lnum) {
2890            System.out.print(ind + " " + lines[lnum]);
2891        }
2892    }
2893    
2894    private void printTokens(int start, int end, String JavaDoc ind, Line[] lines) {
2895        for (int lnum = start; lnum <= end; ++lnum) {
2896            System.out.println(ind + " '" + lines[lnum] + "'");
2897        }
2898    }
2899    
2900}
2901
Popular Tags