KickJava   Java API By Example, From Geeks To Geeks.

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


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.ClassTree;
22 import com.sun.source.tree.MethodTree;
23 import com.sun.source.tree.Tree.Kind;
24 import org.netbeans.api.java.lexer.JavaTokenId;
25 import org.netbeans.api.lexer.TokenSequence;
26 import org.netbeans.modules.java.source.builder.CommentHandlerService;
27 import org.netbeans.modules.java.source.builder.ASTService;
28 import org.netbeans.modules.java.source.builder.UndoListService;
29 import org.netbeans.api.java.source.transform.UndoList;
30 import org.netbeans.api.java.source.Comment;
31 import org.netbeans.api.java.source.query.CommentHandler;
32 import org.netbeans.api.java.source.query.CommentSet;
33 import org.netbeans.modules.java.source.engine.ASTModel;
34 import org.netbeans.api.java.source.query.Query;
35
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
47 import java.util.Iterator JavaDoc;
48 import java.util.List JavaDoc;
49 import org.netbeans.api.java.lexer.JavaTokenId;
50 import org.netbeans.api.java.source.WorkingCopy;
51 import org.netbeans.modules.java.source.save.TreeDiff.LineInsertionType;
52 import static org.netbeans.modules.java.source.save.ListMatcher.*;
53 import static com.sun.tools.javac.code.Flags.*;
54 import org.netbeans.modules.java.source.save.TreeDiff.ListType;
55
56 public class TreeDiff {
57     protected ListBuffer<Diff> diffs;
58     protected CommentHandler comments;
59     protected ASTModel model;
60     protected UndoList undo;
61     protected JCTree oldParent;
62     protected JCTree newParent;
63     protected JCCompilationUnit oldTopLevel;
64     
65     private WorkingCopy workingCopy;
66     private TokenSequence<JavaTokenId> tokenSequence;
67
68     public static com.sun.tools.javac.util.List<Diff> diff(Context context, JCTree oldTree, JCTree newTree) {
69         return diff(context, null, oldTree, newTree);
70     }
71     
72     public static com.sun.tools.javac.util.List<Diff> diff(Context context,
73             WorkingCopy copy,
74             JCTree oldTree,
75             JCTree newTree)
76     {
77         TreeDiff td = new TreeDiff(context, copy);
78         td.diffTree(oldTree, newTree);
79         return td.getDiffs();
80     }
81
82     protected TreeDiff(Context context, WorkingCopy workingCopy) {
83         diffs = new ListBuffer<Diff>();
84         comments = CommentHandlerService.instance(context);
85         model = ASTService.instance(context);
86         undo = UndoListService.instance(context);
87         this.workingCopy = workingCopy;
88         this.tokenSequence = workingCopy.getTokenHierarchy().tokenSequence();
89     }
90
91     protected com.sun.tools.javac.util.List<Diff> getDiffs() {
92         return diffs.toList();
93     }
94     
95     private void append(Diff diff) {
96         // check if diff already found -- true for variables that share
97
// fields, such as the mods for "public int foo, bar;"
98
for (Diff d : diffs)
99             if (d.equals(diff))
100                 return;
101         diffs.append(diff);
102     }
103     
104     public static enum DiffTypes {
105         /**
106          * The tree has been modified; that is, different versions
107          * of it exist in the old and new parent trees.
108          */

109         MODIFY("modify"),
110         
111         /**
112          * The tree is an insertion; that is, it exists in the
113          * new tree, but not the old.
114          */

115         INSERT("insert"),
116         
117         /**
118          * The tree was deleted; which means that it exists in the
119          * old parent tree, but not the new one.
120          */

121         DELETE("delete"),
122         
123         /**
124          * The name associated with these trees has changed.
125          */

126         NAME("name"),
127         
128         /**
129          * The flags have changed.
130          */

131         FLAGS("flags"),
132
133         /**
134          * The comment has been modified; that is, different versions
135          * of it exist in the old and new parent trees.
136          */

137         MODIFY_COMMENT("modify_comment"),
138         
139         /**
140          * The comment is an insertion; that is, it exists in the
141          * new tree, but not the old.
142          */

143         INSERT_COMMENT("insert_comment"),
144         
145         /**
146          * The comment was deleted; which means that it exists in the
147          * old parent tree, but not the new one.
148          */

149         DELETE_COMMENT("delete_comment"),
150
151         /**
152          * Offset
153          */

154         INSERT_OFFSET("insert_offset"),
155         DELETE_OFFSET("delete_offset"),
156         
157         /**
158          * Token diff.
159          */

160         MODIFY_TOKEN("modify_token"),
161
162         /**
163          * Insert token.
164          */

165         INSERT_TOKEN("insert_token"),
166
167         /**
168          * Delete tree with token.
169          */

170         DELETE_TOKEN("delete_token");
171         
172         DiffTypes(String JavaDoc name) {
173             this.name = name;
174         }
175         public final String JavaDoc name;
176     }
177     
178     public static enum LineInsertionType {
179         BEFORE, AFTER, NONE
180     }
181
182     public static class Diff {
183         protected DiffTypes type;
184         int pos;
185         protected JCTree oldTree;
186         protected JCTree newTree;
187         protected LineInsertionType newLine;
188         protected Comment oldComment;
189         protected Comment newComment;
190         protected boolean trailing;
191         protected Name owningClassName;
192         
193         static Diff name(int pos, Name oldName, Name newName) {
194             return new NameDiff(pos, oldName, newName);
195         }
196         
197         static Diff name(int pos, String JavaDoc oldName, String JavaDoc newName) {
198             return new NameDiff(pos, oldName, newName);
199         }
200         
201         static Diff flags(int pos, int endPos, long oldFlags, long newFlags) {
202             return new FlagsDiff(pos, endPos, oldFlags, newFlags);
203         }
204         
205         static Diff delete(JCTree oldTree, int pos) {
206             return new Diff(DiffTypes.DELETE, pos, oldTree, null);
207         }
208
209         static Diff insert(JCTree newTree, int pos, LineInsertionType newLine) {
210             return new Diff(DiffTypes.INSERT, pos, null, newTree, newLine);
211         }
212         
213         static Diff insert(JCTree newTree, int pos, LineInsertionType newLine, Name owningClassName) {
214             return new Diff(DiffTypes.INSERT, pos, null, newTree, newLine, null, null, false, owningClassName);
215         }
216         
217         static Diff modify(JCTree oldTree, int oldPos, JCTree newTree) {
218             return new Diff(DiffTypes.MODIFY, oldPos, oldTree, newTree);
219         }
220
221         static Diff delete(JCTree oldTree, JCTree newTree, Comment oldC) {
222             return new Diff(DiffTypes.DELETE_COMMENT, oldC.pos(), oldTree, newTree, LineInsertionType.BEFORE, oldC, null, false, null);
223         }
224
225         static Diff insert(int pos, LineInsertionType newLine, JCTree oldTree, JCTree newTree, Comment newC, boolean trailing) {
226             return new Diff(DiffTypes.INSERT_COMMENT, pos, oldTree, newTree, newLine, null, newC, trailing, null);
227         }
228
229         static Diff modify(JCTree oldTree, JCTree newTree, Comment oldC, Comment newC) {
230             return new Diff(DiffTypes.MODIFY_COMMENT, oldC.pos(), oldTree, newTree, LineInsertionType.NONE, oldC, newC, false, null);
231         }
232         
233         // XXX: TokenDiffs should be removed and replaced by OffsetDiff.
234
// The implementation of case INSERT_TOKEN, DLETE_TOKEN etc. from Commit.java
235
// has to be moved somewhere else.
236
static Diff insert(String JavaDoc preceding, JCTree newTree, int pos, String JavaDoc tail, ListType itemType) {
237             return new TokenDiff(DiffTypes.INSERT_TOKEN, pos, preceding, null, newTree, tail, itemType);
238         }
239         
240         static Diff delete(String JavaDoc preceding, JCTree oldTree, int pos, String JavaDoc tail) {
241             return new TokenDiff(DiffTypes.DELETE_TOKEN, pos, preceding, oldTree, null, tail, null);
242         }
243         
244         static Diff modify(String JavaDoc preceding, int pos, JCTree oldTree, JCTree newTree, String JavaDoc tail, ListType itemType) {
245             return new TokenDiff(DiffTypes.MODIFY_TOKEN, pos, preceding, oldTree, newTree, tail, itemType);
246         }
247         // end removal section
248

249         static Diff insert(int pos, String JavaDoc head, JCTree newTree, String JavaDoc tail, LineInsertionType type, Name owningClassName) {
250             return new OffsetDiff(DiffTypes.INSERT_OFFSET, pos, Position.NOPOS /* does not matter */, head, newTree, tail, type, owningClassName);
251         }
252         
253         static Diff insert(int pos, String JavaDoc head, JCTree newTree, String JavaDoc tail, LineInsertionType type) {
254             return new OffsetDiff(DiffTypes.INSERT_OFFSET, pos, Position.NOPOS /* does not matter */, head, newTree, tail, type, null);
255         }
256         
257         static Diff delete(int startOffset, int endOffset) {
258             return new OffsetDiff(DiffTypes.DELETE_OFFSET, startOffset, endOffset, null, null, null, LineInsertionType.NONE, null);
259         }
260         
261         Diff(DiffTypes type, int pos) {
262             this(type, pos, null, null);
263         }
264
265         Diff(DiffTypes type, int pos, JCTree oldTree, JCTree newTree) {
266             this(type, pos, oldTree, newTree, LineInsertionType.NONE, null, null, false, null);
267         }
268
269         Diff(DiffTypes type, int pos, JCTree oldTree, JCTree newTree, LineInsertionType newLine) {
270             this(type, pos, oldTree, newTree, newLine, null, null, false, null);
271         }
272
273         Diff(DiffTypes tape, int pos, JCTree oldTree, JCTree newTree, LineInsertionType newLine,
274              Comment oldComment, Comment newComment, boolean trailing, Name owningClassName) {
275             assert pos >= 0 : "invalid source offset";
276             this.type = tape;
277             this.pos = pos;
278             this.oldTree = oldTree;
279             this.newTree = newTree;
280             this.newLine = newLine;
281             this.oldComment = oldComment;
282             this.newComment = newComment;
283             this.trailing = trailing;
284             this.owningClassName = owningClassName;
285         }
286
287         public JCTree getOld() {
288             return oldTree;
289         }
290
291         public JCTree getNew() {
292             return newTree;
293         }
294         
295         public LineInsertionType needsNewLine() {
296             return newLine;
297         }
298         
299         public int getPos() {
300             return pos;
301         }
302         
303         public Comment getOldComment() {
304             return oldComment;
305         }
306         
307         public Comment getNewComment() {
308             return newComment;
309         }
310         
311         public boolean isTrailingComment() {
312             return trailing;
313         }
314
315         public boolean equals(Object JavaDoc obj) {
316             if (!(obj instanceof Diff))
317                 return false;
318             Diff d2 = (Diff)obj;
319             return type != d2.type &&
320                    pos != d2.pos &&
321                    oldTree != d2.oldTree &&
322                    newTree != d2.newTree &&
323                    newLine != d2.newLine &&
324                    oldComment != d2.oldComment &&
325                    newComment != d2.newComment &&
326                    trailing != d2.trailing;
327         }
328
329         public int hashCode() {
330             return type.hashCode() + pos +
331                    (oldTree != null ? oldTree.hashCode() : 0) +
332                    (newTree != null ? newTree.hashCode() : 0) +
333                    newLine.hashCode() +
334                    (oldComment != null ? oldComment.hashCode() : 0) +
335                    (newComment != null ? newComment.hashCode() : 0) +
336                    Boolean.valueOf(trailing).hashCode();
337         }
338
339         public String JavaDoc toString() {
340             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
341             sb.append("tree (");
342             sb.append(type.toString());
343             sb.append(") pos=");
344             sb.append(pos);
345             if (trailing)
346                 sb.append(" trailing comment");
347             sb.append("\n");
348
349             if (type == DiffTypes.DELETE || type == DiffTypes.INSERT || type == DiffTypes.MODIFY)
350                 addDiffString(sb, oldTree, newTree);
351             else
352                 addDiffString(sb, oldComment, newComment);
353             return sb.toString();
354         }
355         
356         private void addDiffString(StringBuffer JavaDoc sb, Object JavaDoc o1, Object JavaDoc o2) {
357             if (o1 != null) {
358                 sb.append("< ");
359                 sb.append(o1.toString());
360                 sb.append((o2 != null) ? "\n---\n> " : "\n");
361             } else
362                 sb.append("> ");
363             if (o2 != null) {
364                 sb.append(o2.toString());
365                 sb.append('\n');
366             }
367         }
368     }
369     
370     public static class NameDiff extends Diff {
371         private String JavaDoc oldName, newName;
372         NameDiff(int pos, Name oldName, Name newName) {
373             this(pos, oldName.toString(), newName.toString());
374         }
375         NameDiff(int pos, String JavaDoc oldName, String JavaDoc newName) {
376             super(DiffTypes.NAME, pos);
377             this.oldName = oldName;
378             this.newName = newName;
379         }
380         public String JavaDoc getOldName() {
381             return oldName;
382         }
383         public String JavaDoc getNewName() {
384             return newName;
385         }
386         public boolean equals(Object JavaDoc obj) {
387             if (!(obj instanceof NameDiff))
388                 return false;
389             NameDiff nd = (NameDiff)obj;
390             return super.equals(obj) && oldName.equals(nd.oldName) && newName.equals(nd.newName);
391         }
392         public int hashCode() {
393             return super.hashCode() + oldName.hashCode() + newName.hashCode();
394         }
395     }
396     
397     public static class FlagsDiff extends Diff {
398         private long oldFlags, newFlags;
399         int endPos;
400         FlagsDiff(int pos, int endPos, long oldFlags, long newFlags) {
401             super(DiffTypes.FLAGS, pos);
402             this.oldFlags = oldFlags;
403             this.newFlags = newFlags;
404             this.endPos = endPos;
405         }
406         public long getOldFlags() {
407             return oldFlags;
408         }
409         public long getNewFlags() {
410             return newFlags;
411         }
412         public int getOldEndPos() {
413             return endPos;
414         }
415         public boolean equals(Object JavaDoc obj) {
416             if (!(obj instanceof FlagsDiff))
417                 return false;
418             FlagsDiff fd = (FlagsDiff)obj;
419             return super.equals(obj) &&
420                    oldFlags == fd.oldFlags &&
421                    newFlags == fd.newFlags &&
422                    endPos == fd.endPos;
423         }
424         public int hashCode() {
425             return super.hashCode() + Long.valueOf(oldFlags).hashCode() +
426                    Long.valueOf(newFlags).hashCode() + endPos;
427         }
428         public String JavaDoc toString() {
429             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
430             sb.append("tree (");
431             sb.append(type.toString());
432             sb.append(") pos=");
433             sb.append(pos);
434             if (trailing)
435                 sb.append(" trailing comment");
436             sb.append("\n< ");
437             sb.append(TreeInfo.flagNames(oldFlags));
438             sb.append("\n---\n> ");
439             sb.append(TreeInfo.flagNames(newFlags));
440             sb.append('\n');
441             return sb.toString();
442         }
443     }
444
445     public static class OffsetDiff extends Diff {
446         private final String JavaDoc head;
447         private final String JavaDoc tail;
448         private final int endOffset;
449         
450         // todo (#pf): ins type should be removed after all things will be
451
// rewritten to new line separator policy
452
OffsetDiff(DiffTypes type, int startOffset, int endOffset, String JavaDoc head, JCTree newTree, String JavaDoc tail, LineInsertionType insType, Name owningClassName) {
453             super(type, startOffset, null, newTree, insType);
454             this.endOffset = endOffset;
455             this.head = head;
456             this.tail = tail;
457             this.owningClassName = owningClassName;
458         }
459         
460         public int getStartOffset() { return getPos(); }
461         public int getEndOffset() { return endOffset; }
462         
463         public String JavaDoc getHead() { return head; }
464         String JavaDoc getTail() { return tail; }
465     }
466     
467     // XXX: this class should be removed and its usage should be refactored
468
// (new code should use OffsetDiff)
469
public static class TokenDiff extends Diff {
470         private String JavaDoc preceding;
471         private String JavaDoc tail;
472         private ListType itemType;
473         
474         TokenDiff(DiffTypes type, int pos, String JavaDoc preceding, JCTree oldTree, JCTree newTree, String JavaDoc tail, ListType itemType) {
475             super(type, pos, oldTree, newTree);
476             this.preceding = preceding;
477             this.tail = tail;
478             this.itemType = itemType;
479         }
480         
481         String JavaDoc getPreceding() {
482             return preceding;
483         }
484         
485         String JavaDoc getTail() {
486             return tail;
487         }
488         
489         ListType getItemType() {
490             return itemType;
491         }
492     }
493     
494     // todo (#pf): Is this really needed? -- Seems it duplicates the work
495
// in SourcePositions, but in different way. Uses map of endPositions.
496
// Look into the implementation and try to use SourcePositions!
497
private int endPos(JCTree t) {
498         return model.getEndPos(t, oldTopLevel);
499     }
500
501     protected void diffTopLevel(JCCompilationUnit oldT, JCCompilationUnit newT) {
502         oldTopLevel = oldT;
503         diffList(oldT.packageAnnotations, newT.packageAnnotations, LineInsertionType.NONE, 0);
504         int posHint;
505         // no package declaration available (default package)
506
if (oldT.pid == null) {
507             if (oldT.getImports().head != null) {
508                 posHint = oldT.getImports().head.getStartPosition();
509             } else if (oldT.getTypeDecls().head != null) {
510                 posHint = oldT.getTypeDecls().head.getStartPosition();
511             } else {
512                 // there is neither package declaration nor
513
// import nor class definition. Who wrote
514
// such a file? Make package declaration
515
// at the beginning of file.
516
posHint = 1;
517             }
518         } else {
519             // replacing old declaration.
520
posHint = endPos(oldT.pid);
521         }
522         diffTreeToken("package ", posHint, oldT.pid, newT.pid, ";");
523         if (oldT.getImports().isEmpty()) {
524             // imports are not available, compute position from package and
525
// type decl position.
526
// XXX: empty lines!!! (if there is not empty line between
527
// package and type decl. Also, when package and imports are
528
// unavailable
529
if (oldT.pid != null) {
530                 // hint pos is at the end of package statement before
531
// its semicolon. Move it after the semicolon.
532
// XXX todo (#pf): ensure there are enough empty lines.
533
posHint = TokenUtilities.moveFwdToToken(tokenSequence, posHint, JavaTokenId.SEMICOLON);
534                 posHint += JavaTokenId.SEMICOLON.fixedText().length();
535             }
536         } else {
537             posHint = oldT.getImports().head.pos;
538             /*
539             tokenSequence.move(posHint);
540             if (tokenSequence.movePrevious() && tokenSequence.token().id() == JavaTokenId.WHITESPACE) {
541                 String whiteSpace = tokenSequence.token().text().toString();
542                 int i = whiteSpace.lastIndexOf("\n");
543                 if (i > -1) posHint = tokenSequence.offset() + i;
544             }
545              **/

546         }
547         //diffList(oldT.getImports(), newT.getImports(), posHint, EstimatorFactory.imports(), Measure.DEFAULT);
548
diffList(oldT.getTypeDecls(), newT.getTypeDecls(), LineInsertionType.BEFORE, Position.NOPOS);
549     }
550
551     protected void diffImport(JCImport oldT, JCImport newT) {
552         if (TreeInfo.fullName(oldT.qualid) != TreeInfo.fullName(newT.qualid))
553             append(Diff.modify(oldT, getOldPos(oldT), newT)); // includes possible staticImport change
554
else if (oldT.staticImport != newT.staticImport)
555             append(Diff.flags(oldT.pos, endPos(oldT),
556                               oldT.staticImport ? Flags.STATIC : 0L,
557                               newT.staticImport ? Flags.STATIC : 0L));
558     }
559
560     // need by visitMethodDef - in case of renaming class, we do not know
561
// this name in constructor matcher - save it in diffClassDef() and use
562
// in diffMethodDef(). Probably better to write method with additional
563
// parameter which delegates to original one visitMethodDef().
564
private Name origClassName = null;
565     
566     protected void diffClassDef(JCClassDecl oldT, JCClassDecl newT) {
567         JCTree opar = oldParent;
568         oldParent = oldT;
569         JCTree npar = newParent;
570         newParent = newT;
571         tokenSequence.move(oldT.pos);
572         tokenSequence.moveNext();
573         int insertHint = TokenUtilities.moveNext(tokenSequence, tokenSequence.offset());
574         if (nameChanged(oldT.name, newT.name)) {
575             origClassName = oldT.name;
576             append(Diff.name(insertHint, oldT.name, newT.name));
577         }
578         insertHint += oldT.name.length();
579         diffModifiers(oldT.mods, newT.mods, oldT);
580         diffParameterList(oldT.typarams, newT.typarams);
581         if (oldT.typarams.nonEmpty()) {
582             // if type parameters exists, compute correct end of type parameters.
583
// ! specifies the offset for insertHint var.
584
// public class Yerba<E, M>! { ...
585
insertHint = endPos(oldT.typarams.last());
586             TokenUtilities.moveFwdToToken(tokenSequence, insertHint, JavaTokenId.GT);
587             insertHint = tokenSequence.offset() + JavaTokenId.GT.fixedText().length();
588         }
589         diffTree(oldT.extending, newT.extending, insertHint, " extends ");
590         // TODO (#pf): there is some space for optimization. If the new list
591
// is also empty, we can skip this computation.
592
if (oldT.implementing.isEmpty()) {
593             // if there is not any implementing part, we need to adjust position
594
// from different place. Look at the examples in all if branches.
595
// | represents current adjustment and ! where we want to point to
596
if (oldT.extending != null)
597                 // public class Yerba<E>| extends Object! { ...
598
insertHint = endPos(oldT.extending);
599             else {
600                 // currently no need to adjust anything here:
601
// public class Yerba<E>|! { ...
602
}
603         } else {
604             // we already have any implements, adjust position to first
605
// public class Yerba<E>| implements !Mate { ...
606
// Note: in case of all implements classes are removed,
607
// diffing mechanism will solve the implements keyword.
608
insertHint = oldT.implementing.iterator().next().getStartPosition();
609         }
610         long flags = oldT.sym != null ? oldT.sym.flags() : oldT.mods.flags;
611         PositionEstimator estimator = (flags & INTERFACE) == 0 ?
612             EstimatorFactory.implementz(((ClassTree) oldT).getImplementsClause(), ((ClassTree) newT).getImplementsClause(), workingCopy) :
613             EstimatorFactory.extendz(((ClassTree) oldT).getImplementsClause(), ((ClassTree) newT).getImplementsClause(), workingCopy);
614         diffList2(oldT.implementing, newT.implementing, insertHint, estimator);
615         insertHint = endPos(oldT) - 1;
616
617         if (oldT.defs.isEmpty()) {
618             // if there is nothing in class declaration, use position
619
// before the closing curly.
620
// TODO (#pf): optimize new lines, this will look ugly. --
621
// do before the last new line character before the closing curly.
622
insertHint = endPos(oldT) - 1;
623         } else {
624             // XXX hack: be careful, syntetic constructor in head has the
625
// same position as class declaration too - go to the next feature.
626
// do not be upset to me for the next line, I will replace it
627
// with some better and final solution soon, hopefully :-).
628
JCTree t = oldT.defs.head.pos == oldT.pos ? oldT.defs.tail.head : oldT.defs.head;
629             if (t != null) insertHint = t.getStartPosition();
630         }
631         PositionEstimator est = EstimatorFactory.members(filterHidden(oldT.defs), filterHidden(newT.defs), workingCopy);
632         diffList(filterHidden(oldT.defs), filterHidden(newT.defs), insertHint, est, Measure.MEMBER, newT.name);
633         oldParent = opar;
634         newParent = npar;
635         // the reference is no longer needed.
636
origClassName = null;
637     }
638
639     protected void diffMethodDef(JCMethodDecl oldT, JCMethodDecl newT) {
640         diffModifiers(oldT.mods, newT.mods, oldT);
641         diffTree(oldT.restype, newT.restype);
642         int posHint;
643         if (oldT.typarams.isEmpty()) {
644             posHint = oldT.restype != null ? oldT.restype.getStartPosition() : oldT.getStartPosition();
645         } else {
646             posHint = oldT.typarams.iterator().next().getStartPosition();
647         }
648         if (!oldT.sym.isConstructor() || origClassName != null) {
649             if (nameChanged(oldT.name, newT.name))
650                 // use orig class name in case of constructor
651
if (oldT.sym.isConstructor() && (origClassName != null))
652                     append(Diff.name(oldT.pos, origClassName, newT.name));
653                 else
654                     append(Diff.name(oldT.pos, oldT.name, newT.name));
655         }
656         diffParameterList(oldT.typarams, newT.typarams, posHint, ListType.TYPE_PARAMETER);
657         if (oldT.params.isEmpty()) {
658             // compute the position. Find the parameters closing ')', its
659
// start position is important for us. This is used when
660
// there was not any parameter in original tree.
661
int startOffset = oldT.restype != null ? oldT.restype.getStartPosition() : oldT.getStartPosition();
662             
663             tokenSequence.move(startOffset);
664             TokenUtilities.moveFwdToToken(tokenSequence, startOffset, JavaTokenId.RPAREN);
665             posHint = tokenSequence.offset();
666         } else {
667             // take the position of the first old parameter
668
posHint = oldT.params.iterator().next().getStartPosition();
669         }
670         diffParameterList(oldT.params, newT.params, posHint, ListType.PARAMETER);
671         // if abstract, hint is before ending semi-colon, otherwise before method body
672
if (oldT.thrown.isEmpty()) {
673             posHint = (oldT.body == null ? endPos(oldT) : oldT.body.pos) - 1;
674             // now check, that there is a whitespace. It is not mandatory, we
675
// have to ensure. If whitespace is not present, take body beginning
676
tokenSequence.move(posHint);
677             if (tokenSequence.token().id() != JavaTokenId.WHITESPACE) {
678                 ++posHint;
679             }
680         } else {
681             posHint = oldT.thrown.iterator().next().getStartPosition();
682         }
683         PositionEstimator est = EstimatorFactory.throwz(((MethodTree) oldT).getThrows(), ((MethodTree) newT).getThrows(), workingCopy);
684         diffList2(oldT.thrown, newT.thrown, posHint, est);
685         diffTree(oldT.body, newT.body);
686         diffTree(oldT.defaultValue, newT.defaultValue);
687     }
688
689     protected void diffVarDef(JCVariableDecl oldT, JCVariableDecl newT) {
690         if (nameChanged(oldT.name, newT.name))
691             append(Diff.name(oldT.pos, oldT.name, newT.name));
692         diffModifiers(oldT.mods, newT.mods, oldT);
693         diffTree(oldT.vartype, newT.vartype);
694         if (newT.init != null && oldT.init != null) {
695             diffTree(oldT.init, newT.init);
696         } else {
697             diffTreeToken("=", endPos(oldT.init), oldT.init, newT.init, "");
698         }
699     }
700
701     protected void diffBlock(JCBlock oldT, JCBlock newT) {
702         if (oldT.flags != newT.flags)
703             append(Diff.flags(oldT.pos, endPos(oldT), oldT.flags, newT.flags));
704         diffList(oldT.stats, newT.stats, LineInsertionType.BEFORE, oldT.pos + 1); // hint after open brace
705
}
706
707     protected void diffDoLoop(JCDoWhileLoop oldT, JCDoWhileLoop newT) {
708         diffTree(oldT.body, newT.body);
709         diffTree(oldT.cond, newT.cond);
710     }
711
712     protected void diffWhileLoop(JCWhileLoop oldT, JCWhileLoop newT) {
713         diffTree(oldT.cond, newT.cond);
714         diffTree(oldT.body, newT.body);
715     }
716
717     protected void diffForLoop(JCForLoop oldT, JCForLoop newT) {
718         int initListHint = oldT.cond != null ? oldT.cond.pos - 1 : Query.NOPOS;
719         int stepListHint = oldT.cond != null ? endPos(oldT.cond) + 1 : Query.NOPOS;
720         diffList(oldT.init, newT.init, LineInsertionType.NONE, initListHint);
721         diffTree(oldT.cond, newT.cond);
722         diffList(oldT.step, newT.step, LineInsertionType.NONE, stepListHint);
723         diffTree(oldT.body, newT.body);
724     }
725     
726     protected void diffForeachLoop(JCEnhancedForLoop oldT, JCEnhancedForLoop newT) {
727         diffTree(oldT.var, newT.var);
728         diffTree(oldT.expr, newT.expr);
729         diffTree(oldT.body, newT.body);
730     }
731
732     protected void diffLabelled(JCLabeledStatement oldT, JCLabeledStatement newT) {
733         if (nameChanged(oldT.label, newT.label))
734             append(Diff.name(oldT.pos, oldT.label, newT.label));
735         diffTree(oldT.body, newT.body);
736     }
737
738     protected void diffSwitch(JCSwitch oldT, JCSwitch newT) {
739         diffTree(oldT.selector, newT.selector);
740         int castListHint = oldT.cases.size() > 0 ? oldT.cases.head.pos : Query.NOPOS;
741         diffList(oldT.cases, newT.cases, LineInsertionType.BEFORE, castListHint);
742     }
743
744     protected void diffCase(JCCase oldT, JCCase newT) {
745         diffTree(oldT.pat, newT.pat);
746         diffList(oldT.stats, newT.stats, LineInsertionType.BEFORE, endPos(oldT) + 1); // after colon
747
}
748
749     protected void diffSynchronized(JCSynchronized oldT, JCSynchronized newT) {
750         diffTree(oldT.lock, newT.lock);
751         diffTree(oldT.body, newT.body);
752     }
753
754     protected void diffTry(JCTry oldT, JCTry newT) {
755         diffTree(oldT.body, newT.body);
756         diffList(oldT.catchers, newT.catchers, LineInsertionType.BEFORE, oldT.body.endpos + 1);
757         diffTree(oldT.finalizer, newT.finalizer);
758     }
759
760     protected void diffCatch(JCCatch oldT, JCCatch newT) {
761         diffTree(oldT.param, newT.param);
762         diffTree(oldT.body, newT.body);
763     }
764
765     protected void diffConditional(JCConditional oldT, JCConditional newT) {
766         diffTree(oldT.cond, newT.cond);
767         diffTree(oldT.truepart, newT.truepart);
768         diffTree(oldT.falsepart, newT.falsepart);
769     }
770
771     protected void diffIf(JCIf oldT, JCIf newT) {
772         if (oldT.elsepart == null && newT.elsepart != null ||
773             oldT.elsepart != null && newT.elsepart == null) {
774             // mark the whole if statement to be reformatted, which Commit will refine.
775
append(Diff.modify(oldT, getOldPos(oldT), newT));
776         } else {
777             diffTree(oldT.cond, newT.cond);
778             diffTree(oldT.thenpart, newT.thenpart);
779             diffTree(oldT.elsepart, newT.elsepart);
780         }
781     }
782
783     protected void diffExec(JCExpressionStatement oldT, JCExpressionStatement newT) {
784         diffTree(oldT.expr, newT.expr);
785     }
786
787     protected void diffBreak(JCBreak oldT, JCBreak newT) {
788         if (nameChanged(oldT.label, newT.label))
789             append(Diff.name(oldT.pos, oldT.label, newT.label));
790         diffTree(oldT.target, newT.target);
791     }
792
793     protected void diffContinue(JCContinue oldT, JCContinue newT) {
794         if (nameChanged(oldT.label, newT.label))
795             append(Diff.name(oldT.pos, oldT.label, newT.label));
796         diffTree(oldT.target, newT.target);
797     }
798
799     protected void diffReturn(JCReturn oldT, JCReturn newT) {
800         diffTree(oldT.expr, newT.expr);
801     }
802
803     protected void diffThrow(JCThrow oldT, JCThrow newT) {
804         diffTree(oldT.expr, newT.expr);
805     }
806
807     protected void diffAssert(JCAssert oldT, JCAssert newT) {
808         diffTree(oldT.cond, newT.cond);
809         diffTree(oldT.detail, newT.detail);
810     }
811
812     protected void diffApply(JCMethodInvocation oldT, JCMethodInvocation newT) {
813         diffParameterList(oldT.typeargs, newT.typeargs);
814         diffTree(oldT.meth, newT.meth);
815         diffParameterList(oldT.args, newT.args);
816     }
817
818     protected void diffNewClass(JCNewClass oldT, JCNewClass newT) {
819         diffTree(oldT.encl, newT.encl);
820         diffParameterList(oldT.typeargs, newT.typeargs);
821         diffTree(oldT.clazz, newT.clazz);
822         diffParameterList(oldT.args, newT.args);
823         diffTree(oldT.def, newT.def);
824         if (oldT.constructor != newT.constructor)
825             append(Diff.name(oldT.pos, oldT.constructor.name, newT.constructor.name));
826     }
827
828     protected void diffNewArray(JCNewArray oldT, JCNewArray newT) {
829         diffTree(oldT.elemtype, newT.elemtype);
830         diffParameterList(oldT.dims, newT.dims);
831         diffList(oldT.elems, newT.elems, LineInsertionType.NONE, Query.NOPOS);
832     }
833
834     protected void diffParens(JCParens oldT, JCParens newT) {
835         diffTree(oldT.expr, newT.expr);
836     }
837
838     protected void diffAssign(JCAssign oldT, JCAssign newT) {
839         diffTree(oldT.lhs, newT.lhs);
840         diffTree(oldT.rhs, newT.rhs);
841     }
842
843     protected void diffAssignop(JCAssignOp oldT, JCAssignOp newT) {
844         diffTree(oldT.lhs, newT.lhs);
845         diffTree(oldT.rhs, newT.rhs);
846         if (oldT.tag != newT.tag)
847             append(Diff.name(oldT.pos, operatorName(oldT.tag), operatorName(newT.tag)));
848     }
849
850     protected void diffUnary(JCUnary oldT, JCUnary newT) {
851         diffTree(oldT.arg, newT.arg);
852         if (oldT.tag != newT.tag)
853             append(Diff.name(oldT.pos, operatorName(oldT.tag), operatorName(newT.tag)));
854     }
855
856     protected void diffBinary(JCBinary oldT, JCBinary newT) {
857         diffTree(oldT.lhs, newT.lhs);
858         diffTree(oldT.rhs, newT.rhs);
859         if (oldT.tag != newT.tag)
860             append(Diff.name(oldT.pos, operatorName(oldT.tag), operatorName(newT.tag)));
861     }
862     
863     private String JavaDoc operatorName(int tag) {
864         // dummy instance, just to access a public method which should be static
865
return new Pretty(null, false).operatorName(tag);
866     }
867
868     protected void diffTypeCast(JCTypeCast oldT, JCTypeCast newT) {
869         diffTree(oldT.clazz, newT.clazz);
870         diffTree(oldT.expr, newT.expr);
871     }
872
873     protected void diffTypeTest(JCInstanceOf oldT, JCInstanceOf newT) {
874         diffTree(oldT.expr, newT.expr);
875         diffTree(oldT.clazz, newT.clazz);
876     }
877
878     protected void diffIndexed(JCArrayAccess oldT, JCArrayAccess newT) {
879         diffTree(oldT.indexed, newT.indexed);
880         diffTree(oldT.index, newT.index);
881     }
882
883     protected void diffSelect(JCFieldAccess oldT, JCFieldAccess newT) {
884         diffTree(oldT.selected, newT.selected);
885         if (nameChanged(oldT.name, newT.name))
886             append(Diff.name(oldT.pos, oldT.name, newT.name));
887     }
888
889     protected void diffIdent(JCIdent oldT, JCIdent newT) {
890         if (nameChanged(oldT.name, newT.name))
891             append(Diff.name(oldT.pos, oldT.name, newT.name));
892     }
893
894     protected void diffLiteral(JCLiteral oldT, JCLiteral newT) {
895         if (oldT.typetag != newT.typetag || !oldT.value.equals(newT.value))
896             append(Diff.modify(oldT, getOldPos(oldT), newT));
897     }
898
899     protected void diffTypeIdent(JCPrimitiveTypeTree oldT, JCPrimitiveTypeTree newT) {
900         if (oldT.typetag != newT.typetag)
901             append(Diff.modify(oldT, getOldPos(oldT), newT));
902     }
903
904     protected void diffTypeArray(JCArrayTypeTree oldT, JCArrayTypeTree newT) {
905         diffTree(oldT.elemtype, newT.elemtype);
906     }
907
908     protected void diffTypeApply(JCTypeApply oldT, JCTypeApply newT) {
909         diffTree(oldT.clazz, newT.clazz);
910         diffParameterList(oldT.arguments, newT.arguments);
911     }
912
913     protected void diffTypeParameter(JCTypeParameter oldT, JCTypeParameter newT) {
914         if (nameChanged(oldT.name, newT.name))
915             append(Diff.name(oldT.pos, oldT.name, newT.name));
916         diffParameterList(oldT.bounds, newT.bounds);
917     }
918     
919     protected void diffWildcard(JCWildcard oldT, JCWildcard newT) {
920         if (oldT.kind != newT.kind)
921             append(Diff.name(oldT.pos, oldT.kind.toString(), newT.kind.toString()));
922         diffTree(oldT.inner, newT.inner);
923     }
924     
925     protected void diffTypeBoundKind(TypeBoundKind oldT, TypeBoundKind newT) {
926         if (oldT.kind != newT.kind)
927             append(Diff.name(oldT.pos, oldT.kind.toString(), newT.kind.toString()));
928     }
929     
930     protected void diffAnnotation(JCAnnotation oldT, JCAnnotation newT) {
931         diffTree(oldT.annotationType, newT.annotationType);
932         diffParameterList(oldT.args, newT.args);
933     }
934     
935     protected void diffModifiers(JCModifiers oldT, JCModifiers newT, JCTree parent) {
936         int oldPos = oldT.pos != Position.NOPOS ? getOldPos(oldT) : getOldPos(parent);
937         if (oldT.flags != newT.flags)
938             append(Diff.flags(oldPos,
939                               oldPos == oldT.pos ? endPos(oldT) : oldPos,
940                               oldT.flags, newT.flags));
941         LineInsertionType insertLine = oldT.annotations.nonEmpty() ?
942             LineInsertionType.BEFORE : LineInsertionType.AFTER;
943         diffList(oldT.annotations, newT.annotations, insertLine, oldPos);
944     }
945     
946     protected void diffLetExpr(LetExpr oldT, LetExpr newT) {
947         diffList(oldT.defs, newT.defs, LineInsertionType.NONE, Query.NOPOS);
948         diffTree(oldT.expr, newT.expr);
949     }
950     
951     protected void diffErroneous(JCErroneous oldT, JCErroneous newT) {
952         diffList(oldT.errs, newT.errs, LineInsertionType.BEFORE, Query.NOPOS);
953     }
954
955     protected boolean listContains(List<? extends JCTree> list, JCTree tree) {
956         for (JCTree t : list)
957             if (treesMatch(t, tree))
958                 return true;
959         return false;
960     }
961
962     protected boolean treesMatch(JCTree t1, JCTree t2) {
963         return treesMatch(t1, t2, true);
964     }
965     
966     public boolean treesMatch(JCTree t1, JCTree t2, boolean deepMatch) {
967         if (t1 == t2)
968             return true;
969         if (t1 == null || t2 == null)
970             return false;
971         if (t1.tag != t2.tag)
972             return false;
973         if (!deepMatch)
974             return true;
975         
976         // don't use visitor, since we want fast-fail behavior
977
switch (t1.tag) {
978           case JCTree.TOPLEVEL:
979               return ((JCCompilationUnit)t1).sourcefile.equals(((JCCompilationUnit)t2).sourcefile);
980           case JCTree.IMPORT:
981               return matchImport((JCImport)t1, (JCImport)t2);
982           case JCTree.CLASSDEF:
983               return ((JCClassDecl)t1).sym == ((JCClassDecl)t2).sym;
984           case JCTree.METHODDEF:
985               return ((JCMethodDecl)t1).sym == ((JCMethodDecl)t2).sym;
986           case JCTree.VARDEF:
987               return ((JCVariableDecl)t1).sym == ((JCVariableDecl)t2).sym;
988           case JCTree.SKIP:
989               return true;
990           case JCTree.BLOCK:
991               return matchBlock((JCBlock)t1, (JCBlock)t2);
992           case JCTree.DOLOOP:
993               return matchDoLoop((JCDoWhileLoop)t1, (JCDoWhileLoop)t2);
994           case JCTree.WHILELOOP:
995               return matchWhileLoop((JCWhileLoop)t1, (JCWhileLoop)t2);
996           case JCTree.FORLOOP:
997               return matchForLoop((JCForLoop)t1, (JCForLoop)t2);
998           case JCTree.FOREACHLOOP:
999               return matchForeachLoop((JCEnhancedForLoop)t1, (JCEnhancedForLoop)t2);
1000          case JCTree.LABELLED:
1001              return matchLabelled((JCLabeledStatement)t1, (JCLabeledStatement)t2);
1002          case JCTree.SWITCH:
1003              return matchSwitch((JCSwitch)t1, (JCSwitch)t2);
1004          case JCTree.CASE:
1005              return matchCase((JCCase)t1, (JCCase)t2);
1006          case JCTree.SYNCHRONIZED:
1007              return matchSynchronized((JCSynchronized)t1, (JCSynchronized)t2);
1008          case JCTree.TRY:
1009              return matchTry((JCTry)t1, (JCTry)t2);
1010          case JCTree.CATCH:
1011              return matchCatch((JCCatch)t1, (JCCatch)t2);
1012          case JCTree.CONDEXPR:
1013              return matchConditional((JCConditional)t1, (JCConditional)t2);
1014          case JCTree.IF:
1015              return matchIf((JCIf)t1, (JCIf)t2);
1016          case JCTree.EXEC:
1017              return treesMatch(((JCExpressionStatement)t1).expr, ((JCExpressionStatement)t2).expr);
1018          case JCTree.BREAK:
1019              return matchBreak((JCBreak)t1, (JCBreak)t2);
1020          case JCTree.CONTINUE:
1021              return matchContinue((JCContinue)t1, (JCContinue)t2);
1022          case JCTree.RETURN:
1023              return treesMatch(((JCReturn)t1).expr, ((JCReturn)t2).expr);
1024          case JCTree.THROW:
1025              return treesMatch(((JCThrow)t1).expr, ((JCThrow)t2).expr);
1026          case JCTree.ASSERT:
1027              return matchAssert((JCAssert)t1, (JCAssert)t2);
1028          case JCTree.APPLY:
1029              return matchApply((JCMethodInvocation)t1, (JCMethodInvocation)t2);
1030          case JCTree.NEWCLASS:
1031              return matchNewClass((JCNewClass)t1, (JCNewClass)t2);
1032          case JCTree.NEWARRAY:
1033              return matchNewArray((JCNewArray)t1, (JCNewArray)t2);
1034          case JCTree.PARENS:
1035              return treesMatch(((JCParens)t1).expr, ((JCParens)t2).expr);
1036          case JCTree.ASSIGN:
1037              return matchAssign((JCAssign)t1, (JCAssign)t2);
1038          case JCTree.TYPECAST:
1039              return matchTypeCast((JCTypeCast)t1, (JCTypeCast)t2);
1040          case JCTree.TYPETEST:
1041              return matchTypeTest((JCInstanceOf)t1, (JCInstanceOf)t2);
1042          case JCTree.INDEXED:
1043              return matchIndexed((JCArrayAccess)t1, (JCArrayAccess)t2);
1044          case JCTree.SELECT:
1045              return ((JCFieldAccess)t1).sym == ((JCFieldAccess)t2).sym;
1046          case JCTree.IDENT:
1047              return ((JCIdent)t1).sym == ((JCIdent)t2).sym;
1048          case JCTree.LITERAL:
1049              return matchLiteral((JCLiteral)t1, (JCLiteral)t2);
1050          case JCTree.TYPEIDENT:
1051              return ((JCPrimitiveTypeTree)t1).typetag == ((JCPrimitiveTypeTree)t2).typetag;
1052          case JCTree.TYPEARRAY:
1053              return treesMatch(((JCArrayTypeTree)t1).elemtype, ((JCArrayTypeTree)t2).elemtype);
1054          case JCTree.TYPEAPPLY:
1055              return matchTypeApply((JCTypeApply)t1, (JCTypeApply)t2);
1056          case JCTree.TYPEPARAMETER:
1057              return matchTypeParameter((JCTypeParameter)t1, (JCTypeParameter)t2);
1058          case JCTree.WILDCARD:
1059              return matchWildcard((JCWildcard)t1, (JCWildcard)t2);
1060          case JCTree.TYPEBOUNDKIND:
1061              return ((TypeBoundKind)t1).kind == ((TypeBoundKind)t2).kind;
1062          case JCTree.ANNOTATION:
1063              return matchAnnotation((JCAnnotation)t1, (JCAnnotation)t2);
1064          case JCTree.LETEXPR:
1065              return matchLetExpr((LetExpr)t1, (LetExpr)t2);
1066          case JCTree.POS:
1067          case JCTree.NEG:
1068          case JCTree.NOT:
1069          case JCTree.COMPL:
1070          case JCTree.PREINC:
1071          case JCTree.PREDEC:
1072          case JCTree.POSTINC:
1073          case JCTree.POSTDEC:
1074          case JCTree.NULLCHK:
1075              return matchUnary((JCUnary)t1, (JCUnary)t2);
1076          case JCTree.OR:
1077          case JCTree.AND:
1078          case JCTree.BITOR:
1079          case JCTree.BITXOR:
1080          case JCTree.BITAND:
1081          case JCTree.EQ:
1082          case JCTree.NE:
1083          case JCTree.LT:
1084          case JCTree.GT:
1085          case JCTree.LE:
1086          case JCTree.GE:
1087          case JCTree.SL:
1088          case JCTree.SR:
1089          case JCTree.USR:
1090          case JCTree.PLUS:
1091          case JCTree.MINUS:
1092          case JCTree.MUL:
1093          case JCTree.DIV:
1094          case JCTree.MOD:
1095              return matchBinary((JCBinary)t1, (JCBinary)t2);
1096          case JCTree.BITOR_ASG:
1097          case JCTree.BITXOR_ASG:
1098          case JCTree.BITAND_ASG:
1099          case JCTree.SL_ASG:
1100          case JCTree.SR_ASG:
1101          case JCTree.USR_ASG:
1102          case JCTree.PLUS_ASG:
1103          case JCTree.MINUS_ASG:
1104          case JCTree.MUL_ASG:
1105          case JCTree.DIV_ASG:
1106          case JCTree.MOD_ASG:
1107              return matchAssignop((JCAssignOp)t1, (JCAssignOp)t2);
1108          default:
1109              String JavaDoc msg = ((com.sun.source.tree.Tree)t1).getKind().toString() +
1110                      " " + t1.getClass().getName();
1111              throw new AssertionError JavaDoc(msg);
1112        }
1113    }
1114
1115    protected boolean nameChanged(Name oldName, Name newName) {
1116        if (oldName == newName)
1117            return false;
1118        byte[] arr1 = oldName.toUtf();
1119        byte[] arr2 = newName.toUtf();
1120        int len = arr1.length;
1121        if (len != arr2.length)
1122            return true;
1123        for (int i = 0; i < len; i++)
1124            if (arr1[i] != arr2[i])
1125                return true;
1126        return false;
1127    }
1128
1129    /**
1130     * Diff an unordered list, which may contain insertions and deletions.
1131     */

1132    protected void diffList(List<? extends JCTree> oldList,
1133                            List<? extends JCTree> newList,
1134                            LineInsertionType newLine, int insertHint) {
1135        diffList(oldList, newList, newLine, insertHint, null);
1136    }
1137    
1138    /**
1139     * Diff an unordered list, which may contain insertions and deletions.
1140     * The owningClassName hint will be used when inserting constructors.
1141     */

1142    protected void diffList(List<? extends JCTree> oldList,
1143                            List<? extends JCTree> newList,
1144                            LineInsertionType newLine, int insertHint, Name owningClassName) {
1145        if (oldList == newList)
1146            return;
1147        assert oldList != null && newList != null;
1148        int lastOldPos = insertHint;
1149        Iterator JavaDoc<? extends JCTree> oldIter = oldList.iterator();
1150        Iterator JavaDoc<? extends JCTree> newIter = newList.iterator();
1151        JCTree oldT = safeNext(oldIter);
1152        JCTree newT = safeNext(newIter);
1153        while (oldT != null && newT != null) {
1154            if (oldTopLevel != null) {
1155                int endPos = model.getEndPos(oldT, oldTopLevel);
1156
1157                if (endPos != Position.NOPOS)
1158                    lastOldPos = endPos;
1159            }
1160            if (treesMatch(oldT, newT, false)) {
1161                diffTree(oldT, newT);
1162                oldT = safeNext(oldIter);
1163                newT = safeNext(newIter);
1164            }
1165            else if (!listContains(newList, oldT) && !listContains(oldList, newT)) {
1166                append(Diff.modify(oldT, getOldPos(oldT), newT));
1167                oldT = safeNext(oldIter);
1168                newT = safeNext(newIter);
1169            }
1170            else if (!listContains(newList, oldT)) {
1171                if (!isHidden(oldT, oldParent))
1172                    append(Diff.delete(oldT, getOldPos(oldT)));
1173                oldT = safeNext(oldIter);
1174            }
1175            else {
1176                if (!isHidden(newT, newParent))
1177                    append(Diff.insert(newT, getOldPos(oldT), newLine, owningClassName));
1178                newT = safeNext(newIter);
1179            }
1180        }
1181        while (oldT != null) {
1182            if (!isHidden(oldT, oldParent))
1183                append(Diff.delete(oldT, getOldPos(oldT)));
1184            if (oldTopLevel != null)
1185                lastOldPos = model.getEndPos(oldT, oldTopLevel);
1186            oldT = safeNext(oldIter);
1187        }
1188        while (newT != null) {
1189            if (!isHidden(newT, newParent))
1190                append(Diff.insert(newT, lastOldPos, newLine, owningClassName));
1191            newT = safeNext(newIter);
1192        }
1193    }
1194    
1195    private JCTree safeNext(Iterator JavaDoc<? extends JCTree> iter) {
1196        return iter.hasNext() ? iter.next() : null;
1197    }
1198
1199    // XXX: this method should be removed later when all call will be
1200
// refactored and will use new list matching
1201
protected void diffParameterList(List<? extends JCTree> oldList, List<? extends JCTree> newList) {
1202        if (oldList == newList)
1203            return;
1204        assert oldList != null && newList != null;
1205        int lastOldPos = Query.NOPOS;
1206        Iterator JavaDoc<? extends JCTree> oldIter = oldList.iterator();
1207        Iterator JavaDoc<? extends JCTree> newIter = newList.iterator();
1208        while (oldIter.hasNext() && newIter.hasNext()) {
1209            JCTree oldT = oldIter.next();
1210            diffTree(oldT, newIter.next());
1211            if (oldTopLevel != null)
1212                lastOldPos = model.getEndPos(oldT, oldTopLevel);
1213        }
1214        while (oldIter.hasNext()) {
1215            JCTree oldT = oldIter.next();
1216            append(Diff.delete(oldT, getOldPos(oldT)));
1217        }
1218        while (newIter.hasNext()) {
1219            append(Diff.insert(newIter.next(), lastOldPos, LineInsertionType.BEFORE));
1220        }
1221    }
1222    
1223    /**
1224     * Diff a ordered list for differences.
1225     */

1226    protected void diffList2(
1227        List<? extends JCTree> oldList, List<? extends JCTree> newList,
1228        int initialPos, PositionEstimator estimator)
1229    {
1230        if (oldList == newList)
1231            return;
1232        assert oldList != null && newList != null;
1233        int lastOldPos = initialPos;
1234        
1235        ListMatcher<JCTree> matcher = ListMatcher.<JCTree>instance(
1236                (List<JCTree>) oldList,
1237                (List<JCTree>) newList
1238        );
1239        if (!matcher.match()) {
1240            return;
1241        }
1242        Iterator JavaDoc<? extends JCTree> oldIter = oldList.iterator();
1243        ResultItem<JCTree>[] result = matcher.getTransformedResult();
1244        Separator s = matcher.separatorInstance();
1245        s.compute();
1246        int[][] matrix = estimator.getMatrix();
1247        int testPos = initialPos;
1248        int i = 0;
1249        for (int j = 0; j < result.length; j++) {
1250            JCTree oldT;
1251            ResultItem<JCTree> item = result[j];
1252            switch (item.operation) {
1253                case MODIFY: {
1254                    tokenSequence.moveIndex(matrix[i][4]);
1255                    if (tokenSequence.moveNext()) {
1256                        testPos = tokenSequence.offset();
1257                        if (JavaTokenId.COMMA == tokenSequence.token().id())
1258                            testPos += JavaTokenId.COMMA.fixedText().length();
1259                    }
1260                    oldT = oldIter.next(); ++i;
1261                    append(Diff.modify("", lastOldPos, oldT, item.element, "", ListType.PARAMETER));
1262                    lastOldPos = endPos(oldT);
1263                    break;
1264                }
1265                case INSERT: {
1266                    String JavaDoc prec = s.head(j) ? estimator.head() : s.prev(j) ? estimator.sep() : null;
1267                    String JavaDoc tail = s.next(j) ? estimator.sep() : null;
1268                    if (estimator.getIndentString() != null && !estimator.getIndentString().equals(" ")) {
1269                        prec += estimator.getIndentString();
1270                    }
1271                    append(Diff.insert(testPos, prec, item.element, tail, LineInsertionType.NONE));
1272                    break;
1273                }
1274                case DELETE: {
1275                    // compute offsets for removal (tree bounds are not enough
1276
// in this case, we have to remove also tokens around like
1277
// preceding keyword, i.e. throws, implements etc. and also
1278
// separators like commas.
1279

1280                    // this is a hack: be careful when removing the first:
1281
// throws Exception,IOException... do not remove the space
1282
// after throws keyword, there is not space after comma!
1283
int delta = 0;
1284                    if (i == 0 && matrix[i+1][2] != -1 && matrix[i+1][2] == matrix[i+1][3]) {
1285                        ++delta;
1286                    }
1287                    int startOffset = toOff(s.head(j) || s.prev(j) ? matrix[i][1] : matrix[i][2+delta]);
1288                    int endOffset = toOff(s.tail(j) || s.next(j) ? matrix[i+1][2] : matrix[i][4]);
1289                    assert startOffset != -1 && endOffset != -1 : "Invalid offset!";
1290                    append(Diff.delete(startOffset, endOffset));
1291                    tokenSequence.moveIndex(matrix[i][4]);
1292                    if (tokenSequence.moveNext()) {
1293                        testPos = tokenSequence.offset();
1294                        if (JavaTokenId.COMMA == tokenSequence.token().id())
1295                            testPos += JavaTokenId.COMMA.fixedText().length();
1296                    }
1297                    oldT = oldIter.next(); ++i;
1298                    lastOldPos = endPos(item.element);
1299                    break;
1300                }
1301                case NOCHANGE: {
1302                    tokenSequence.moveIndex(matrix[i][4]);
1303                    if (tokenSequence.moveNext()) {
1304                        testPos = tokenSequence.offset();
1305                        if (JavaTokenId.COMMA == tokenSequence.token().id())
1306                            testPos += JavaTokenId.COMMA.fixedText().length();
1307                    }
1308                    oldT = oldIter.next(); ++i;
1309                    lastOldPos = endPos(oldT);
1310                    break;
1311                }
1312            }
1313        }
1314    }
1315
1316    private int toOff(int tokenIndex) {
1317        if (tokenIndex == -1) {
1318            return -1;
1319        }
1320        tokenSequence.moveIndex(tokenIndex);
1321        return tokenSequence.offset();
1322    }
1323    
1324    /**
1325     * Diff a ordered list for differences.
1326     */

1327    protected void diffParameterList(List<? extends JCTree> oldList,
1328                                     List<? extends JCTree> newList,
1329                                     int where, ListType type)
1330    {
1331        if (oldList == newList)
1332            return;
1333        assert oldList != null && newList != null;
1334        int lastOldPos = where;
1335        
1336        ListMatcher<JCExpression> matcher = ListMatcher.<JCExpression>instance(
1337                (List<JCExpression>) oldList,
1338                (List<JCExpression>) newList
1339        );
1340        if (!matcher.match()) {
1341            return;
1342        }
1343        Iterator JavaDoc<? extends JCTree> oldIter = oldList.iterator();
1344        ResultItem<JCExpression>[] result = matcher.getTransformedResult();
1345        Separator s = matcher.separatorInstance();
1346        s.compute();
1347        for (int j = 0; j < result.length; j++) {
1348            JCTree oldT;
1349            ResultItem<JCExpression> item = result[j];
1350            switch (item.operation) {
1351                case MODIFY:
1352                    oldT = oldIter.next();
1353                    append(Diff.modify("", lastOldPos, oldT, item.element, "", ListType.PARAMETER));
1354                    lastOldPos = endPos(oldT);
1355                    break;
1356                case INSERT: {
1357                    String JavaDoc prec = s.head(j) ? type.head() : s.prev(j) ? type.sep() : null;
1358                    String JavaDoc tail = s.tail(j) ? type.tail() : s.next(j) ? type.sep() : null;
1359                    // XXX: todo (#pf): strange, should be solved better. Used for
1360
// move position after last available separator. In case there
1361
// is no available separator, use lastOldPos immediately for
1362
// diff.
1363
//if (type.sep().equals(tail)) {
1364
// is there any next element in old list and we do not
1365
// insert the first element.
1366
int pos = lastOldPos;
1367                    if (oldIter.hasNext() && lastOldPos != where) {
1368                        pos = TokenUtilities.moveFwdToToken(tokenSequence, lastOldPos, type.sep);
1369                        if (pos > 0) {
1370                            pos += type.sep.fixedText().length();
1371                        }
1372                    }
1373                    append(Diff.insert(prec, item.element, pos, tail, ListType.PARAMETER));
1374                    break;
1375                }
1376                case DELETE: {
1377                    // XXX: todo (#pf): use tokens around. Should be refactored to JavaTokenId and
1378
// some formatting policy
1379
String JavaDoc prec = s.head(j) ? type.headToken() : s.prev(j) ? type.sepToken() : null;
1380                    String JavaDoc tail = s.tail(j) ? type.tailToken() : s.next(j) ? type.sepToken() : null;
1381                    append(Diff.delete(prec, item.element, lastOldPos, tail));
1382                    oldT = oldIter.next();
1383                    lastOldPos = endPos(item.element);
1384                    break;
1385                }
1386                case NOCHANGE:
1387                    oldT = oldIter.next();
1388                    lastOldPos = endPos(oldT);
1389                    break;
1390            }
1391        }
1392    }
1393    
1394    /**
1395     * Used for diffing lists which does not contain any separator.
1396     * (Currently for imports and members diffing.)
1397     */

1398    protected void diffList(
1399            List<? extends JCTree> oldList,
1400            List<? extends JCTree> newList,
1401            int initialPos,
1402            PositionEstimator estimator,
1403            Measure measure)
1404    {
1405        diffList(oldList, newList, initialPos, estimator, measure, null);
1406    }
1407    
1408    protected void diffList(
1409            List<? extends JCTree> oldList,
1410            List<? extends JCTree> newList,
1411            int initialPos,
1412            PositionEstimator estimator,
1413            Measure measure,
1414            Name owningClassName)
1415    {
1416        if (oldList == newList)
1417            return;
1418        assert oldList != null && newList != null;
1419        
1420        ListMatcher<JCExpression> matcher = ListMatcher.<JCExpression>instance(
1421                (List<JCExpression>) oldList,
1422                (List<JCExpression>) newList,
1423                measure
1424        );
1425        if (!matcher.match()) {
1426            return;
1427        }
1428        Iterator JavaDoc<? extends JCTree> oldIter = oldList.iterator();
1429        ResultItem<JCExpression>[] result = matcher.getTransformedResult();
1430        int posHint = initialPos;
1431        int i = 0;
1432        for (int j = 0; j < result.length; j++) {
1433            JCTree oldT = null;
1434            ResultItem<JCExpression> item = result[j];
1435            switch (item.operation) {
1436                case MODIFY:
1437                    oldT = oldIter.next();
1438                    if (treesMatch(oldT, item.element, false)) {
1439                        diffTree(oldT, item.element);
1440                    } else {
1441                        append(Diff.modify(oldT, posHint, item.element));
1442                    }
1443                    posHint = estimator.getPositions(i)[1];
1444                    ++i;
1445                    break;
1446                case INSERT: {
1447                    int pos = estimator.getInsertPos(i);
1448                    // estimator couldn't compute the position - probably
1449
// first element is inserted to the collection
1450
if (pos < 0 && oldList.isEmpty() && i == 0) {
1451                        pos = initialPos;
1452                        StringBuilder JavaDoc aHead = new StringBuilder JavaDoc(), aTail = new StringBuilder JavaDoc();
1453                        pos = estimator.prepare(initialPos, aHead, aTail);
1454                        String JavaDoc tail = null;
1455                        if (j+1 == result.length) {
1456                            tail = aTail.toString();
1457                        }
1458                        append(Diff.insert(pos, aHead.toString(), item.element, tail, estimator.lineInsertType(), owningClassName));
1459                    } else {
1460                        append(Diff.insert(item.element, pos, estimator.lineInsertType(), owningClassName));
1461                    }
1462                    break;
1463                }
1464                case DELETE: {
1465                    oldT = oldIter.next();
1466                    int[] pos = estimator.getPositions(i);
1467                     ++i;
1468                    posHint = pos[1];
1469                    append(Diff.delete(pos[0], pos[1]));
1470                    break;
1471                }
1472                case NOCHANGE:
1473                    oldT = oldIter.next();
1474                    posHint = estimator.getPositions(i)[1];
1475                    ++i;
1476                    break;
1477            }
1478        }
1479    }
1480    
1481    private List filterHidden(List<JCTree> list) {
1482        List<JCTree> result = new ArrayList JavaDoc<JCTree>(); // todo (#pf): capacity?
1483
for (JCTree tree : list) {
1484            if (Kind.METHOD == tree.getKind()) {
1485                CharSequence JavaDoc name = ((MethodTree) tree).getName();
1486                if ("<init>".contentEquals(name) && tree.pos == oldParent.pos)
1487                    continue;
1488            }
1489            result.add(tree);
1490        }
1491        return result;
1492    }
1493    
1494    private boolean isHidden(JCTree t, JCTree parent) {
1495        if (parent == null)
1496            return false;
1497        //TODO: the test was originaly: t.pos == parent.pos, which caused problems when adding
1498
//member into class without non-syntetic constructors. See ConstructorTest.
1499
if (t.pos == Query.NOPOS)
1500            return true;
1501        return model.isSynthetic(t);
1502    }
1503    
1504    protected void diffPrecedingComments(JCTree oldT, JCTree newT) {
1505        CommentSet cs = comments.getComments(newT);
1506        if (!cs.hasChanges())
1507            return;
1508        List<Comment> oldComments = comments.getComments(oldT).getPrecedingComments();
1509        List<Comment> newComments = cs.getPrecedingComments();
1510        diffCommentLists(oldT, newT, oldComments, newComments, false);
1511    }
1512
1513    protected void diffTrailingComments(JCTree oldT, JCTree newT) {
1514        CommentSet cs = comments.getComments(newT);
1515        if (!cs.hasChanges())
1516            return;
1517        List<Comment> oldComments = comments.getComments(oldT).getTrailingComments();
1518        List<Comment> newComments = cs.getTrailingComments();
1519        diffCommentLists(oldT, newT, oldComments, newComments, true);
1520    }
1521    
1522    private void diffCommentLists(JCTree oldT, JCTree newT, List<Comment>oldList,
1523                                  List<Comment>newList, boolean trailing) {
1524        int lastPos = getOldPos(oldT);
1525        Iterator JavaDoc<Comment> oldIter = oldList.iterator();
1526        Iterator JavaDoc<Comment> newIter = newList.iterator();
1527        Comment oldC = safeNext(oldIter);
1528        Comment newC = safeNext(newIter);
1529        while (oldC != null && newC != null) {
1530            lastPos = oldC.pos();
1531            if (commentsMatch(oldC, newC)) {
1532                oldC = safeNext(oldIter);
1533                newC = safeNext(newIter);
1534            }
1535            else if (!listContains(newList, oldC)) {
1536                if (!listContains(oldList, newC)) {
1537                    append(Diff.modify(oldT, newT, oldC, newC));
1538                    oldC = safeNext(oldIter);
1539                    newC = safeNext(newIter);
1540                } else {
1541                    append(Diff.delete(oldT, newT, oldC));
1542                    oldC = safeNext(oldIter);
1543                }
1544            }
1545            else {
1546                append(Diff.insert(lastPos, LineInsertionType.BEFORE, oldT, newT, newC, trailing));
1547                newC = safeNext(newIter);
1548            }
1549        }
1550        while (oldC != null) {
1551            append(Diff.delete(oldT, newT, oldC));
1552            oldC = safeNext(oldIter);
1553        }
1554        while (newC != null) {
1555            append(Diff.insert(lastPos, LineInsertionType.BEFORE, oldT, newT, newC, trailing));
1556            lastPos += newC.endPos() - newC.pos();
1557            newC = safeNext(oldIter);
1558        }
1559    }
1560    
1561    private Comment safeNext(Iterator JavaDoc<Comment> iter) {
1562        return iter.hasNext() ? iter.next() : null;
1563    }
1564    
1565    private boolean commentsMatch(Comment oldC, Comment newC) {
1566        if (oldC == null && newC == null)
1567            return true;
1568        if (oldC == null || newC == null)
1569            return false;
1570        return oldC.equals(newC);
1571    }
1572    
1573    private boolean listContains(List<Comment>list, Comment comment) {
1574        for (Comment c : list)
1575            if (c.equals(comment))
1576                return true;
1577        return false;
1578    }
1579    
1580    // from TreesService
1581
private static JCTree leftMostTree(JCTree tree) {
1582        switch (tree.tag) {
1583            case(JCTree.APPLY):
1584                return leftMostTree(((JCMethodInvocation)tree).meth);
1585            case(JCTree.ASSIGN):
1586                return leftMostTree(((JCAssign)tree).lhs);
1587            case(JCTree.BITOR_ASG): case(JCTree.BITXOR_ASG): case(JCTree.BITAND_ASG):
1588            case(JCTree.SL_ASG): case(JCTree.SR_ASG): case(JCTree.USR_ASG):
1589            case(JCTree.PLUS_ASG): case(JCTree.MINUS_ASG): case(JCTree.MUL_ASG):
1590            case(JCTree.DIV_ASG): case(JCTree.MOD_ASG):
1591                return leftMostTree(((JCAssignOp)tree).lhs);
1592            case(JCTree.OR): case(JCTree.AND): case(JCTree.BITOR):
1593            case(JCTree.BITXOR): case(JCTree.BITAND): case(JCTree.EQ):
1594            case(JCTree.NE): case(JCTree.LT): case(JCTree.GT):
1595            case(JCTree.LE): case(JCTree.GE): case(JCTree.SL):
1596            case(JCTree.SR): case(JCTree.USR): case(JCTree.PLUS):
1597            case(JCTree.MINUS): case(JCTree.MUL): case(JCTree.DIV):
1598            case(JCTree.MOD):
1599                return leftMostTree(((JCBinary)tree).lhs);
1600            case(JCTree.CLASSDEF): {
1601                JCClassDecl node = (JCClassDecl)tree;
1602                if (node.mods.pos != Position.NOPOS)
1603                    return node.mods;
1604                break;
1605            }
1606            case(JCTree.CONDEXPR):
1607                return leftMostTree(((JCConditional)tree).cond);
1608            case(JCTree.EXEC):
1609                return leftMostTree(((JCExpressionStatement)tree).expr);
1610            case(JCTree.INDEXED):
1611                return leftMostTree(((JCArrayAccess)tree).indexed);
1612            case(JCTree.METHODDEF): {
1613                JCMethodDecl node = (JCMethodDecl)tree;
1614                if (node.mods.pos != Position.NOPOS)
1615                    return node.mods;
1616                if (node.restype != null) // true for constructors
1617
return leftMostTree(node.restype);
1618                return node;
1619            }
1620            case(JCTree.SELECT):
1621                return leftMostTree(((JCFieldAccess)tree).selected);
1622            case(JCTree.TYPEAPPLY):
1623                return leftMostTree(((JCTypeApply)tree).clazz);
1624            case(JCTree.TYPEARRAY):
1625                return leftMostTree(((JCArrayTypeTree)tree).elemtype);
1626            case(JCTree.TYPETEST):
1627                return leftMostTree(((JCInstanceOf)tree).expr);
1628            case(JCTree.POSTINC):
1629            case(JCTree.POSTDEC):
1630                return leftMostTree(((JCUnary)tree).arg);
1631            case(JCTree.VARDEF): {
1632                JCVariableDecl node = (JCVariableDecl)tree;
1633                if (node.mods.pos != Position.NOPOS)
1634                    return node.mods;
1635                return leftMostTree(node.vartype);
1636            }
1637            case(JCTree.TOPLEVEL): {
1638                JCCompilationUnit node = (JCCompilationUnit)tree;
1639                assert node.defs.size() > 0;
1640                return node.pid != null ? node.pid : node.defs.head;
1641            }
1642        }
1643        return tree;
1644    }
1645    
1646    private int getOldPos(JCTree oldT) {
1647        return getOldPos(oldT, model, undo);
1648    }
1649    
1650    static int getOldPos(JCTree oldT, ASTModel model, UndoList undo) {
1651        int oldPos = model.getStartPos(oldT);
1652        if (oldPos == Query.NOPOS) {
1653            // see if original tree is available for position
1654
JCTree t = (JCTree)undo.getOld(leftMostTree(oldT));
1655            if (t != null && t != oldT)
1656                // recurse in case there are multiple changes to this tree
1657
oldPos = getOldPos(t, model, undo);
1658        }
1659        if (oldPos == Query.NOPOS)
1660            oldPos = oldT.pos == Query.NOPOS ? leftMostTree(oldT).pos : oldT.pos;
1661        return oldPos;
1662    }
1663    
1664    /**
1665     * Create differences between trees. Old tree has to exist, i.e.
1666     * <code>oldT != null</code>. There is a one exception - when both
1667     * <code>oldT</code> and <code>newT</code> are null, then method
1668     * just returns.
1669     *
1670     * @param oldT original tree in source code
1671     * @param newT tree to repace the original tree
1672     */

1673    protected void diffTree(JCTree oldT, JCTree newT) {
1674        if (oldT == null && newT != null)
1675            throw new IllegalArgumentException JavaDoc("Null is not allowed in parameters.");
1676
1677        diffTree(oldT, newT, Position.NOPOS, null);
1678    }
1679    
1680    private void diffTree(JCTree oldT, JCTree newT, int startPos, String JavaDoc head) {
1681        if (oldT == newT)
1682            return;
1683        diffPrecedingComments(oldT, newT);
1684
1685        if (oldT == null) {
1686            append(Diff.insert(startPos, head, newT, "", LineInsertionType.NONE));
1687            return;
1688        }
1689        int oldPos = getOldPos(oldT);
1690
1691        if (newT == null) {
1692            // todo (#pf): perhaps else part is enough. But to be more careful,
1693
// leaving original implementation until the test suite will be
1694
// large enough.
1695
if (startPos == Position.NOPOS)
1696                append(Diff.delete(oldT, oldPos));
1697            else
1698                append(Diff.delete(startPos, endPos(oldT)));
1699            return;
1700        }
1701        
1702        if ((oldT.tag != JCTree.TOPLEVEL && oldT.tag != JCTree.METHODDEF && oldT.tag != JCTree.CLASSDEF && oldT.tag != JCTree.VARDEF) &&
1703            (oldT.tag != newT.tag || newT.pos == Query.NOPOS || oldT.type != newT.type)) {
1704            append(Diff.modify(oldT, oldPos, newT));
1705            return;
1706        }
1707
1708        switch (oldT.tag) {
1709          case JCTree.TOPLEVEL:
1710              diffTopLevel((JCCompilationUnit)oldT, (JCCompilationUnit)newT);
1711              break;
1712          case JCTree.IMPORT:
1713              diffImport((JCImport)oldT, (JCImport)newT);
1714              break;
1715          case JCTree.CLASSDEF:
1716              diffClassDef((JCClassDecl)oldT, (JCClassDecl)newT);
1717              break;
1718          case JCTree.METHODDEF:
1719              diffMethodDef((JCMethodDecl)oldT, (JCMethodDecl)newT);
1720              break;
1721          case JCTree.VARDEF:
1722              diffVarDef((JCVariableDecl)oldT, (JCVariableDecl)newT);
1723              break;
1724          case JCTree.SKIP:
1725              break;
1726          case JCTree.BLOCK:
1727              diffBlock((JCBlock)oldT, (JCBlock)newT);
1728              break;
1729          case JCTree.DOLOOP:
1730              diffDoLoop((JCDoWhileLoop)oldT, (JCDoWhileLoop)newT);
1731              break;
1732          case JCTree.WHILELOOP:
1733              diffWhileLoop((JCWhileLoop)oldT, (JCWhileLoop)newT);
1734              break;
1735          case JCTree.FORLOOP:
1736              diffForLoop((JCForLoop)oldT, (JCForLoop)newT);
1737              break;
1738          case JCTree.FOREACHLOOP:
1739              diffForeachLoop((JCEnhancedForLoop)oldT, (JCEnhancedForLoop)newT);
1740              break;
1741          case JCTree.LABELLED:
1742              diffLabelled((JCLabeledStatement)oldT, (JCLabeledStatement)newT);
1743              break;
1744          case JCTree.SWITCH:
1745              diffSwitch((JCSwitch)oldT, (JCSwitch)newT);
1746              break;
1747          case JCTree.CASE:
1748              diffCase((JCCase)oldT, (JCCase)newT);
1749              break;
1750          case JCTree.SYNCHRONIZED:
1751              diffSynchronized((JCSynchronized)oldT, (JCSynchronized)newT);
1752              break;
1753          case JCTree.TRY:
1754              diffTry((JCTry)oldT, (JCTry)newT);
1755              break;
1756          case JCTree.CATCH:
1757              diffCatch((JCCatch)oldT, (JCCatch)newT);
1758              break;
1759          case JCTree.CONDEXPR:
1760              diffConditional((JCConditional)oldT, (JCConditional)newT);
1761              break;
1762          case JCTree.IF:
1763              diffIf((JCIf)oldT, (JCIf)newT);
1764              break;
1765          case JCTree.EXEC:
1766              diffExec((JCExpressionStatement)oldT, (JCExpressionStatement)newT);
1767              break;
1768          case JCTree.BREAK:
1769              diffBreak((JCBreak)oldT, (JCBreak)newT);
1770              break;
1771          case JCTree.CONTINUE:
1772              diffContinue((JCContinue)oldT, (JCContinue)newT);
1773              break;
1774          case JCTree.RETURN:
1775              diffReturn((JCReturn)oldT, (JCReturn)newT);
1776              break;
1777          case JCTree.THROW:
1778              diffThrow((JCThrow)oldT, (JCThrow)newT);
1779              break;
1780          case JCTree.ASSERT:
1781              diffAssert((JCAssert)oldT, (JCAssert)newT);
1782              break;
1783          case JCTree.APPLY:
1784              diffApply((JCMethodInvocation)oldT, (JCMethodInvocation)newT);
1785              break;
1786          case JCTree.NEWCLASS:
1787              diffNewClass((JCNewClass)oldT, (JCNewClass)newT);
1788              break;
1789          case JCTree.NEWARRAY:
1790              diffNewArray((JCNewArray)oldT, (JCNewArray)newT);
1791              break;
1792          case JCTree.PARENS:
1793              diffParens((JCParens)oldT, (JCParens)newT);
1794              break;
1795          case JCTree.ASSIGN:
1796              diffAssign((JCAssign)oldT, (JCAssign)newT);
1797              break;
1798          case JCTree.TYPECAST:
1799              diffTypeCast((JCTypeCast)oldT, (JCTypeCast)newT);
1800              break;
1801          case JCTree.TYPETEST:
1802              diffTypeTest((JCInstanceOf)oldT, (JCInstanceOf)newT);
1803              break;
1804          case JCTree.INDEXED:
1805              diffIndexed((JCArrayAccess)oldT, (JCArrayAccess)newT);
1806              break;
1807          case JCTree.SELECT:
1808              diffSelect((JCFieldAccess)oldT, (JCFieldAccess)newT);
1809              break;
1810          case JCTree.IDENT:
1811              diffIdent((JCIdent)oldT, (JCIdent)newT);
1812              break;
1813          case JCTree.LITERAL:
1814              diffLiteral((JCLiteral)oldT, (JCLiteral)newT);
1815              break;
1816          case JCTree.TYPEIDENT:
1817              diffTypeIdent((JCPrimitiveTypeTree)oldT, (JCPrimitiveTypeTree)newT);
1818              break;
1819          case JCTree.TYPEARRAY:
1820              diffTypeArray((JCArrayTypeTree)oldT, (JCArrayTypeTree)newT);
1821              break;
1822          case JCTree.TYPEAPPLY:
1823              diffTypeApply((JCTypeApply)oldT, (JCTypeApply)newT);
1824              break;
1825          case JCTree.TYPEPARAMETER:
1826              diffTypeParameter((JCTypeParameter)oldT, (JCTypeParameter)newT);
1827              break;
1828          case JCTree.WILDCARD:
1829              diffWildcard((JCWildcard)oldT, (JCWildcard)newT);
1830              break;
1831          case JCTree.TYPEBOUNDKIND:
1832              diffTypeBoundKind((TypeBoundKind)oldT, (TypeBoundKind)newT);
1833              break;
1834          case JCTree.ANNOTATION:
1835              diffAnnotation((JCAnnotation)oldT, (JCAnnotation)newT);
1836              break;
1837          case JCTree.LETEXPR:
1838              diffLetExpr((LetExpr)oldT, (LetExpr)newT);
1839              break;
1840          case JCTree.POS:
1841          case JCTree.NEG:
1842          case JCTree.NOT:
1843          case JCTree.COMPL:
1844          case JCTree.PREINC:
1845          case JCTree.PREDEC:
1846          case JCTree.POSTINC:
1847          case JCTree.POSTDEC:
1848          case JCTree.NULLCHK:
1849              diffUnary((JCUnary)oldT, (JCUnary)newT);
1850              break;
1851          case JCTree.OR:
1852          case JCTree.AND:
1853          case JCTree.BITOR:
1854          case JCTree.BITXOR:
1855          case JCTree.BITAND:
1856          case JCTree.EQ:
1857          case JCTree.NE:
1858          case JCTree.LT:
1859          case JCTree.GT:
1860          case JCTree.LE:
1861          case JCTree.GE:
1862          case JCTree.SL:
1863          case JCTree.SR:
1864          case JCTree.USR:
1865          case JCTree.PLUS:
1866          case JCTree.MINUS:
1867          case JCTree.MUL:
1868          case JCTree.DIV:
1869          case JCTree.MOD:
1870              diffBinary((JCBinary)oldT, (JCBinary)newT);
1871              break;
1872          case JCTree.BITOR_ASG:
1873          case JCTree.BITXOR_ASG:
1874          case JCTree.BITAND_ASG:
1875          case JCTree.SL_ASG:
1876          case JCTree.SR_ASG:
1877          case JCTree.USR_ASG:
1878          case JCTree.PLUS_ASG:
1879          case JCTree.MINUS_ASG:
1880          case JCTree.MUL_ASG:
1881          case JCTree.DIV_ASG:
1882          case JCTree.MOD_ASG:
1883              diffAssignop((JCAssignOp)oldT, (JCAssignOp)newT);
1884              break;
1885          case JCTree.ERRONEOUS:
1886              diffErroneous((JCErroneous)oldT, (JCErroneous)newT);
1887              break;
1888          default:
1889              String JavaDoc msg = "Diff not implemented: " +
1890                  ((com.sun.source.tree.Tree)oldT).getKind().toString() +
1891                  " " + oldT.getClass().getName();
1892              throw new AssertionError JavaDoc(msg);
1893        }
1894        diffTrailingComments(oldT, newT);
1895    }
1896
1897    protected boolean listsMatch(List<? extends JCTree> oldList, List<? extends JCTree> newList) {
1898        if (oldList == newList)
1899            return true;
1900        int n = oldList.size();
1901        if (newList.size() != n)
1902            return false;
1903        for (int i = 0; i < n; i++)
1904            if (!treesMatch(oldList.get(i), newList.get(i)))
1905                return false;
1906        return true;
1907    }
1908
1909    private boolean matchImport(JCImport t1, JCImport t2) {
1910        return t1.staticImport == t2.staticImport && treesMatch(t1.qualid, t2.qualid);
1911    }
1912
1913    private boolean matchBlock(JCBlock t1, JCBlock t2) {
1914        return t1.flags == t2.flags && listsMatch(t1.stats, t2.stats);
1915    }
1916
1917    private boolean matchDoLoop(JCDoWhileLoop t1, JCDoWhileLoop t2) {
1918        return treesMatch(t1.cond, t2.cond) && treesMatch(t1.body, t2.body);
1919    }
1920
1921    private boolean matchWhileLoop(JCWhileLoop t1, JCWhileLoop t2) {
1922        return treesMatch(t1.cond, t2.cond) && treesMatch(t1.body, t2.body);
1923    }
1924
1925    private boolean matchForLoop(JCForLoop t1, JCForLoop t2) {
1926        return listsMatch(t1.init, t2.init) && treesMatch(t1.cond, t2.cond) &&
1927               listsMatch(t1.step, t2.step) && treesMatch(t1.body, t2.body);
1928    }
1929    
1930    private boolean matchForeachLoop(JCEnhancedForLoop t1, JCEnhancedForLoop t2) {
1931        return treesMatch(t1.var, t2.var) && treesMatch(t1.expr, t2.expr) &&
1932               treesMatch(t1.body, t2.body);
1933    }
1934
1935    private boolean matchLabelled(JCLabeledStatement t1, JCLabeledStatement t2) {
1936        return t1.label == t2.label && treesMatch(t1.body, t2.body);
1937    }
1938
1939    private boolean matchSwitch(JCSwitch t1, JCSwitch t2) {
1940        return treesMatch(t1.selector, t2.selector) && listsMatch(t1.cases, t2.cases);
1941    }
1942
1943    private boolean matchCase(JCCase t1, JCCase t2) {
1944        return treesMatch(t1.pat, t2.pat) && listsMatch(t1.stats, t2.stats);
1945    }
1946
1947    private boolean matchSynchronized(JCSynchronized t1, JCSynchronized t2) {
1948        return treesMatch(t1.lock, t2.lock) && treesMatch(t1.body, t2.body);
1949    }
1950
1951    private boolean matchTry(JCTry t1, JCTry t2) {
1952        return treesMatch(t1.finalizer, t2.finalizer) &&
1953                listsMatch(t1.catchers, t2.catchers) &&
1954                treesMatch(t1.body, t2.body);
1955    }
1956
1957    private boolean matchCatch(JCCatch t1, JCCatch t2) {
1958        return treesMatch(t1.param, t2.param) && treesMatch(t1.body, t2.body);
1959    }
1960    
1961    private boolean matchConditional(JCConditional t1, JCConditional t2) {
1962        return treesMatch(t1.cond, t2.cond) && treesMatch(t1.truepart, t2.truepart) &&
1963               treesMatch(t1.falsepart, t2.falsepart);
1964    }
1965    
1966    private boolean matchIf(JCIf t1, JCIf t2) {
1967        return treesMatch(t1.cond, t2.cond) && treesMatch(t1.thenpart, t2.thenpart) &&
1968               treesMatch(t1.elsepart, t2.elsepart);
1969    }
1970
1971    private boolean matchBreak(JCBreak t1, JCBreak t2) {
1972        return t1.label == t2.label && treesMatch(t1.target, t2.target);
1973    }
1974
1975    private boolean matchContinue(JCContinue t1, JCContinue t2) {
1976        return t1.label == t2.label && treesMatch(t1.target, t2.target);
1977    }
1978
1979    private boolean matchAssert(JCAssert t1, JCAssert t2) {
1980        return treesMatch(t1.cond, t2.cond) && treesMatch(t1.detail, t2.detail);
1981    }
1982    
1983    private boolean matchApply(JCMethodInvocation t1, JCMethodInvocation t2) {
1984        return t1.varargsElement == t2.varargsElement &&
1985               listsMatch(t1.typeargs, t2.typeargs) &&
1986               treesMatch(t1.meth, t2.meth) &&
1987               listsMatch(t1.args, t2.args);
1988    }
1989    
1990    private boolean matchNewClass(JCNewClass t1, JCNewClass t2) {
1991        return t1.constructor == t2.constructor &&
1992               listsMatch(t1.typeargs, t2.typeargs) &&
1993               listsMatch(t1.args, t2.args) &&
1994               t1.varargsElement == t2.varargsElement;
1995    }
1996    
1997    private boolean matchNewArray(JCNewArray t1, JCNewArray t2) {
1998        return treesMatch(t1.elemtype, t2.elemtype) &&
1999               listsMatch(t1.dims, t2.dims) && listsMatch(t1.elems, t2.elems);
2000    }
2001
2002    private boolean matchAssign(JCAssign t1, JCAssign t2) {
2003        return treesMatch(t1.lhs, t2.lhs) && treesMatch(t1.rhs, t2.rhs);
2004    }
2005
2006    private boolean matchAssignop(JCAssignOp t1, JCAssignOp t2) {
2007        return t1.operator == t2.operator &&
2008               treesMatch(t1.lhs, t2.lhs) && treesMatch(t1.rhs, t2.rhs);
2009    }
2010
2011    private boolean matchUnary(JCUnary t1, JCUnary t2) {
2012        return t1.operator == t2.operator && treesMatch(t1.arg, t2.arg);
2013    }
2014
2015    private boolean matchBinary(JCBinary t1, JCBinary t2) {
2016        return t1.operator == t2.operator &&
2017               treesMatch(t1.lhs, t2.lhs) && treesMatch(t1.rhs, t2.rhs);
2018    }
2019    
2020    private boolean matchTypeCast(JCTypeCast t1, JCTypeCast t2) {
2021        return treesMatch(t1.clazz, t2.clazz) && treesMatch(t1.expr, t2.expr);
2022    }
2023    
2024    private boolean matchTypeTest(JCInstanceOf t1, JCInstanceOf t2) {
2025        return treesMatch(t1.clazz, t2.clazz) && treesMatch(t1.expr, t2.expr);
2026    }
2027    
2028    private boolean matchIndexed(JCArrayAccess t1, JCArrayAccess t2) {
2029        return treesMatch(t1.indexed, t2.indexed) && treesMatch(t1.index, t2.index);
2030    }
2031
2032    private boolean matchLiteral(JCLiteral t1, JCLiteral t2) {
2033        return t1.typetag == t2.typetag && t1.value == t2.value;
2034    }
2035
2036    private boolean matchTypeApply(JCTypeApply t1, JCTypeApply t2) {
2037        return treesMatch(t1.clazz, t2.clazz) &&
2038               listsMatch(t1.arguments, t2.arguments);
2039    }
2040    
2041    private boolean matchTypeParameter(JCTypeParameter t1, JCTypeParameter t2) {
2042        return t1.name == t2.name && listsMatch(t1.bounds, t2.bounds);
2043    }
2044    
2045    private boolean matchWildcard(JCWildcard t1, JCWildcard t2) {
2046        return t1.kind == t2.kind && treesMatch(t1.inner, t2.inner);
2047    }
2048
2049    private boolean matchAnnotation(JCAnnotation t1, JCAnnotation t2) {
2050        return treesMatch(t1.annotationType, t2.annotationType) &&
2051               listsMatch(t1.args, t2.args);
2052    }
2053    
2054    private boolean matchModifiers(JCModifiers t1, JCModifiers t2) {
2055        return t1.flags == t2.flags && listsMatch(t1.annotations, t2.annotations);
2056    }
2057
2058    private boolean matchLetExpr(LetExpr t1, LetExpr t2) {
2059        return listsMatch(t1.defs, t2.defs) && treesMatch(t1.expr, t2.expr);
2060    }
2061
2062    private void diffTreeToken(String JavaDoc preceding, int pos, JCTree t1, JCTree t2, String JavaDoc tail) {
2063        if (t1 == t2) {
2064            return;
2065        } else {
2066            append(Diff.modify(preceding, pos, t1, t2, tail, null));
2067        }
2068    }
2069    
2070    public static enum ListType {
2071        PARAMETER(null, JavaTokenId.COMMA, null, null, null, null),
2072        
2073        TYPE_PARAMETER(JavaTokenId.LT, JavaTokenId.COMMA, JavaTokenId.GT, null, null, "> ");
2074
2075        public final JavaTokenId head;
2076        public final JavaTokenId sep;
2077        public final JavaTokenId tail;
2078        
2079        private final String JavaDoc printHead;
2080        private final String JavaDoc printSepa;
2081        private final String JavaDoc printTail;
2082        
2083        private ListType(JavaTokenId head,
2084                         JavaTokenId separator,
2085                         JavaTokenId tail,
2086                         String JavaDoc printHead,
2087                         String JavaDoc printSeparator,
2088                         String JavaDoc printTail)
2089        {
2090            this.head = head;
2091            this.sep = separator;
2092            this.tail = tail;
2093            this.printHead = printHead;
2094            this.printSepa = printSeparator;
2095            this.printTail = printTail;
2096        }
2097        
2098        public String JavaDoc head() { return p(head, printHead); }
2099        public String JavaDoc sep() { return p(sep, printSepa); }
2100        public String JavaDoc tail() { return p(tail, printTail); }
2101        
2102        public String JavaDoc headToken() { return r(head); }
2103        public String JavaDoc sepToken() { return r(sep); }
2104        public String JavaDoc tailToken() { return r(tail); }
2105        
2106        private String JavaDoc p(JavaTokenId token, String JavaDoc text) {
2107            if (text != null) {
2108                return text;
2109            } else {
2110                if (token == null) {
2111                    return null;
2112                } else {
2113                    return token.fixedText();
2114                }
2115            }
2116        }
2117
2118        private String JavaDoc r(JavaTokenId head) {
2119            return head == null ? null : head.fixedText();
2120        }
2121    }
2122}
2123
Popular Tags