1 19 package org.netbeans.modules.java.source.save; 20 21 import com.sun.source.tree.*; 22 import static com.sun.source.tree.Tree.*; 23 import java.io.IOException ; 24 import javax.swing.text.BadLocationException ; 25 import org.netbeans.api.java.lexer.JavaTokenId; 26 import org.netbeans.api.lexer.TokenSequence; 27 import org.netbeans.modules.java.source.builder.CommentHandlerService; 28 import org.netbeans.modules.java.source.builder.ASTService; 29 import org.netbeans.modules.java.source.builder.UndoListService; 30 import org.netbeans.api.java.source.transform.UndoList; 31 import org.netbeans.api.java.source.Comment; 32 import org.netbeans.api.java.source.query.CommentHandler; 33 import org.netbeans.api.java.source.query.CommentSet; 34 import org.netbeans.modules.java.source.engine.ASTModel; 35 import org.netbeans.api.java.source.query.Query; 36 import com.sun.tools.javac.code.*; 37 import com.sun.tools.javac.tree.JCTree; 38 import com.sun.tools.javac.tree.JCTree.*; 39 import com.sun.tools.javac.tree.Pretty; 40 import com.sun.tools.javac.tree.TreeInfo; 41 import com.sun.tools.javac.util.Context; 42 import com.sun.tools.javac.util.ListBuffer; 43 import com.sun.tools.javac.util.Name; 44 import com.sun.tools.javac.util.Position; 45 import java.util.ArrayList ; 46 import java.util.EnumSet ; 47 import java.util.HashMap ; 48 import java.util.Iterator ; 49 import java.util.List ; 50 import java.util.Map ; 51 import java.util.logging.Level ; 52 import java.util.logging.Logger ; 53 import org.netbeans.api.java.lexer.JavaTokenId; 54 import org.netbeans.api.java.source.WorkingCopy; 55 import org.netbeans.api.lexer.TokenHierarchy; 56 import org.netbeans.modules.java.source.engine.SourceRewriter; 57 import org.netbeans.modules.java.source.engine.StringSourceRewriter; 58 import org.netbeans.modules.java.source.engine.JavaFormatOptions; 59 import org.netbeans.modules.java.source.JavaSourceAccessor; 60 import org.netbeans.modules.java.source.pretty.VeryPretty; 61 import org.netbeans.modules.java.source.save.ListMatcher; 62 import static org.netbeans.modules.java.source.save.TreeDiff.LineInsertionType.*; 63 import static org.netbeans.modules.java.source.save.ListMatcher.*; 64 import static com.sun.tools.javac.code.Flags.*; 65 import static org.netbeans.modules.java.source.save.TreeDiff.*; 66 import static org.netbeans.modules.java.source.save.PositionEstimator.*; 67 68 public class CasualDiff { 69 protected ListBuffer<Diff> diffs; 70 protected CommentHandler comments; 71 protected ASTModel model; 72 protected UndoList undo; 73 protected JCTree oldParent; 74 protected JCTree newParent; 75 protected JCCompilationUnit oldTopLevel; 76 77 private WorkingCopy workingCopy; 78 private TokenSequence<JavaTokenId> tokenSequence; 79 private SourceRewriter output; 80 private String origText; 81 private VeryPretty printer; 82 private int pointer; 83 private Context context; 84 85 private Map <Integer , String > diffInfo = new HashMap <Integer , String >(); 86 87 88 public CasualDiff() { 89 } 90 91 protected CasualDiff(Context context, WorkingCopy workingCopy) { 92 diffs = new ListBuffer<Diff>(); 93 comments = CommentHandlerService.instance(context); 94 model = ASTService.instance(context); 95 undo = UndoListService.instance(context); 96 this.workingCopy = workingCopy; 97 this.tokenSequence = workingCopy.getTokenHierarchy().tokenSequence(); 98 this.output = new StringSourceRewriter(); 99 this.origText = workingCopy.getText(); 100 this.context = context; 101 printer = new VeryPretty(context, JavaFormatOptions.getDefault()); 102 } 103 104 public com.sun.tools.javac.util.List<Diff> getDiffs() { 105 return diffs.toList(); 106 } 107 108 public static com.sun.tools.javac.util.List<Diff> diff(Context context, 109 WorkingCopy copy, 110 JCTree oldTree, 111 JCTree newTree) 112 { 113 CasualDiff td = new CasualDiff(context, copy); 114 try { 115 td.diffTree(oldTree, newTree, new int[] { -1, -1}); 116 String resultSrc = td.output.toString(); 117 td.makeListMatch(td.workingCopy.getText(), resultSrc); 118 JavaSourceAccessor.INSTANCE.getCommandEnvironment(td.workingCopy).setResult(td.diffInfo, "user-info"); 119 } 120 catch (Exception e) { 121 e.printStackTrace(); 122 } 123 124 return td.getDiffs(); 125 } 126 127 private void append(Diff diff) { 128 for (Diff d : diffs) 131 if (d.equals(diff)) 132 return; 133 diffs.append(diff); 134 } 135 136 private int endPos(JCTree t) { 140 return model.getEndPos(t, oldTopLevel); 141 } 142 143 private int endPos(com.sun.tools.javac.util.List<? extends JCTree> trees) { 144 int result = -1; 145 if (trees.nonEmpty()) { 146 result = endPos(trees.head); 147 for (com.sun.tools.javac.util.List <? extends JCTree> l = trees.tail; l.nonEmpty(); l = l.tail) { 148 result = endPos(l.head); 149 } 150 } 151 return result; 152 } 153 154 private int endPos(List<? extends JCTree> trees) { 155 if (trees.isEmpty()) 156 return -1; 157 JCTree tree; 158 return endPos(trees.get(trees.size()-1)); 159 } 160 161 protected void diffTopLevel(JCCompilationUnit oldT, JCCompilationUnit newT) { 162 oldTopLevel = oldT; 163 int posHint = 0; 166 try { 167 posHint = diffPackageStatement(oldT, newT, pointer); 168 PositionEstimator est = EstimatorFactory.imports(((CompilationUnitTree) oldT).getImports(), ((CompilationUnitTree) newT).getImports(), workingCopy); 169 pointer = diffListImports(oldT.getImports(), newT.getImports(), posHint, est, Measure.DEFAULT, printer); 170 if (oldT.getTypeDecls().nonEmpty()) { 171 posHint = getOldPos(oldT.getTypeDecls().head); 172 } else { 173 } 175 output.writeTo(printer.toString()); 176 printer.reset(0); 177 est = EstimatorFactory.toplevel(((CompilationUnitTree) oldT).getTypeDecls(), ((CompilationUnitTree) newT).getTypeDecls(), workingCopy); 178 int[] pos = diffList(oldT.getTypeDecls(), newT.getTypeDecls(), posHint, est, Measure.DEFAULT, printer); 179 if (pointer < pos[0]) 180 output.writeTo(origText.substring(pointer, pos[0])); 181 if (pos[1] > pointer) { 182 pointer = pos[1]; 183 } 184 output.writeTo(printer.toString()); 185 output.writeTo(origText.substring(pointer)); 186 } catch (Exception e) { 187 Logger.getLogger("global").log(Level.SEVERE, "Error during generating!", e); 189 this.output = new StringSourceRewriter(); 190 try { 191 this.output.writeTo(origText); 192 } catch (BadLocationException ex) { 193 } catch (IOException ex) { 194 } 195 } 196 } 197 198 private static enum ChangeKind { 199 INSERT, 200 DELETE, 201 MODIFY, 202 NOCHANGE; 203 } 204 205 private ChangeKind getChangeKind(Tree oldT, Tree newT) { 206 if (oldT == newT) { 207 return ChangeKind.NOCHANGE; 208 } 209 if (oldT != null && newT != null) { 210 return ChangeKind.MODIFY; 211 } 212 if (oldT != null) { 213 return ChangeKind.DELETE; 214 } else { 215 return ChangeKind.INSERT; 216 } 217 } 218 219 private int diffPackageStatement(JCCompilationUnit oldT, JCCompilationUnit newT, int localPointer) { 220 ChangeKind change = getChangeKind(oldT.pid, newT.pid); 221 switch (change) { 222 case NOCHANGE: 224 break; 225 226 case INSERT: 228 printer.print("package "); 229 printer.print(newT.pid); 230 printer.print(";"); 231 printer.newline(); 232 break; 233 234 case DELETE: 236 TokenUtilities.movePrevious(tokenSequence, oldT.pid.getStartPosition()); 237 copyTo(localPointer, tokenSequence.offset()); 238 TokenUtilities.moveNext(tokenSequence, endPos(oldT.pid)); 239 localPointer = tokenSequence.offset() + 1; 240 break; 243 244 case MODIFY: 246 copyTo(localPointer, getOldPos(oldT.pid)); 247 localPointer = endPos(oldT.pid); 248 printer.print(newT.pid); 249 diffInfo.put(getOldPos(oldT.pid), "Update package statement"); 250 break; 251 } 252 return localPointer; 253 } 254 255 protected int diffImport(JCImport oldT, JCImport newT, int[] bounds) { 256 int localPointer = bounds[0]; 257 258 int[] qualBounds = getBounds(oldT.getQualifiedIdentifier()); 259 copyTo(localPointer, qualBounds[0]); 260 localPointer = diffTree(oldT.getQualifiedIdentifier(), newT.getQualifiedIdentifier(), qualBounds); 261 268 copyTo(localPointer, bounds[1]); 269 270 return bounds[1]; 271 } 272 273 private Name origClassName = null; 278 279 protected int diffClassDef(JCClassDecl oldT, JCClassDecl newT, int[] bounds) { 280 int localPointer = bounds[0]; 281 int insertHint = localPointer; 282 JCTree opar = oldParent; 283 oldParent = oldT; 284 JCTree npar = newParent; 285 newParent = newT; 286 if (anonClass == false) { 288 tokenSequence.move(oldT.pos); 289 tokenSequence.moveNext(); tokenSequence.moveNext(); 291 insertHint = TokenUtilities.moveNext(tokenSequence, tokenSequence.offset()); 292 localPointer = diffModifiers(oldT.mods, newT.mods, oldT, localPointer); 293 if (nameChanged(oldT.name, newT.name)) { 294 copyTo(localPointer, insertHint); 295 printer.print(newT.name); 296 diffInfo.put(insertHint, "Change class name"); 297 localPointer = insertHint += oldT.name.length(); 298 origClassName = oldT.name; 299 } else { 300 insertHint += oldT.name.length(); 301 } 302 localPointer = diffParameterList(oldT.typarams, newT.typarams, localPointer); 303 if (oldT.typarams.nonEmpty()) { 304 insertHint = endPos(oldT.typarams.last()); 308 TokenUtilities.moveFwdToToken(tokenSequence, insertHint, JavaTokenId.GT); 309 insertHint = tokenSequence.offset() + JavaTokenId.GT.fixedText().length(); 310 } 311 switch (getChangeKind(oldT.extending, newT.extending)) { 312 case NOCHANGE: 313 insertHint = oldT.extending != null ? endPos(oldT.extending) : insertHint; 314 copyTo(localPointer, localPointer = insertHint); 315 break; 316 case MODIFY: 317 copyTo(localPointer, getOldPos(oldT.extending)); 318 localPointer = diffTree(oldT.extending, newT.extending, getBounds(oldT.extending)); 319 break; 320 321 case INSERT: 322 copyTo(localPointer, insertHint); 323 printer.print(" extends "); 324 printer.print(newT.extending); 325 localPointer = insertHint; 326 break; 327 case DELETE: 328 copyTo(localPointer, insertHint); 329 localPointer = endPos(oldT.extending); 330 break; 331 } 332 if (oldT.implementing.isEmpty()) { 335 if (oldT.extending != null) 339 insertHint = endPos(oldT.extending); 341 else { 342 } 345 } else { 346 insertHint = oldT.implementing.iterator().next().getStartPosition(); 351 } 352 long flags = oldT.sym != null ? oldT.sym.flags() : oldT.mods.flags; 353 PositionEstimator estimator = (flags & INTERFACE) == 0 ? 354 EstimatorFactory.implementz(((ClassTree) oldT).getImplementsClause(), ((ClassTree) newT).getImplementsClause(), workingCopy) : 355 EstimatorFactory.extendz(((ClassTree) oldT).getImplementsClause(), ((ClassTree) newT).getImplementsClause(), workingCopy); 356 if (!newT.implementing.isEmpty()) 357 copyTo(localPointer, insertHint); 358 localPointer = diffList2(oldT.implementing, newT.implementing, insertHint, estimator); 359 insertHint = endPos(oldT) - 1; 360 361 if (oldT.defs.isEmpty()) { 362 insertHint = endPos(oldT) - 1; 367 } else { 368 JCTree t = oldT.defs.head.pos == oldT.pos ? oldT.defs.tail.head : oldT.defs.head; 373 if (t != null) insertHint = t.getStartPosition(); 374 } 375 } else { 376 insertHint = TokenUtilities.moveFwdToToken(tokenSequence, getOldPos(oldT), JavaTokenId.LBRACE); 377 tokenSequence.moveNext(); 378 insertHint = tokenSequence.offset(); 379 } 380 int old = printer.indent(); 381 VeryPretty mujPrinter = new VeryPretty(context, JavaFormatOptions.getDefault()); 382 mujPrinter.reset(old); 383 mujPrinter.indent(); 384 mujPrinter.enclClassName = newT.getSimpleName(); 385 PositionEstimator est = EstimatorFactory.members(filterHidden(oldT.defs), filterHidden(newT.defs), workingCopy); 386 int[] pos = diffList(filterHidden(oldT.defs), filterHidden(newT.defs), insertHint, est, Measure.DEFAULT, mujPrinter); 387 if (localPointer < pos[0]) 388 copyTo(localPointer, pos[0]); 389 printer.print(mujPrinter.toString()); 390 if (pos[1] != -1) 391 copyTo(pos[1], bounds[1]); 392 else 393 copyTo(localPointer, bounds[1]); 394 oldParent = opar; 396 newParent = npar; 397 origClassName = null; 399 printer.undent(old); 400 return bounds[1]; 401 } 402 403 private boolean hasModifiers(JCModifiers mods) { 404 return mods != null && (!mods.getFlags().isEmpty() || !mods.getAnnotations().isEmpty()); 405 } 406 407 protected int diffMethodDef(JCMethodDecl oldT, JCMethodDecl newT, int[] bounds) { 408 int localPointer = bounds[0]; 409 if (!matchModifiers(oldT.mods, newT.mods)) { 411 if (hasModifiers(newT.mods)) { 413 localPointer = diffModifiers(oldT.mods, newT.mods, oldT, localPointer); 414 } else { 415 int oldPos = getOldPos(oldT.mods); 420 copyTo(localPointer, oldPos); 421 localPointer = oldT.restype != null ? getOldPos(oldT.restype) : oldT.pos; 422 } 423 } 424 int pos = oldT.typarams.isEmpty() ? 430 oldT.restype != null ? 431 getOldPos(oldT.restype) : 432 oldT.pos : 433 getOldPos(oldT.typarams.head); 434 435 if (!listsMatch(oldT.typarams, newT.typarams)) { 436 if (newT.typarams.nonEmpty()) 437 copyTo(localPointer, pos); 438 else 439 if (hasModifiers(oldT.mods)) 440 copyTo(localPointer, endPos(oldT.mods)); 441 VeryPretty locBuf = new VeryPretty(context); 442 localPointer = diffParameterList(oldT.typarams, 443 newT.typarams, 444 oldT.typarams.isEmpty() || newT.typarams.isEmpty(), 445 pos, 446 locBuf 447 ); 448 printer.print(locBuf.toString()); 449 } 450 if (oldT.restype != null) { int[] restypeBounds = getBounds(oldT.restype); 452 copyTo(localPointer, restypeBounds[0]); 453 localPointer = diffTree(oldT.restype, newT.restype, restypeBounds); 454 copyTo(localPointer, localPointer = restypeBounds[1]); 455 } 456 int posHint; 457 if (oldT.typarams.isEmpty()) { 458 posHint = oldT.restype != null ? oldT.restype.getStartPosition() : oldT.getStartPosition(); 459 } else { 460 posHint = oldT.typarams.iterator().next().getStartPosition(); 461 } 462 if (!oldT.sym.isConstructor() || origClassName != null) { 463 if (nameChanged(oldT.name, newT.name)) { 464 copyTo(localPointer, oldT.pos); 465 if (oldT.sym.isConstructor() && (origClassName != null)) { 467 printer.print(newT.name); 468 localPointer = oldT.pos + origClassName.length(); 469 } 470 else { 471 printer.print(newT.name); 472 diffInfo.put(oldT.pos, "Rename method " + oldT.name); 473 localPointer = oldT.pos + oldT.name.length(); 474 } 475 } else { 476 copyTo(localPointer, localPointer = (oldT.pos + oldT.name.length())); 477 } 478 } 479 if (oldT.params.isEmpty()) { 480 int startOffset = oldT.restype != null ? oldT.restype.getStartPosition() : oldT.getStartPosition(); 484 485 TokenUtilities.moveFwdToToken(tokenSequence, startOffset, JavaTokenId.RPAREN); 486 posHint = tokenSequence.offset(); 487 } else { 488 posHint = oldT.params.iterator().next().getStartPosition(); 490 } 491 if (!listsMatch(oldT.params, newT.params)) { 492 copyTo(localPointer, posHint); 493 VeryPretty locBuf = new VeryPretty(context); 494 locBuf.setPrec(TreeInfo.noPrec); 495 localPointer = diffParameterList(oldT.params, newT.params, false, posHint, locBuf); 496 printer.print(locBuf.toString()); 497 } 498 tokenSequence.moveNext(); 500 posHint = tokenSequence.offset(); 501 if (localPointer < posHint) 502 copyTo(localPointer, localPointer = posHint); 503 if (oldT.thrown.isEmpty()) { 505 posHint = (oldT.body == null ? endPos(oldT) : oldT.body.pos) - 1; 506 tokenSequence.move(posHint); 509 tokenSequence.moveNext(); 510 if (tokenSequence.token().id() != JavaTokenId.WHITESPACE) { 511 ++posHint; 512 } 513 } else { 514 posHint = oldT.thrown.iterator().next().getStartPosition(); 515 } 516 copyTo(localPointer, localPointer = posHint); 517 PositionEstimator est = EstimatorFactory.throwz(((MethodTree) oldT).getThrows(), ((MethodTree) newT).getThrows(), workingCopy); 518 localPointer = diffList2(oldT.thrown, newT.thrown, posHint, est); 519 posHint = endPos(oldT) - 1; 520 localPointer = diffTree(oldT.body, newT.body, localPointer); 521 copyTo(localPointer, bounds[1]); 523 return bounds[1]; 524 } 525 526 protected int diffVarDef(JCVariableDecl oldT, JCVariableDecl newT, int[] bounds) { 527 int localPointer = bounds[0]; 528 if (!matchModifiers(oldT.mods, newT.mods)) { 529 if (hasModifiers(newT.mods)) { 531 localPointer = diffModifiers(oldT.mods, newT.mods, oldT, localPointer); 532 } else { 533 int oldPos = getOldPos(oldT.mods); 534 copyTo(localPointer, oldPos); 535 localPointer = getOldPos(oldT.vartype); 536 } 537 } 538 int[] vartypeBounds = getBounds(oldT.vartype); 539 copyTo(localPointer, vartypeBounds[0]); 540 localPointer = diffTree(oldT.vartype, newT.vartype, vartypeBounds); 541 if (nameChanged(oldT.name, newT.name)) { 542 copyTo(localPointer, oldT.pos); 543 printer.print(newT.name); 544 diffInfo.put(oldT.pos, "Rename variable " + oldT.name); 545 localPointer = oldT.pos + oldT.name.length(); 546 } 547 if (newT.init != null && oldT.init != null) { 548 copyTo(localPointer, localPointer = getOldPos(oldT.init)); 549 localPointer = diffTree(oldT.init, newT.init, new int[] { localPointer, endPos(oldT.init) }); 550 } else { 551 if (oldT.init != null && newT.init == null) { 552 int pos = getOldPos(oldT.init); 554 tokenSequence.move(pos); 555 moveToSrcRelevant(tokenSequence, Direction.BACKWARD); 556 moveToSrcRelevant(tokenSequence, Direction.BACKWARD); 557 tokenSequence.moveNext(); 558 int to = tokenSequence.offset(); 559 copyTo(localPointer, to); 560 localPointer = endPos(oldT.init); 561 } 562 if (oldT.init == null && newT.init != null) { 563 copyTo(localPointer, localPointer = endPos(oldT.init)); 564 printer.print(newT.init); 565 } 566 } 567 copyTo(localPointer, bounds[1]); 568 return bounds[1]; 569 } 570 571 protected int diffBlock(JCBlock oldT, JCBlock newT, int lastPrinted) { 572 int localPointer = lastPrinted; 573 if (oldT.flags != newT.flags) 574 append(Diff.flags(oldT.pos, endPos(oldT), oldT.flags, newT.flags)); 575 VeryPretty bodyPrinter = new VeryPretty(context, JavaFormatOptions.getDefault()); 576 int oldIndent = printer.indent(); 577 bodyPrinter.reset(oldIndent); 578 bodyPrinter.indent(); 579 if (oldT.stats.head != null && oldT.stats.head.pos == oldT.pos) { 581 oldT.stats = oldT.stats.tail; 582 } 583 if (newT.stats.head != null && newT.stats.head.pos == oldT.pos) { 584 newT.stats = newT.stats.tail; 585 } 586 PositionEstimator est = EstimatorFactory.members(((BlockTree) oldT).getStatements(), ((BlockTree) newT).getStatements(), workingCopy); 587 int[] pos = diffList(oldT.stats, newT.stats, oldT.pos + 1, est, Measure.DEFAULT, bodyPrinter); if (localPointer < pos[0]) { 589 copyTo(localPointer, pos[0]); 590 } 591 localPointer = pos[1]; 592 printer.print(bodyPrinter.toString()); 593 if (localPointer < endPos(oldT)) { 594 copyTo(localPointer, localPointer = endPos(oldT)); 595 } 596 printer.undent(oldIndent); 597 return localPointer; 598 } 599 600 protected int diffDoLoop(JCDoWhileLoop oldT, JCDoWhileLoop newT, int[] bounds) { 601 int localPointer = bounds[0]; 602 603 int[] bodyBounds = getBounds(oldT.body); 604 copyTo(localPointer, bodyBounds[0]); 605 localPointer = diffTree(oldT.body, newT.body, bodyBounds); 606 607 int[] condBounds = getBounds(oldT.cond); 608 copyTo(localPointer, condBounds[0]); 609 localPointer = diffTree(oldT.cond, newT.cond, condBounds); 610 copyTo(localPointer, bounds[1]); 611 612 return bounds[1]; 613 } 614 615 protected int diffWhileLoop(JCWhileLoop oldT, JCWhileLoop newT, int[] bounds) { 616 int localPointer = bounds[0]; 617 int[] condPos = getBounds(oldT.cond); 619 copyTo(localPointer, condPos[0]); 620 localPointer = diffTree(oldT.cond, newT.cond, condPos); 621 int[] bodyPos = getBounds(oldT.body); 623 copyTo(localPointer, bodyPos[0]); 624 localPointer = diffTree(oldT.body, newT.body, bodyPos); 625 626 copyTo(localPointer, bounds[1]); 627 return bounds[1]; 628 } 629 630 protected int diffForLoop(JCForLoop oldT, JCForLoop newT, int[] bounds) { 631 int localPointer = bounds[0]; 632 int initListHint = oldT.cond != null ? oldT.cond.pos - 1 : Query.NOPOS; 633 int stepListHint = oldT.cond != null ? endPos(oldT.cond) + 1 : Query.NOPOS; 634 copyTo(bounds[0], getOldPos(oldT.init.head)); 635 localPointer = diffList(oldT.init, newT.init, LineInsertionType.NONE, initListHint); 636 copyTo(localPointer, getOldPos(oldT.cond)); 637 localPointer = diffTree(oldT.cond, newT.cond, getBounds(oldT.cond)); 638 if (oldT.step.nonEmpty()) 639 copyTo(localPointer, getOldPos(oldT.step.head)); 640 else 641 copyTo(localPointer, stepListHint); 642 localPointer = diffList(oldT.step, newT.step, LineInsertionType.NONE, stepListHint); 643 copyTo(localPointer, getOldPos(oldT.body)); 644 localPointer = diffTree(oldT.body, newT.body, getBounds(oldT.body)); 645 copyTo(localPointer, bounds[1]); 646 return bounds[1]; 647 } 648 649 protected int diffForeachLoop(JCEnhancedForLoop oldT, JCEnhancedForLoop newT, int[] bounds) { 650 int localPointer = bounds[0]; 651 int[] varBounds = getBounds(oldT.var); 653 copyTo(localPointer, varBounds[0]); 654 localPointer = diffTree(oldT.var, newT.var, varBounds); 655 int[] exprBounds = getBounds(oldT.expr); 657 copyTo(localPointer, exprBounds[0]); 658 localPointer = diffTree(oldT.expr, newT.expr, exprBounds); 659 int[] bodyBounds = getBounds(oldT.body); 661 copyTo(localPointer, bodyBounds[0]); 662 localPointer = diffTree(oldT.body, newT.body, bodyBounds); 663 copyTo(localPointer, bounds[1]); 664 665 return bounds[1]; 666 } 667 668 protected int diffLabelled(JCLabeledStatement oldT, JCLabeledStatement newT, int[] bounds) { 669 int localPointer = bounds[0]; 670 if (nameChanged(oldT.label, newT.label)) { 671 copyTo(localPointer, localPointer = getOldPos(oldT)); 672 printer.print(newT.label); 673 localPointer += oldT.label.length(); 674 } 675 int[] bodyBounds = getBounds(oldT.body); 676 copyTo(localPointer, bodyBounds[0]); 677 localPointer = diffTree(oldT.body, newT.body, bodyBounds); 678 copyTo(localPointer, bounds[1]); 679 680 return bounds[1]; 681 } 682 683 protected int diffSwitch(JCSwitch oldT, JCSwitch newT, int[] bounds) { 684 int localPointer = bounds[0]; 685 686 int[] selectorBounds = getBounds(oldT.selector); 688 copyTo(localPointer, selectorBounds[0]); 689 localPointer = diffTree(oldT.selector, newT.selector, selectorBounds); 690 691 int castListHint = oldT.cases.size() > 0 ? oldT.cases.head.pos : Query.NOPOS; 692 PositionEstimator est = EstimatorFactory.members(oldT.getCases(), newT.getCases(), workingCopy); 693 copyTo(localPointer, castListHint); 694 int[] pos = diffList(oldT.cases, newT.cases, castListHint, est, Measure.DEFAULT, printer); 695 696 copyTo(pos[1], bounds[1]); 697 return bounds[1]; 698 } 699 700 protected int diffCase(JCCase oldT, JCCase newT, int[] bounds) { 701 int localPointer = bounds[0]; 702 if (oldT.pat != null) { 703 int[] patBounds = getBounds(oldT.pat); 704 copyTo(localPointer, patBounds[0]); 705 localPointer = diffTree(oldT.pat, newT.pat, patBounds); 706 } 707 int pos = oldT.stats.head.pos; 708 PositionEstimator est = EstimatorFactory.members(oldT.getStatements(), newT.getStatements(), workingCopy); 709 VeryPretty localPrinter = new VeryPretty(context, JavaFormatOptions.getDefault()); 710 int[] stmtPos = diffList(oldT.stats, newT.stats, pos, est, Measure.DEFAULT, localPrinter); 711 if (localPointer < stmtPos[0]) copyTo(localPointer, stmtPos[0]); 712 printer.print(localPrinter.toString()); 713 copyTo(stmtPos[1], bounds[1]); 714 715 return bounds[1]; 716 } 717 718 protected int diffSynchronized(JCSynchronized oldT, JCSynchronized newT, int[] bounds) { 719 int localPointer = bounds[0]; 720 int[] lockBounds = getBounds(oldT.lock); 722 copyTo(localPointer, lockBounds[0]); 723 localPointer = diffTree(oldT.lock, newT.lock, lockBounds); 724 int[] bodyBounds = getBounds(oldT.body); 726 copyTo(localPointer, bodyBounds[0]); 727 localPointer = diffTree(oldT.body, newT.body, bodyBounds); 728 copyTo(localPointer, bounds[1]); 729 730 return bounds[1]; 731 } 732 733 protected int diffTry(JCTry oldT, JCTry newT, int[] bounds) { 734 int localPointer = bounds[0]; 735 int[] bodyPos = getBounds(oldT.body); 736 copyTo(localPointer, bodyPos[0]); 737 localPointer = diffTree(oldT.body, newT.body, bodyPos); 738 int pos = oldT.catchers.head != null ? getOldPos(oldT.catchers.head) : oldT.body.endpos + 1; 739 VeryPretty locPrint = new VeryPretty(context); 740 PositionEstimator est = EstimatorFactory.members(((TryTree) oldT).getCatches(), ((TryTree) newT).getCatches(), workingCopy); 741 int[] retPos = diffList(oldT.catchers, newT.catchers, pos, est, Measure.DEFAULT, locPrint); 742 if (localPointer < retPos[0]) { 743 copyTo(localPointer, retPos[0]); 744 } 745 printer.print(locPrint.toString()); 746 localPointer = oldT.catchers.head != null ? endPos(oldT.catchers) : pos; 747 if (oldT.finalizer != null) { 748 int[] finalBounds = getBounds(oldT.finalizer); 749 copyTo(localPointer, finalBounds[0]); 750 localPointer = diffTree(oldT.finalizer, newT.finalizer, finalBounds); 751 copyTo(localPointer, bounds[1]); 752 } else if (retPos[1] < bounds[1]) { 753 copyTo(localPointer, bounds[1]); 754 } 755 return bounds[1]; 756 } 757 758 protected int diffCatch(JCCatch oldT, JCCatch newT, int[] bounds) { 759 int localPointer = bounds[0]; 760 int[] paramBounds = getBounds(oldT.param); 762 copyTo(localPointer, paramBounds[0]); 763 localPointer = diffTree(oldT.param, newT.param, paramBounds); 764 int[] bodyBounds = getBounds(oldT.body); 766 copyTo(localPointer, bodyBounds[0]); 767 localPointer = diffTree(oldT.body, newT.body, bodyBounds); 768 copyTo(localPointer, bounds[1]); 769 770 return bounds[1]; 771 } 772 773 protected int diffConditional(JCConditional oldT, JCConditional newT, int[] bounds) { 774 int localPointer = bounds[0]; 775 int[] condBounds = getBounds(oldT.cond); 777 copyTo(localPointer, condBounds[0]); 778 localPointer = diffTree(oldT.cond, newT.cond, condBounds); 779 int[] trueBounds = getBounds(oldT.truepart); 781 copyTo(localPointer, trueBounds[0]); 782 localPointer = diffTree(oldT.truepart, newT.truepart, trueBounds); 783 int[] falseBounds = getBounds(oldT.falsepart); 785 copyTo(localPointer, falseBounds[0]); 786 localPointer = diffTree(oldT.falsepart, newT.falsepart, falseBounds); 787 copyTo(localPointer, bounds[1]); 788 789 return bounds[1]; 790 } 791 792 protected int diffIf(JCIf oldT, JCIf newT, int[] bounds) { 793 int localPointer = bounds[0]; 794 if (oldT.elsepart == null && newT.elsepart != null || 795 oldT.elsepart != null && newT.elsepart == null) { 796 append(Diff.modify(oldT, getOldPos(oldT), newT)); 798 } else { 799 int[] condBounds = getBounds(oldT.cond); 800 copyTo(localPointer, condBounds[0]); 801 localPointer = diffTree(oldT.cond, newT.cond, condBounds); 802 int[] thenpartBounds = getBounds(oldT.thenpart); 803 copyTo(localPointer, thenpartBounds[0]); 804 localPointer = diffTree(oldT.thenpart, newT.thenpart, thenpartBounds); 805 if (oldT.elsepart != null) { 806 thenpartBounds = new int[] { getOldPos(oldT.elsepart), endPos(oldT.elsepart) }; 807 copyTo(localPointer, thenpartBounds[0]); 808 localPointer = diffTree(oldT.elsepart, newT.elsepart, thenpartBounds); 809 } 810 } 811 copyTo(localPointer, bounds[1]); 812 return bounds[1]; 813 } 814 815 protected int diffExec(JCExpressionStatement oldT, JCExpressionStatement newT, int[] bounds) { 816 int localPointer = getOldPos(oldT); 817 copyTo(bounds[0], localPointer); 818 localPointer = diffTree(oldT.expr, newT.expr, bounds); 819 copyTo(localPointer, bounds[1]); 820 return bounds[1]; 821 } 822 823 protected int diffBreak(JCBreak oldT, JCBreak newT, int[] bounds) { 824 int localPointer = bounds[0]; 825 if (nameChanged(oldT.label, newT.label)) { 826 copyTo(localPointer, localPointer = getOldPos(oldT)); 827 printer.print("break "); 828 printer.print(newT.label); 829 localPointer += 6 + oldT.label.length(); 830 } 831 copyTo(localPointer, bounds[1]); 835 return bounds[1]; 836 } 837 838 protected int diffContinue(JCContinue oldT, JCContinue newT, int[] bounds) { 839 int localPointer = bounds[0]; 840 if (nameChanged(oldT.label, newT.label)) { 841 copyTo(localPointer, localPointer = getOldPos(oldT)); 842 printer.print("continue "); 843 printer.print(newT.label); 844 localPointer += 9 + oldT.label.length(); 845 } 846 copyTo(localPointer, bounds[1]); 850 851 return bounds[1]; 852 } 853 854 protected int diffReturn(JCReturn oldT, JCReturn newT, int[] bounds) { 855 int[] exprBounds = getBounds(oldT.expr); 856 copyTo(bounds[0], exprBounds[0]); 857 int localPointer = diffTree(oldT.expr, newT.expr, exprBounds); 858 copyTo(localPointer, bounds[1]); 859 860 return bounds[1]; 861 } 862 863 protected int diffThrow(JCThrow oldT, JCThrow newT, int[] bounds) { 864 int localPointer = bounds[0]; 865 int[] exprBounds = getBounds(oldT.expr); 867 copyTo(localPointer, exprBounds[0]); 868 localPointer = diffTree(oldT.expr, newT.expr, exprBounds); 869 copyTo(localPointer, bounds[1]); 870 871 return bounds[1]; 872 } 873 874 protected int diffAssert(JCAssert oldT, JCAssert newT, int[] bounds) { 875 int localPointer = bounds[0]; 876 int[] condBounds = getBounds(oldT.cond); 878 copyTo(localPointer, condBounds[0]); 879 localPointer = diffTree(oldT.cond, newT.cond, condBounds); 880 int[] detailBounds = getBounds(oldT.detail); 882 copyTo(localPointer, detailBounds[0]); 883 localPointer = diffTree(oldT.detail, newT.detail, detailBounds); 884 copyTo(localPointer, bounds[1]); 885 886 return bounds[1]; 887 } 888 889 protected int diffApply(JCMethodInvocation oldT, JCMethodInvocation newT, int[] bounds) { 890 int localPointer = bounds[0]; 891 diffParameterList(oldT.typeargs, newT.typeargs, localPointer); 892 int[] methBounds = getBounds(oldT.meth); 893 localPointer = diffTree(oldT.meth, newT.meth, methBounds); 894 if (!listsMatch(oldT.args, newT.args)) { 895 if (oldT.args.nonEmpty()) { 896 copyTo(localPointer, localPointer = getOldPos(oldT.args.head)); 897 } else { 898 int rParen = TokenUtilities.moveFwdToToken(tokenSequence, getOldPos(oldT.meth), JavaTokenId.RPAREN); 899 copyTo(localPointer, localPointer = rParen); 900 } 901 VeryPretty buf = new VeryPretty(context, JavaFormatOptions.getDefault()); 902 localPointer = diffParameterList(oldT.args, newT.args, false, localPointer, buf); 903 printer.print(buf.toString()); 904 } 905 copyTo(localPointer, bounds[1]); 906 907 return bounds[1]; 908 } 909 910 boolean anonClass = false; 911 912 protected int diffNewClass(JCNewClass oldT, JCNewClass newT, int[] bounds) { 913 int localPointer = bounds[0]; 914 if (oldT.encl != null) { 915 int[] enclBounds = getBounds(oldT.encl); 916 localPointer = diffTree(oldT.encl, newT.encl, enclBounds); 917 } 918 diffParameterList(oldT.typeargs, newT.typeargs, localPointer); 919 int[] clazzBounds = getBounds(oldT.clazz); 920 copyTo(localPointer, clazzBounds[0]); 921 localPointer = diffTree(oldT.clazz, newT.clazz, clazzBounds ); 922 localPointer = diffParameterList(oldT.args, newT.args, localPointer); 923 if (oldT.def != null) { 925 copyTo(localPointer, getOldPos(oldT.def)); 926 if (newT.def != null) { 927 anonClass = true; 928 localPointer = diffTree(oldT.def, newT.def, getBounds(oldT.def)); 929 anonClass = false; 930 } else { 931 localPointer = endPos(oldT.def); 932 } 933 } 934 copyTo(localPointer, bounds[1]); 935 return bounds[1]; 936 } 937 938 protected int diffNewArray(JCNewArray oldT, JCNewArray newT, int[] bounds) { 939 int localPointer = bounds[0]; 940 if (oldT.elemtype != null) { 942 int[] elemtypeBounds = getBounds(oldT.elemtype); 943 copyTo(localPointer, elemtypeBounds[0]); 944 localPointer = diffTree(oldT.elemtype, newT.elemtype, elemtypeBounds); 945 } 946 if (oldT.elems != null && oldT.elems.head != null) { 948 copyTo(localPointer, getOldPos(oldT.elems.head)); 949 localPointer = diffParameterList(oldT.elems, newT.elems, getOldPos(oldT.elems.head)); 950 } 951 copyTo(localPointer, bounds[1]); 952 return bounds[1]; 953 } 954 955 protected int diffParens(JCParens oldT, JCParens newT, int[] bounds) { 956 int localPointer = bounds[0]; 957 copyTo(localPointer, getOldPos(oldT.expr)); 958 localPointer = diffTree(oldT.expr, newT.expr, getBounds(oldT.expr)); 959 return localPointer; 960 } 961 962 protected int diffAssign(JCAssign oldT, JCAssign newT, int[] bounds) { 963 int localPointer = bounds[0]; 964 int[] lhsBounds = getBounds(oldT.lhs); 966 copyTo(localPointer, lhsBounds[0]); 967 localPointer = diffTree(oldT.lhs, newT.lhs, lhsBounds); 968 int[] rhsBounds = getBounds(oldT.rhs); 970 copyTo(localPointer, rhsBounds[0]); 971 localPointer = diffTree(oldT.rhs, newT.rhs, rhsBounds); 972 973 copyTo(localPointer, bounds[1]); 974 return bounds[1]; 975 } 976 977 protected int diffAssignop(JCAssignOp oldT, JCAssignOp newT, int[] bounds) { 978 int localPointer = bounds[0]; 979 int[] lhsBounds = getBounds(oldT.lhs); 981 copyTo(localPointer, lhsBounds[0]); 982 localPointer = diffTree(oldT.lhs, newT.lhs, lhsBounds); 983 if (oldT.tag != newT.tag) { copyTo(localPointer, oldT.pos); 985 printer.print(getAssignementOperator(newT)); 986 localPointer = oldT.pos + getAssignementOperator(oldT).length(); 987 } 988 int[] rhsBounds = getBounds(oldT.rhs); 990 copyTo(localPointer, rhsBounds[0]); 991 localPointer = diffTree(oldT.rhs, newT.rhs, rhsBounds); 992 993 copyTo(localPointer, bounds[1]); 994 return bounds[1]; 995 } 996 997 String getAssignementOperator(Tree t) { 998 String name; 999 switch (t.getKind()) { 1000 case MULTIPLY_ASSIGNMENT: return "*="; 1001 case DIVIDE_ASSIGNMENT: return "/="; 1002 case REMAINDER_ASSIGNMENT: return "%="; 1003 case PLUS_ASSIGNMENT: return "+="; 1004 case MINUS_ASSIGNMENT: return "-="; 1005 case LEFT_SHIFT_ASSIGNMENT: return "<<="; 1006 case RIGHT_SHIFT_ASSIGNMENT: return ">>="; 1007 case AND_ASSIGNMENT: return "&="; 1008 case XOR_ASSIGNMENT: return "^="; 1009 case OR_ASSIGNMENT: return "|="; 1010 case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT: return ">>>="; 1011 default: 1012 throw new IllegalArgumentException ("Illegal kind " + t.getKind()); 1013 } 1014 } 1015 1016 protected int diffUnary(JCUnary oldT, JCUnary newT, int[] bounds) { 1017 int localPointer = bounds[0]; 1018 int[] argBounds = getBounds(oldT.arg); 1019 copyTo(localPointer, argBounds[0]); 1020 localPointer = diffTree(oldT.arg, newT.arg, argBounds); 1021 if (oldT.tag != newT.tag) { 1022 copyTo(localPointer, oldT.pos); 1023 printer.print(operatorName(newT.tag)); 1024 localPointer = oldT.pos + operatorName(oldT.tag).length(); 1025 } 1026 copyTo(localPointer, bounds[1]); 1027 return bounds[1]; 1028 } 1029 1030 protected int diffBinary(JCBinary oldT, JCBinary newT, int[] bounds) { 1031 int localPointer = bounds[0]; 1032 1033 int[] lhsBounds = getBounds(oldT.lhs); 1034 copyTo(localPointer, lhsBounds[0]); 1035 localPointer = diffTree(oldT.lhs, newT.lhs, lhsBounds); 1036 if (oldT.tag != newT.tag) { 1037 copyTo(localPointer, oldT.pos); 1038 printer.print(operatorName(newT.tag)); 1039 localPointer = oldT.pos + operatorName(oldT.tag).toString().length(); 1040 } 1041 int[] rhsBounds = getBounds(oldT.rhs); 1042 copyTo(localPointer, rhsBounds[0]); 1043 localPointer = diffTree(oldT.rhs, newT.rhs, rhsBounds); 1044 copyTo(localPointer, bounds[1]); 1045 return bounds[1]; 1046 } 1047 1048 private String operatorName(int tag) { 1049 return new Pretty(null, false).operatorName(tag); 1051 } 1052 1053 protected int diffTypeCast(JCTypeCast oldT, JCTypeCast newT, int[] bounds) { 1054 int localPointer = bounds[0]; 1055 int[] clazzBounds = getBounds(oldT.clazz); 1057 copyTo(localPointer, clazzBounds[0]); 1058 localPointer = diffTree(oldT.clazz, newT.clazz, clazzBounds); 1059 int[] exprBounds = getBounds(oldT.expr); 1061 copyTo(localPointer, exprBounds[0]); 1062 localPointer = diffTree(oldT.expr, newT.expr, exprBounds); 1063 copyTo(localPointer, bounds[1]); 1064 1065 return bounds[1]; 1066 } 1067 1068 protected int diffTypeTest(JCInstanceOf oldT, JCInstanceOf newT, int[] bounds) { 1069 int localPointer = bounds[0]; 1070 int[] exprBounds = getBounds(oldT.expr); 1072 copyTo(localPointer, exprBounds[0]); 1073 localPointer = diffTree(oldT.expr, newT.expr, exprBounds); 1074 int[] clazzBounds = getBounds(oldT.clazz); 1076 copyTo(localPointer, clazzBounds[0]); 1077 localPointer = diffTree(oldT.clazz, newT.clazz, clazzBounds); 1078 copyTo(localPointer, bounds[1]); 1079 1080 return bounds[1]; 1081 } 1082 1083 protected int diffIndexed(JCArrayAccess oldT, JCArrayAccess newT, int[] bounds) { 1084 int localPointer = bounds[0]; 1085 int[] indexedBounds = getBounds(oldT.indexed); 1087 copyTo(localPointer, indexedBounds[0]); 1088 localPointer = diffTree(oldT.indexed, newT.indexed, indexedBounds); 1089 int[] indexBounds = getBounds(oldT.index); 1091 copyTo(localPointer, indexBounds[0]); 1092 localPointer = diffTree(oldT.index, newT.index, indexBounds); 1093 copyTo(localPointer, bounds[1]); 1094 1095 return bounds[1]; 1096 } 1097 1098 protected int diffSelect(JCFieldAccess oldT, JCFieldAccess newT, int[] bounds) { 1099 int localPointer = bounds[0]; 1100 copyTo(localPointer, getOldPos(oldT.selected)); 1101 localPointer = diffTree(oldT.selected, newT.selected, getBounds(oldT.selected)); 1102 if (nameChanged(oldT.name, newT.name)) { 1103 copyTo(localPointer, endPos(oldT.selected)); 1104 printer.print("."); 1105 printer.print(newT.name); 1106 diffInfo.put(endPos(oldT.selected) + 1, "Update reference to " + oldT.name); 1107 localPointer = endPos(oldT.selected) + 1 +oldT.name.length(); 1108 } 1109 copyTo(localPointer, bounds[1]); 1110 return bounds[1]; 1111 } 1112 1113 protected int diffIdent(JCIdent oldT, JCIdent newT, int lastPrinted) { 1114 if (nameChanged(oldT.name, newT.name)) { 1115 copyTo(lastPrinted, oldT.pos); 1116 printer.print(newT.name); 1117 diffInfo.put(oldT.pos, "Update reference to " + oldT.name); 1118 return endPos(oldT); 1119 } 1120 return lastPrinted; 1121 } 1122 1123 protected int diffLiteral(JCLiteral oldT, JCLiteral newT, int[] bounds) { 1124 if (oldT.typetag != newT.typetag || !oldT.value.equals(newT.value)) { 1125 int localPointer = bounds[0]; 1126 int[] literalBounds = getBounds(oldT); 1128 copyTo(localPointer, literalBounds[0]); 1129 printer.print(newT); 1130 copyTo(literalBounds[1], bounds[1]); 1131 } else { 1132 copyTo(bounds[0], bounds[1]); 1133 } 1134 return bounds[1]; 1135 } 1136 1137 protected void diffTypeIdent(JCPrimitiveTypeTree oldT, JCPrimitiveTypeTree newT) { 1138 if (oldT.typetag != newT.typetag) 1139 append(Diff.modify(oldT, getOldPos(oldT), newT)); 1140 } 1141 1142 protected int diffTypeArray(JCArrayTypeTree oldT, JCArrayTypeTree newT, int[] bounds) { 1143 int localPointer = bounds[0]; 1144 copyTo(localPointer, bounds[0]); 1145 int[] elemtypeBounds = getBounds(oldT.elemtype); 1146 localPointer = diffTree(oldT.elemtype, newT.elemtype, elemtypeBounds); 1147 copyTo(localPointer, bounds[1]); 1148 return bounds[1]; 1149 } 1150 1151 protected int diffTypeApply(JCTypeApply oldT, JCTypeApply newT, int[] bounds) { 1152 int localPointer = bounds[0]; 1153 int[] clazzBounds = getBounds(oldT.clazz); 1154 copyTo(localPointer, clazzBounds[0]); 1155 localPointer = diffTree(oldT.clazz, newT.clazz, clazzBounds); 1156 if (!listsMatch(oldT.arguments, newT.arguments)) { 1157 int pos = oldT.arguments.nonEmpty() ? getOldPos(oldT.arguments.head) : endPos(oldT.clazz); 1158 if (newT.arguments.nonEmpty()) 1159 copyTo(localPointer, pos); 1160 VeryPretty locBuf = new VeryPretty(context); 1161 localPointer = diffParameterList( 1162 oldT.arguments, 1163 newT.arguments, 1164 oldT.arguments.isEmpty() || newT.arguments.isEmpty(), 1165 pos, 1166 locBuf 1167 ); 1168 printer.print(locBuf.toString()); 1169 } 1170 copyTo(localPointer, bounds[1]); 1171 return bounds[1]; 1172 } 1173 1174 protected int diffTypeParameter(JCTypeParameter oldT, JCTypeParameter newT, int[] bounds) { 1175 int localPointer = bounds[0]; 1176 copyTo(localPointer, getOldPos(oldT)); 1177 if (nameChanged(oldT.name, newT.name)) { 1178 printer.print(newT.name); 1179 localPointer += oldT.name.length(); 1180 } 1181 copyTo(localPointer, bounds[1]); 1184 return bounds[1]; 1185 } 1186 1187 protected int diffWildcard(JCWildcard oldT, JCWildcard newT, int[] bounds) { 1188 int localPointer = bounds[0]; 1189 if (oldT.kind != newT.kind) { 1190 copyTo(localPointer, oldT.pos); 1191 printer.print(newT.kind.toString()); 1192 localPointer = oldT.pos + oldT.kind.toString().length(); 1193 } 1194 int[] innerBounds = getBounds(oldT.inner); 1195 copyTo(localPointer, innerBounds[0]); 1196 localPointer = diffTree(oldT.inner, newT.inner, innerBounds); 1197 copyTo(localPointer, bounds[1]); 1198 1199 return bounds[1]; 1200 } 1201 1202 protected int diffTypeBoundKind(TypeBoundKind oldT, TypeBoundKind newT, int[] bounds) { 1203 int localPointer = bounds[0]; 1204 if (oldT.kind != newT.kind) { 1205 copyTo(localPointer, oldT.pos); 1206 printer.print(newT.kind.toString()); 1207 localPointer = oldT.pos + oldT.kind.toString().length(); 1208 } 1209 copyTo(localPointer, bounds[1]); 1210 return bounds[1]; 1211 } 1212 1213 protected int diffAnnotation(JCAnnotation oldT, JCAnnotation newT, int[] bounds) { 1214 int localPointer = bounds[0]; 1215 int[] annotationBounds = getBounds(oldT.annotationType); 1216 copyTo(localPointer,annotationBounds[0]); 1217 localPointer = diffTree(oldT.annotationType, newT.annotationType, annotationBounds); 1218 diffParameterList(oldT.args, newT.args, -1); 1219 copyTo(localPointer, bounds[1]); 1220 1221 return bounds[1]; 1222 } 1223 1224 protected int diffModifiers(JCModifiers oldT, JCModifiers newT, JCTree parent, int lastPrinted) { 1225 if (oldT == newT) { 1226 return lastPrinted; 1228 } 1229 int result = endPos(oldT.annotations); 1230 int oldPos = oldT.pos != Position.NOPOS ? getOldPos(oldT) : getOldPos(parent); 1231 if (listsMatch(oldT.annotations, newT.annotations)) { 1232 copyTo(lastPrinted, lastPrinted = oldPos); 1233 if (result > 0) { 1234 copyTo(lastPrinted, lastPrinted = result); 1235 } else { 1236 } 1237 } else { 1238 if (oldT.annotations.isEmpty()) copyTo(lastPrinted, oldPos); 1239 PositionEstimator est = EstimatorFactory.members(((ModifiersTree) oldT).getAnnotations(), ((ModifiersTree) newT).getAnnotations(), workingCopy); 1240 int[] res = diffList(oldT.annotations, newT.annotations, oldPos, est, Measure.DEFAULT, printer); 1241 lastPrinted = res[1]; 1242 } 1247 if (oldT.flags != newT.flags) { 1248 int endPos = endPos(oldT); 1249 if (endPos > 0) { 1250 printer.print(newT.toString().trim()); 1251 lastPrinted = endPos; 1252 } else { 1253 printer.print(newT.toString()); 1254 } 1255 } 1256 if (endPos(oldT) > 0) { 1257 copyTo(lastPrinted, endPos(oldT)); 1258 return endPos(oldT); 1259 } else { 1260 return lastPrinted; 1261 } 1262 } 1263 1264 protected void diffLetExpr(LetExpr oldT, LetExpr newT) { 1265 diffList(oldT.defs, newT.defs, LineInsertionType.NONE, Query.NOPOS); 1266 diffTree(oldT.expr, newT.expr, getBounds(oldT.expr)); 1267 } 1268 1269 protected void diffErroneous(JCErroneous oldT, JCErroneous newT) { 1270 diffList(oldT.errs, newT.errs, LineInsertionType.BEFORE, Query.NOPOS); 1271 } 1272 1273 protected boolean listContains(List<? extends JCTree> list, JCTree tree) { 1274 for (JCTree t : list) 1275 if (treesMatch(t, tree)) 1276 return true; 1277 return false; 1278 } 1279 1280 protected boolean treesMatch(JCTree t1, JCTree t2) { 1281 return treesMatch(t1, t2, true); 1282 } 1283 1284 public boolean treesMatch(JCTree t1, JCTree t2, boolean deepMatch) { 1285 if (t1 == t2) 1286 return true; 1287 if (t1 == null || t2 == null) 1288 return false; 1289 if (t1.tag != t2.tag) 1290 return false; 1291 if (!deepMatch) 1292 return true; 1293 1294 switch (t1.tag) { 1296 case JCTree.TOPLEVEL: 1297 return ((JCCompilationUnit)t1).sourcefile.equals(((JCCompilationUnit)t2).sourcefile); 1298 case JCTree.IMPORT: 1299 return matchImport((JCImport)t1, (JCImport)t2); 1300 case JCTree.CLASSDEF: 1301 return ((JCClassDecl)t1).sym == ((JCClassDecl)t2).sym; 1302 case JCTree.METHODDEF: 1303 return ((JCMethodDecl)t1).sym == ((JCMethodDecl)t2).sym; 1304 case JCTree.VARDEF: 1305 return ((JCVariableDecl)t1).sym == ((JCVariableDecl)t2).sym; 1306 case JCTree.SKIP: 1307 return true; 1308 case JCTree.BLOCK: 1309 return matchBlock((JCBlock)t1, (JCBlock)t2); 1310 case JCTree.DOLOOP: 1311 return matchDoLoop((JCDoWhileLoop)t1, (JCDoWhileLoop)t2); 1312 case JCTree.WHILELOOP: 1313 return matchWhileLoop((JCWhileLoop)t1, (JCWhileLoop)t2); 1314 case JCTree.FORLOOP: 1315 return matchForLoop((JCForLoop)t1, (JCForLoop)t2); 1316 case JCTree.FOREACHLOOP: 1317 return matchForeachLoop((JCEnhancedForLoop)t1, (JCEnhancedForLoop)t2); 1318 case JCTree.LABELLED: 1319 return matchLabelled((JCLabeledStatement)t1, (JCLabeledStatement)t2); 1320 case JCTree.SWITCH: 1321 return matchSwitch((JCSwitch)t1, (JCSwitch)t2); 1322 case JCTree.CASE: 1323 return matchCase((JCCase)t1, (JCCase)t2); 1324 case JCTree.SYNCHRONIZED: 1325 return matchSynchronized((JCSynchronized)t1, (JCSynchronized)t2); 1326 case JCTree.TRY: 1327 return matchTry((JCTry)t1, (JCTry)t2); 1328 case JCTree.CATCH: 1329 return matchCatch((JCCatch)t1, (JCCatch)t2); 1330 case JCTree.CONDEXPR: 1331 return matchConditional((JCConditional)t1, (JCConditional)t2); 1332 case JCTree.IF: 1333 return matchIf((JCIf)t1, (JCIf)t2); 1334 case JCTree.EXEC: 1335 return treesMatch(((JCExpressionStatement)t1).expr, ((JCExpressionStatement)t2).expr); 1336 case JCTree.BREAK: 1337 return matchBreak((JCBreak)t1, (JCBreak)t2); 1338 case JCTree.CONTINUE: 1339 return matchContinue((JCContinue)t1, (JCContinue)t2); 1340 case JCTree.RETURN: 1341 return treesMatch(((JCReturn)t1).expr, ((JCReturn)t2).expr); 1342 case JCTree.THROW: 1343 return treesMatch(((JCThrow)t1).expr, ((JCThrow)t2).expr); 1344 case JCTree.ASSERT: 1345 return matchAssert((JCAssert)t1, (JCAssert)t2); 1346 case JCTree.APPLY: 1347 return matchApply((JCMethodInvocation)t1, (JCMethodInvocation)t2); 1348 case JCTree.NEWCLASS: 1349 if (((JCNewClass)t2).def != null) ((JCNewClass)t2).def.sym = null; 1353 return matchNewClass((JCNewClass)t1, (JCNewClass)t2); 1354 case JCTree.NEWARRAY: 1355 return matchNewArray((JCNewArray)t1, (JCNewArray)t2); 1356 case JCTree.PARENS: 1357 return treesMatch(((JCParens)t1).expr, ((JCParens)t2).expr); 1358 case JCTree.ASSIGN: 1359 return matchAssign((JCAssign)t1, (JCAssign)t2); 1360 case JCTree.TYPECAST: 1361 return matchTypeCast((JCTypeCast)t1, (JCTypeCast)t2); 1362 case JCTree.TYPETEST: 1363 return matchTypeTest((JCInstanceOf)t1, (JCInstanceOf)t2); 1364 case JCTree.INDEXED: 1365 return matchIndexed((JCArrayAccess)t1, (JCArrayAccess)t2); 1366 case JCTree.SELECT: 1367 return matchSelect((JCFieldAccess) t1, (JCFieldAccess) t2); 1368 case JCTree.IDENT: 1369 return ((JCIdent)t1).sym == ((JCIdent)t2).sym; 1370 case JCTree.LITERAL: 1371 return matchLiteral((JCLiteral)t1, (JCLiteral)t2); 1372 case JCTree.TYPEIDENT: 1373 return ((JCPrimitiveTypeTree)t1).typetag == ((JCPrimitiveTypeTree)t2).typetag; 1374 case JCTree.TYPEARRAY: 1375 return treesMatch(((JCArrayTypeTree)t1).elemtype, ((JCArrayTypeTree)t2).elemtype); 1376 case JCTree.TYPEAPPLY: 1377 return matchTypeApply((JCTypeApply)t1, (JCTypeApply)t2); 1378 case JCTree.TYPEPARAMETER: 1379 return matchTypeParameter((JCTypeParameter)t1, (JCTypeParameter)t2); 1380 case JCTree.WILDCARD: 1381 return matchWildcard((JCWildcard)t1, (JCWildcard)t2); 1382 case JCTree.TYPEBOUNDKIND: 1383 return ((TypeBoundKind)t1).kind == ((TypeBoundKind)t2).kind; 1384 case JCTree.ANNOTATION: 1385 return matchAnnotation((JCAnnotation)t1, (JCAnnotation)t2); 1386 case JCTree.LETEXPR: 1387 return matchLetExpr((LetExpr)t1, (LetExpr)t2); 1388 case JCTree.POS: 1389 case JCTree.NEG: 1390 case JCTree.NOT: 1391 case JCTree.COMPL: 1392 case JCTree.PREINC: 1393 case JCTree.PREDEC: 1394 case JCTree.POSTINC: 1395 case JCTree.POSTDEC: 1396 case JCTree.NULLCHK: 1397 return matchUnary((JCUnary)t1, (JCUnary)t2); 1398 case JCTree.OR: 1399 case JCTree.AND: 1400 case JCTree.BITOR: 1401 case JCTree.BITXOR: 1402 case JCTree.BITAND: 1403 case JCTree.EQ: 1404 case JCTree.NE: 1405 case JCTree.LT: 1406 case JCTree.GT: 1407 case JCTree.LE: 1408 case JCTree.GE: 1409 case JCTree.SL: 1410 case JCTree.SR: 1411 case JCTree.USR: 1412 case JCTree.PLUS: 1413 case JCTree.MINUS: 1414 case JCTree.MUL: 1415 case JCTree.DIV: 1416 case JCTree.MOD: 1417 return matchBinary((JCBinary)t1, (JCBinary)t2); 1418 case JCTree.BITOR_ASG: 1419 case JCTree.BITXOR_ASG: 1420 case JCTree.BITAND_ASG: 1421 case JCTree.SL_ASG: 1422 case JCTree.SR_ASG: 1423 case JCTree.USR_ASG: 1424 case JCTree.PLUS_ASG: 1425 case JCTree.MINUS_ASG: 1426 case JCTree.MUL_ASG: 1427 case JCTree.DIV_ASG: 1428 case JCTree.MOD_ASG: 1429 return matchAssignop((JCAssignOp)t1, (JCAssignOp)t2); 1430 default: 1431 String msg = ((com.sun.source.tree.Tree)t1).getKind().toString() + 1432 " " + t1.getClass().getName(); 1433 throw new AssertionError (msg); 1434 } 1435 } 1436 1437 protected boolean nameChanged(Name oldName, Name newName) { 1438 if (oldName == newName) 1439 return false; 1440 byte[] arr1 = oldName.toUtf(); 1441 byte[] arr2 = newName.toUtf(); 1442 int len = arr1.length; 1443 if (len != arr2.length) 1444 return true; 1445 for (int i = 0; i < len; i++) 1446 if (arr1[i] != arr2[i]) 1447 return true; 1448 return false; 1449 } 1450 1451 1455 protected int diffList(List<? extends JCTree> oldList, 1456 List<? extends JCTree> newList, 1457 LineInsertionType newLine, int insertHint) { 1458 int lastPrinted = insertHint; 1459 if (oldList == newList) 1460 return insertHint; 1461 assert oldList != null && newList != null; 1462 int lastOldPos = insertHint; 1463 Iterator <? extends JCTree> oldIter = oldList.iterator(); 1464 Iterator <? extends JCTree> newIter = newList.iterator(); 1465 JCTree oldT = safeNext(oldIter); 1466 JCTree newT = safeNext(newIter); 1467 while (oldT != null && newT != null) { 1468 if (oldTopLevel != null) { 1469 int endPos = model.getEndPos(oldT, oldTopLevel); 1470 1471 if (endPos != Position.NOPOS) 1472 lastOldPos = endPos; 1473 } 1474 if (treesMatch(oldT, newT, false)) { 1475 lastPrinted = diffTree(oldT, newT, new int[] { getOldPos(oldT), endPos(oldT) }); 1476 oldT = safeNext(oldIter); 1477 newT = safeNext(newIter); 1478 } 1479 else if (!listContains(newList, oldT) && !listContains(oldList, newT)) { 1480 append(Diff.modify(oldT, getOldPos(oldT), newT)); 1481 oldT = safeNext(oldIter); 1482 newT = safeNext(newIter); 1483 } 1484 else if (!listContains(newList, oldT)) { 1485 if (!isHidden(oldT, oldParent)) 1486 append(Diff.delete(oldT, getOldPos(oldT))); 1487 oldT = safeNext(oldIter); 1488 } 1489 else { 1490 if (!isHidden(newT, newParent)) 1491 append(Diff.insert(newT, getOldPos(oldT), newLine, null)); 1492 newT = safeNext(newIter); 1493 } 1494 } 1495 while (oldT != null) { 1496 if (!isHidden(oldT, oldParent)) 1497 append(Diff.delete(oldT, getOldPos(oldT))); 1498 if (oldTopLevel != null) 1499 lastOldPos = model.getEndPos(oldT, oldTopLevel); 1500 oldT = safeNext(oldIter); 1501 } 1502 while (newT != null) { 1503 if (!isHidden(newT, newParent)) 1504 append(Diff.insert(newT, lastOldPos, newLine, null)); 1505 newT = safeNext(newIter); 1506 } 1507 return lastPrinted; 1508 } 1509 1510 private JCTree safeNext(Iterator <? extends JCTree> iter) { 1511 return iter.hasNext() ? iter.next() : null; 1512 } 1513 1514 protected int diffParameterList(List<? extends JCTree> oldList, List<? extends JCTree> newList, int localPointer) { 1517 if (oldList == newList) 1518 return localPointer; 1519 assert oldList != null && newList != null; 1520 int lastOldPos = Query.NOPOS; 1521 Iterator <? extends JCTree> oldIter = oldList.iterator(); 1522 Iterator <? extends JCTree> newIter = newList.iterator(); 1523 while (oldIter.hasNext() && newIter.hasNext()) { 1524 JCTree oldT = oldIter.next(); 1525 copyTo(localPointer, localPointer = getOldPos(oldT)); 1526 localPointer = diffTree(oldT, newIter.next(), new int[] { localPointer, endPos(oldT) }); 1527 if (oldTopLevel != null) 1528 lastOldPos = model.getEndPos(oldT, oldTopLevel); 1529 } 1530 while (oldIter.hasNext()) { 1531 JCTree oldT = oldIter.next(); 1532 append(Diff.delete(oldT, getOldPos(oldT))); 1533 } 1534 while (newIter.hasNext()) { 1535 append(Diff.insert(newIter.next(), lastOldPos, LineInsertionType.BEFORE)); 1536 } 1537 return localPointer; 1538 } 1539 1540 1543 protected int diffList2( 1544 List<? extends JCTree> oldList, List<? extends JCTree> newList, 1545 int initialPos, PositionEstimator estimator) 1546 { 1547 if (oldList == newList) 1548 return initialPos; 1549 assert oldList != null && newList != null; 1550 int lastOldPos = initialPos; 1551 1552 ListMatcher<JCTree> matcher = ListMatcher.<JCTree>instance( 1553 (List<JCTree>) oldList, 1554 (List<JCTree>) newList 1555 ); 1556 if (!matcher.match()) { 1557 return initialPos; 1558 } 1559 Iterator <? extends JCTree> oldIter = oldList.iterator(); 1560 ResultItem<JCTree>[] result = matcher.getTransformedResult(); 1561 Separator s = matcher.separatorInstance(); 1562 s.compute(); 1563 int[][] matrix = estimator.getMatrix(); 1564 int testPos = initialPos; 1565 int i = 0; 1566 for (int j = 0; j < result.length; j++) { 1567 JCTree oldT; 1568 ResultItem<JCTree> item = result[j]; 1569 switch (item.operation) { 1570 case MODIFY: { 1571 tokenSequence.moveIndex(matrix[i][4]); 1573 if (tokenSequence.moveNext()) { 1574 testPos = tokenSequence.offset(); 1575 if (JavaTokenId.COMMA == tokenSequence.token().id()) 1576 testPos += JavaTokenId.COMMA.fixedText().length(); 1577 } 1578 oldT = oldIter.next(); ++i; 1579 copyTo(lastOldPos, getOldPos(oldT)); 1580 if (treesMatch(oldT, item.element, false)) { 1581 lastOldPos = diffTree(oldT, item.element, getBounds(oldT)); 1582 } else { 1583 printer.print(item.element); 1584 lastOldPos = endPos(oldT); 1585 } 1586 break; 1587 } 1588 case INSERT: { 1589 String prec = s.head(j) ? estimator.head() : s.prev(j) ? estimator.sep() : null; 1590 String tail = s.next(j) ? estimator.sep() : null; 1591 if (estimator.getIndentString() != null && !estimator.getIndentString().equals(" ")) { 1592 prec += estimator.getIndentString(); 1593 } 1594 copyTo(lastOldPos, testPos); 1595 printer.print(prec); 1596 printer.print(item.element); 1597 printer.print(tail); 1598 break; 1600 } 1601 case DELETE: { 1602 1607 int delta = 0; 1611 if (i == 0 && matrix[i+1][2] != -1 && matrix[i+1][2] == matrix[i+1][3]) { 1612 ++delta; 1613 } 1614 int startOffset = toOff(s.head(j) || s.prev(j) ? matrix[i][1] : matrix[i][2+delta]); 1615 int endOffset = toOff(s.tail(j) || s.next(j) ? matrix[i+1][2] : matrix[i][4]); 1616 assert startOffset != -1 && endOffset != -1 : "Invalid offset!"; 1617 tokenSequence.moveIndex(matrix[i][4]); 1620 if (tokenSequence.moveNext()) { 1621 testPos = tokenSequence.offset(); 1622 if (JavaTokenId.COMMA == tokenSequence.token().id()) 1623 testPos += JavaTokenId.COMMA.fixedText().length(); 1624 } 1625 if (i == 0 && !newList.isEmpty()) { 1626 lastOldPos = endOffset; 1627 } else { 1628 lastOldPos = endPos(item.element); 1629 } 1630 oldT = oldIter.next(); ++i; 1631 break; 1632 } 1633 case NOCHANGE: { 1634 tokenSequence.moveIndex(matrix[i][4]); 1635 if (tokenSequence.moveNext()) { 1636 testPos = tokenSequence.offset(); 1637 if (JavaTokenId.COMMA == tokenSequence.token().id()) 1638 testPos += JavaTokenId.COMMA.fixedText().length(); 1639 } 1640 oldT = oldIter.next(); ++i; 1641 copyTo(lastOldPos, lastOldPos = endPos(oldT)); 1642 break; 1643 } 1644 } 1645 } 1646 return lastOldPos; 1647 } 1648 1649 private int toOff(int tokenIndex) { 1650 if (tokenIndex == -1) { 1651 return -1; 1652 } 1653 tokenSequence.moveIndex(tokenIndex); 1654 tokenSequence.moveNext(); 1655 return tokenSequence.offset(); 1656 } 1657 1658 1663 private int diffParameterList( 1664 List<? extends JCTree> oldList, 1665 List<? extends JCTree> newList, 1666 boolean printParen, 1667 int pos, 1668 VeryPretty buf) 1669 { 1670 if (oldList == newList || (oldList.isEmpty() && newList.isEmpty())) 1671 return pos; 1673 assert oldList != null && newList != null; 1674 1675 if (newList.isEmpty()) { 1676 int endPos = endPos(oldList); 1677 if (printParen) { 1678 tokenSequence.move(endPos); 1679 TokenUtilities.moveFwdToToken(tokenSequence, endPos, JavaTokenId.GT); 1680 tokenSequence.moveNext(); 1681 endPos = tokenSequence.offset(); 1682 if (!PositionEstimator.nonRelevant.contains(tokenSequence.token())) 1683 buf.print(" "); } 1685 return endPos; 1686 } 1687 ListMatcher<JCTree> matcher = ListMatcher.<JCTree>instance( 1688 (List<JCTree>) oldList, 1689 (List<JCTree>) newList 1690 ); 1691 if (!matcher.match()) { 1692 return pos; 1694 } 1695 ResultItem<JCTree>[] result = matcher.getResult(); 1696 if (printParen && oldList.isEmpty()) { 1697 buf.print(JavaTokenId.LT.fixedText()); 1698 } 1699 JCTree lastDeleted = null; 1700 for (int index = 0, j = 0; j < result.length; j++) { 1701 ResultItem<JCTree> item = result[j]; 1702 switch (item.operation) { 1703 case INSERT: 1705 if (index++ > 0) buf.print(","); 1706 if (lastDeleted != null && treesMatch(lastDeleted, item.element, false)) { 1707 VeryPretty mainPrint = this.printer; 1708 this.printer = buf; 1709 diffTree(lastDeleted, item.element, getBounds(lastDeleted)); 1710 this.printer = mainPrint; 1711 } else { 1712 buf.print(item.element); 1713 } 1714 lastDeleted = null; 1715 break; 1716 case DELETE: 1717 lastDeleted = item.element; 1718 break; 1719 case NOCHANGE: 1721 if (index++ > 0) buf.print(","); 1722 int[] bounds = getBounds(item.element); 1723 tokenSequence.move(bounds[0]); 1724 TokenUtilities.movePrevious(tokenSequence, bounds[0]); 1725 tokenSequence.moveNext(); 1726 int start = tokenSequence.offset(); 1727 TokenUtilities.moveNext(tokenSequence, bounds[1]); 1728 int end = tokenSequence.offset(); 1729 copyTo(start, end, buf); 1730 lastDeleted = null; 1731 break; 1732 default: 1733 break; 1734 } 1735 } 1736 if (printParen && oldList.isEmpty()) { 1737 buf.print(JavaTokenId.GT.fixedText()); 1738 buf.print(" "); } 1740 return oldList.isEmpty() ? pos : endPos(oldList); 1741 } 1742 1743 1747 private int[] diffList( 1748 List<? extends JCTree> oldList, 1749 List<? extends JCTree> newList, 1750 int initialPos, 1751 PositionEstimator estimator, 1752 Measure measure, 1753 VeryPretty printer) 1754 { 1755 int[] ret = new int[] { -1, -1 }; 1756 if (oldList == newList) { 1757 return ret; 1758 } 1759 assert oldList != null && newList != null; 1760 1761 ListMatcher<JCTree> matcher = ListMatcher.instance( 1762 oldList, 1763 newList, 1764 measure 1765 ); 1766 if (!matcher.match()) { 1767 return ret; 1768 } 1769 JCTree lastdel = null; ResultItem<JCTree>[] result = matcher.getResult(); 1771 int posHint = initialPos; 1772 int i = 0; 1773 for (int j = 0; j < result.length; j++) { 1774 ResultItem<JCTree> item = result[j]; 1775 switch (item.operation) { 1776 case MODIFY: { 1777 assert true : "Modify is no longer operated!"; 1778 break; 1779 } 1780 case INSERT: { 1781 int pos = estimator.getInsertPos(i); 1782 String head = "", tail = ""; 1785 if (pos < 0 && oldList.isEmpty() && i == 0) { 1786 pos = initialPos; 1787 StringBuilder aHead = new StringBuilder (), aTail = new StringBuilder (); 1788 pos = estimator.prepare(initialPos, aHead, aTail); 1789 if (j+1 == result.length) { 1790 tail = aTail.toString(); 1791 } 1792 head = aHead.toString(); 1793 posHint = pos; 1794 if (ret[0] < 0) ret[0] = posHint; 1795 if (ret[1] < 0) ret[1] = posHint; 1796 } else { 1797 if (ret[0] < 0) ret[0] = posHint; 1798 if (ret[1] < 0) ret[1] = posHint; 1799 } 1800 int oldPos = item.element.getKind() != Kind.VARIABLE ? getOldPos(item.element) : item.element.pos; 1801 boolean found = false; 1802 if (oldPos > 0) { 1803 for (JCTree oldT : oldList) { 1804 int oldNodePos = oldT.getKind() != Kind.VARIABLE ? getOldPos(oldT) : oldT.pos; 1805 if (oldPos == oldNodePos) { 1806 found = true; 1807 VeryPretty oldPrinter = this.printer; 1808 int old = oldPrinter.indent(); 1809 this.printer = new VeryPretty(context, JavaFormatOptions.getDefault()); 1810 this.printer.reset(old); 1811 int index = oldList.indexOf(oldT); 1812 int[] poss = estimator.getPositions(index); 1813 diffTree(oldT, item.element, poss); 1814 printer.print(this.printer.toString()); 1815 this.printer = oldPrinter; 1818 this.printer.undent(old); 1819 break; 1820 } 1821 } 1822 } 1823 if (!found) { 1824 if (lastdel != null && treesMatch(item.element, lastdel, false)) { 1825 VeryPretty oldPrinter = this.printer; 1826 int old = oldPrinter.indent(); 1827 this.printer = new VeryPretty(context, JavaFormatOptions.getDefault()); 1828 this.printer.reset(old); 1829 int index = oldList.indexOf(lastdel); 1830 int[] poss = estimator.getPositions(index); 1831 diffTree(lastdel, item.element, poss); 1832 printer.print(this.printer.toString()); 1833 this.printer = oldPrinter; 1834 this.printer.undent(old); 1835 break; 1836 } 1837 if (j == 0 && !oldList.isEmpty()) { 1838 posHint = estimator.getPositions(0)[0]; 1839 } 1840 printer.print(head); 1841 int old = printer.indent(); 1842 VeryPretty inPrint = new VeryPretty(context, JavaFormatOptions.getDefault()); 1843 inPrint.reset(old); 1844 inPrint.enclClassName = printer.enclClassName; 1845 inPrint.print(item.element); 1847 inPrint.newline(); 1848 printer.print(inPrint.toString()); 1849 printer.undent(old); 1850 } 1855 break; 1856 } 1857 case DELETE: { 1858 int[] pos = estimator.getPositions(i); 1859 lastdel = oldList.get(i); 1860 if (ret[0] < 0) { 1861 ret[0] = pos[0]; 1862 } 1863 ++i; 1864 ret[1] = pos[1]; 1865 posHint = pos[1]; 1866 break; 1867 } 1868 case NOCHANGE: { 1869 int[] pos = estimator.getPositions(i); 1870 if (ret[0] < 0) { 1871 ret[0] = pos[0]; 1872 } 1873 copyTo(pos[0], pos[1], printer); 1874 ret[1] = pos[1]; 1875 ++i; 1876 break; 1877 } 1878 } 1879 } 1880 if (!oldList.isEmpty()) { 1881 Iterator <? extends JCTree> it = oldList.iterator(); 1882 for (i = 0; it.hasNext(); i++, it.next()) ; 1883 int[] pos = estimator.getPositions(i); 1884 ret[1] = pos[1]; 1885 } 1886 return ret; 1887 } 1888 1889 private List filterHidden(List<JCTree> list) { 1890 List<JCTree> result = new ArrayList <JCTree>(); for (JCTree tree : list) { 1892 if (Kind.METHOD == tree.getKind()) { 1893 if ((((JCMethodDecl)tree).mods.flags & Flags.GENERATEDCONSTR) != 0) 1896 continue; 1897 } 1898 result.add(tree); 1899 } 1900 return result; 1901 } 1902 1903 1904 1908 private int diffListImports( 1909 List<? extends JCTree> oldList, 1910 List<? extends JCTree> newList, 1911 int localPointer, 1912 PositionEstimator estimator, 1913 Measure measure, 1914 VeryPretty printer) 1915 { 1916 if (oldList == newList) { 1917 return localPointer; 1918 } 1919 assert oldList != null && newList != null; 1920 1921 ListMatcher<JCTree> matcher = ListMatcher.instance( 1922 oldList, 1923 newList, 1924 measure 1925 ); 1926 if (!matcher.match()) { 1927 return localPointer; 1928 } 1929 JCTree lastdel = null; ResultItem<JCTree>[] result = matcher.getResult(); 1931 1932 if (oldList.isEmpty() && !newList.isEmpty()) { 1934 StringBuilder aHead = new StringBuilder (), aTail = new StringBuilder (); 1937 int pos = estimator.prepare(0, aHead, aTail); 1938 copyTo(localPointer, pos, printer); 1939 printer.print(aHead.toString()); 1940 for (JCTree item : newList) { 1941 if (BEFORE == estimator.lineInsertType()) printer.newline(); 1942 printer.printExpr(item); 1943 if (AFTER == estimator.lineInsertType()) printer.newline(); 1944 } 1945 return pos; 1950 } 1951 1952 if (newList.isEmpty() && !oldList.isEmpty()) { 1954 int[] removalBounds = estimator.sectionRemovalBounds(null); 1955 copyTo(localPointer, removalBounds[0]); 1956 return removalBounds[1]; 1957 } 1958 int i = 0; 1959 copyTo(localPointer, localPointer = estimator.getInsertPos(0), printer); 1961 for (int j = 0; j < result.length; j++) { 1963 ResultItem<JCTree> item = result[j]; 1964 switch (item.operation) { 1965 case INSERT: { 1966 int pos = estimator.getInsertPos(i); 1967 String head = "", tail = ""; 1970 if (pos < 0 && oldList.isEmpty() && i == 0) { 1971 pos = localPointer; 1972 StringBuilder aHead = new StringBuilder (), aTail = new StringBuilder (); 1973 pos = estimator.prepare(localPointer, aHead, aTail); 1974 if (j+1 == result.length) { 1975 tail = aTail.toString(); 1976 } 1977 head = aHead.toString(); 1978 } 1979 int oldPos = item.element.getKind() != Kind.VARIABLE ? getOldPos(item.element) : item.element.pos; 1980 boolean found = false; 1981 if (oldPos > 0) { 1982 for (JCTree oldT : oldList) { 1983 int oldNodePos = oldT.getKind() != Kind.VARIABLE ? getOldPos(oldT) : oldT.pos; 1984 if (oldPos == oldNodePos) { 1985 found = true; 1986 VeryPretty oldPrinter = this.printer; 1987 int old = oldPrinter.indent(); 1988 this.printer = new VeryPretty(context, JavaFormatOptions.getDefault()); 1989 this.printer.reset(old); 1990 int index = oldList.indexOf(oldT); 1991 int[] poss = estimator.getPositions(index); 1992 diffTree(oldT, item.element, poss); 1993 printer.print(this.printer.toString()); 1994 this.printer = oldPrinter; 1995 this.printer.undent(old); 1996 break; 1997 } 1998 } 1999 } 2000 if (!found) { 2001 if (lastdel != null && treesMatch(item.element, lastdel, false)) { 2002 VeryPretty oldPrinter = this.printer; 2003 int old = oldPrinter.indent(); 2004 this.printer = new VeryPretty(context, JavaFormatOptions.getDefault()); 2005 this.printer.reset(old); 2006 int index = oldList.indexOf(lastdel); 2007 int[] poss = estimator.getPositions(index); 2008 diffTree(lastdel, item.element, poss); 2009 printer.print(this.printer.toString()); 2010 this.printer = oldPrinter; 2011 this.printer.undent(old); 2012 break; 2013 } 2014 printer.print(head); 2015 int old = printer.indent(); 2016 printer.enclClassName = printer.enclClassName; 2017 if (LineInsertionType.BEFORE == estimator.lineInsertType()) printer.newline(); 2018 printer.print(item.element); 2019 if (LineInsertionType.AFTER == estimator.lineInsertType()) printer.newline(); 2020 printer.undent(old); 2021 } 2022 break; 2023 } 2024 case DELETE: { 2025 int[] pos = estimator.getPositions(i); 2026 if (localPointer < pos[0]) { 2027 copyTo(localPointer, pos[0], printer); 2028 } 2029 lastdel = oldList.get(i); 2030 ++i; 2031 localPointer = pos[1]; 2032 break; 2033 } 2034 case NOCHANGE: { 2035 int[] pos = estimator.getPositions(i); 2036 if (pos[0] > localPointer && i != 0) { 2037 copyTo(localPointer, pos[0], printer); 2039 } 2040 copyTo(pos[0], localPointer = pos[1], printer); 2041 lastdel = null; 2042 ++i; 2043 break; 2044 } 2045 } 2046 } 2047 return localPointer; 2048 } 2049 2050 private boolean isHidden(JCTree t, JCTree parent) { 2051 if (parent == null) 2052 return false; 2053 if (t.pos == Query.NOPOS) 2056 return true; 2057 return model.isSynthetic(t); 2058 } 2059 2060 protected void diffPrecedingComments(JCTree oldT, JCTree newT) { 2061 CommentSet cs = comments.getComments(newT); 2062 if (!cs.hasChanges()) 2063 return; 2064 List<Comment> oldComments = comments.getComments(oldT).getPrecedingComments(); 2065 List<Comment> newComments = cs.getPrecedingComments(); 2066 diffCommentLists(oldT, newT, oldComments, newComments, false); 2067 } 2068 2069 protected void diffTrailingComments(JCTree oldT, JCTree newT) { 2070 CommentSet cs = comments.getComments(newT); 2071 if (!cs.hasChanges()) 2072 return; 2073 List<Comment> oldComments = comments.getComments(oldT).getTrailingComments(); 2074 List<Comment> newComments = cs.getTrailingComments(); 2075 diffCommentLists(oldT, newT, oldComments, newComments, true); 2076 } 2077 2078 private void diffCommentLists(JCTree oldT, JCTree newT, List<Comment>oldList, 2079 List<Comment>newList, boolean trailing) { 2080 int lastPos = getOldPos(oldT); 2081 Iterator <Comment> oldIter = oldList.iterator(); 2082 Iterator <Comment> newIter = newList.iterator(); 2083 Comment oldC = safeNext(oldIter); 2084 Comment newC = safeNext(newIter); 2085 while (oldC != null && newC != null) { 2086 lastPos = oldC.pos(); 2087 if (commentsMatch(oldC, newC)) { 2088 oldC = safeNext(oldIter); 2089 newC = safeNext(newIter); 2090 } 2091 else if (!listContains(newList, oldC)) { 2092 if (!listContains(oldList, newC)) { 2093 append(Diff.modify(oldT, newT, oldC, newC)); 2094 oldC = safeNext(oldIter); 2095 newC = safeNext(newIter); 2096 } else { 2097 append(Diff.delete(oldT, newT, oldC)); 2098 oldC = safeNext(oldIter); 2099 } 2100 } 2101 else { 2102 append(Diff.insert(lastPos, LineInsertionType.BEFORE, oldT, newT, newC, trailing)); 2103 newC = safeNext(newIter); 2104 } 2105 } 2106 while (oldC != null) { 2107 append(Diff.delete(oldT, newT, oldC)); 2108 oldC = safeNext(oldIter); 2109 } 2110 while (newC != null) { 2111 append(Diff.insert(lastPos, LineInsertionType.BEFORE, oldT, newT, newC, trailing)); 2112 lastPos += newC.endPos() - newC.pos(); 2113 newC = safeNext(oldIter); 2114 } 2115 } 2116 2117 private Comment safeNext(Iterator <Comment> iter) { 2118 return iter.hasNext() ? iter.next() : null; 2119 } 2120 2121 private boolean commentsMatch(Comment oldC, Comment newC) { 2122 if (oldC == null && newC == null) 2123 return true; 2124 if (oldC == null || newC == null) 2125 return false; 2126 return oldC.equals(newC); 2127 } 2128 2129 private boolean listContains(List<Comment>list, Comment comment) { 2130 for (Comment c : list) 2131 if (c.equals(comment)) 2132 return true; 2133 return false; 2134 } 2135 2136 private static JCTree leftMostTree(JCTree tree) { 2138 switch (tree.tag) { 2139 case(JCTree.APPLY): 2140 return leftMostTree(((JCMethodInvocation)tree).meth); 2141 case(JCTree.ASSIGN): 2142 return leftMostTree(((JCAssign)tree).lhs); 2143 case(JCTree.BITOR_ASG): case(JCTree.BITXOR_ASG): case(JCTree.BITAND_ASG): 2144 case(JCTree.SL_ASG): case(JCTree.SR_ASG): case(JCTree.USR_ASG): 2145 case(JCTree.PLUS_ASG): case(JCTree.MINUS_ASG): case(JCTree.MUL_ASG): 2146 case(JCTree.DIV_ASG): case(JCTree.MOD_ASG): 2147 return leftMostTree(((JCAssignOp)tree).lhs); 2148 case(JCTree.OR): case(JCTree.AND): case(JCTree.BITOR): 2149 case(JCTree.BITXOR): case(JCTree.BITAND): case(JCTree.EQ): 2150 case(JCTree.NE): case(JCTree.LT): case(JCTree.GT): 2151 case(JCTree.LE): case(JCTree.GE): case(JCTree.SL): 2152 case(JCTree.SR): case(JCTree.USR): case(JCTree.PLUS): 2153 case(JCTree.MINUS): case(JCTree.MUL): case(JCTree.DIV): 2154 case(JCTree.MOD): 2155 return leftMostTree(((JCBinary)tree).lhs); 2156 case(JCTree.CLASSDEF): { 2157 JCClassDecl node = (JCClassDecl)tree; 2158 if (node.mods.pos != Position.NOPOS) 2159 return node.mods; 2160 break; 2161 } 2162 case(JCTree.CONDEXPR): 2163 return leftMostTree(((JCConditional)tree).cond); 2164 case(JCTree.EXEC): 2165 return leftMostTree(((JCExpressionStatement)tree).expr); 2166 case(JCTree.INDEXED): 2167 return leftMostTree(((JCArrayAccess)tree).indexed); 2168 case(JCTree.METHODDEF): { 2169 JCMethodDecl node = (JCMethodDecl)tree; 2170 if (node.mods.pos != Position.NOPOS) 2171 return node.mods; 2172 if (node.restype != null) return leftMostTree(node.restype); 2174 return node; 2175 } 2176 case(JCTree.SELECT): 2177 return leftMostTree(((JCFieldAccess)tree).selected); 2178 case(JCTree.TYPEAPPLY): 2179 return leftMostTree(((JCTypeApply)tree).clazz); 2180 case(JCTree.TYPEARRAY): 2181 return leftMostTree(((JCArrayTypeTree)tree).elemtype); 2182 case(JCTree.TYPETEST): 2183 return leftMostTree(((JCInstanceOf)tree).expr); 2184 case(JCTree.POSTINC): 2185 case(JCTree.POSTDEC): 2186 return leftMostTree(((JCUnary)tree).arg); 2187 case(JCTree.VARDEF): { 2188 JCVariableDecl node = (JCVariableDecl)tree; 2189 if (node.mods.pos != Position.NOPOS) 2190 return node.mods; 2191 return leftMostTree(node.vartype); 2192 } 2193 case(JCTree.TOPLEVEL): { 2194 JCCompilationUnit node = (JCCompilationUnit)tree; 2195 assert node.defs.size() > 0; 2196 return node.pid != null ? node.pid : node.defs.head; 2197 } 2198 } 2199 return tree; 2200 } 2201 2202 private int getOldPos(JCTree oldT) { 2203 return getOldPos(oldT, model, undo); 2204 } 2205 2206 static int getOldPos(JCTree oldT, ASTModel model, UndoList undo) { 2207 int oldPos = model.getStartPos(oldT); 2208 if (oldPos == Query.NOPOS) { 2209 JCTree t = (JCTree)undo.getOld(leftMostTree(oldT)); 2211 if (t != null && t != oldT) 2212 oldPos = getOldPos(t, model, undo); 2214 } 2215 if (oldPos == Query.NOPOS) 2216 oldPos = oldT.pos == Query.NOPOS ? leftMostTree(oldT).pos : oldT.pos; 2217 return oldPos; 2218 } 2219 2220 2230 protected int diffTree(JCTree oldT, JCTree newT, int[] elementBounds) { 2231 if (oldT == null && newT != null) 2232 throw new IllegalArgumentException ("Null is not allowed in parameters."); 2233 2234 if (oldT == newT) 2235 return elementBounds[0]; 2236 diffPrecedingComments(oldT, newT); 2237 int retVal = -1; 2238 int oldPos = getOldPos(oldT); 2239 2240 if (oldT.tag != newT.tag) { 2241 if (((compAssign.contains(oldT.getKind()) && compAssign.contains(newT.getKind())) == false) && 2242 ((binaries.contains(oldT.getKind()) && binaries.contains(newT.getKind())) == false) && 2243 ((unaries.contains(oldT.getKind()) && unaries.contains(newT.getKind())) == false)) { 2244 printer.print(newT); 2246 return endPos(oldT); 2247 } 2248 } 2249 2250 switch (oldT.tag) { 2251 case JCTree.TOPLEVEL: 2252 diffTopLevel((JCCompilationUnit)oldT, (JCCompilationUnit)newT); 2253 break; 2254 case JCTree.IMPORT: 2255 retVal = diffImport((JCImport)oldT, (JCImport)newT, elementBounds); 2256 break; 2257 case JCTree.CLASSDEF: 2258 retVal = diffClassDef((JCClassDecl)oldT, (JCClassDecl)newT, elementBounds); 2259 break; 2260 case JCTree.METHODDEF: 2261 retVal = diffMethodDef((JCMethodDecl)oldT, (JCMethodDecl)newT, elementBounds); 2262 break; 2263 case JCTree.VARDEF: 2264 return diffVarDef((JCVariableDecl)oldT, (JCVariableDecl)newT, elementBounds); 2265 case JCTree.SKIP: 2266 break; 2267 case JCTree.BLOCK: 2268 retVal = diffBlock((JCBlock)oldT, (JCBlock)newT, elementBounds[0]); 2269 break; 2270 case JCTree.DOLOOP: 2271 retVal = diffDoLoop((JCDoWhileLoop)oldT, (JCDoWhileLoop)newT, elementBounds); 2272 break; 2273 case JCTree.WHILELOOP: 2274 retVal = diffWhileLoop((JCWhileLoop)oldT, (JCWhileLoop)newT, elementBounds); 2275 break; 2276 case JCTree.FORLOOP: 2277 retVal = diffForLoop((JCForLoop)oldT, (JCForLoop)newT, elementBounds); 2278 break; 2279 case JCTree.FOREACHLOOP: 2280 retVal = diffForeachLoop((JCEnhancedForLoop)oldT, (JCEnhancedForLoop)newT, elementBounds); 2281 break; 2282 case JCTree.LABELLED: 2283 retVal = diffLabelled((JCLabeledStatement)oldT, (JCLabeledStatement)newT, elementBounds); 2284 break; 2285 case JCTree.SWITCH: 2286 retVal = diffSwitch((JCSwitch)oldT, (JCSwitch)newT, elementBounds); 2287 break; 2288 case JCTree.CASE: 2289 retVal = diffCase((JCCase)oldT, (JCCase)newT, elementBounds); 2290 break; 2291 case JCTree.SYNCHRONIZED: 2292 retVal = diffSynchronized((JCSynchronized)oldT, (JCSynchronized)newT, elementBounds); 2293 break; 2294 case JCTree.TRY: 2295 retVal = diffTry((JCTry)oldT, (JCTry)newT, elementBounds); 2296 break; 2297 case JCTree.CATCH: 2298 retVal = diffCatch((JCCatch)oldT, (JCCatch)newT, elementBounds); 2299 break; 2300 case JCTree.CONDEXPR: 2301 retVal = diffConditional((JCConditional)oldT, (JCConditional)newT, elementBounds); 2302 break; 2303 case JCTree.IF: 2304 retVal = diffIf((JCIf)oldT, (JCIf)newT, elementBounds); 2305 break; 2306 case JCTree.EXEC: 2307 retVal = diffExec((JCExpressionStatement)oldT, (JCExpressionStatement)newT, elementBounds); 2308 break; 2309 case JCTree.BREAK: 2310 retVal = diffBreak((JCBreak)oldT, (JCBreak)newT, elementBounds); 2311 break; 2312 case JCTree.CONTINUE: 2313 retVal = diffContinue((JCContinue)oldT, (JCContinue)newT, elementBounds); 2314 break; 2315 case JCTree.RETURN: 2316 retVal = diffReturn((JCReturn)oldT, (JCReturn)newT, elementBounds); 2317 break; 2318 case JCTree.THROW: 2319 retVal = diffThrow((JCThrow)oldT, (JCThrow)newT,elementBounds); 2320 break; 2321 case JCTree.ASSERT: 2322 retVal = diffAssert((JCAssert)oldT, (JCAssert)newT, elementBounds); 2323 break; 2324 case JCTree.APPLY: 2325 retVal = diffApply((JCMethodInvocation)oldT, (JCMethodInvocation)newT, elementBounds); 2326 break; 2327 case JCTree.NEWCLASS: 2328 retVal = diffNewClass((JCNewClass)oldT, (JCNewClass)newT, elementBounds); 2329 break; 2330 case JCTree.NEWARRAY: 2331 retVal = diffNewArray((JCNewArray)oldT, (JCNewArray)newT, elementBounds); 2332 break; 2333 case JCTree.PARENS: 2334 retVal = diffParens((JCParens)oldT, (JCParens)newT, elementBounds); 2335 break; 2336 case JCTree.ASSIGN: 2337 retVal = diffAssign((JCAssign)oldT, (JCAssign)newT, elementBounds); 2338 break; 2339 case JCTree.TYPECAST: 2340 retVal = diffTypeCast((JCTypeCast)oldT, (JCTypeCast)newT, elementBounds); 2341 break; 2342 case JCTree.TYPETEST: 2343 retVal = diffTypeTest((JCInstanceOf)oldT, (JCInstanceOf)newT, elementBounds); 2344 break; 2345 case JCTree.INDEXED: 2346 retVal = diffIndexed((JCArrayAccess)oldT, (JCArrayAccess)newT, elementBounds); 2347 break; 2348 case JCTree.SELECT: 2349 retVal = diffSelect((JCFieldAccess)oldT, (JCFieldAccess)newT, elementBounds); 2350 break; 2351 case JCTree.IDENT: 2352 retVal = diffIdent((JCIdent)oldT, (JCIdent)newT, elementBounds[0]); 2353 break; 2354 case JCTree.LITERAL: 2355 retVal = diffLiteral((JCLiteral)oldT, (JCLiteral)newT, elementBounds); 2356 break; 2357 case JCTree.TYPEIDENT: 2358 diffTypeIdent((JCPrimitiveTypeTree)oldT, (JCPrimitiveTypeTree)newT); 2359 break; 2360 case JCTree.TYPEARRAY: 2361 retVal = diffTypeArray((JCArrayTypeTree)oldT, (JCArrayTypeTree)newT, elementBounds); 2362 break; 2363 case JCTree.TYPEAPPLY: 2364 retVal = diffTypeApply((JCTypeApply)oldT, (JCTypeApply)newT, elementBounds); 2365 break; 2366 case JCTree.TYPEPARAMETER: 2367 retVal = diffTypeParameter((JCTypeParameter)oldT, (JCTypeParameter)newT, elementBounds); 2368 break; 2369 case JCTree.WILDCARD: 2370 retVal = diffWildcard((JCWildcard)oldT, (JCWildcard)newT, elementBounds); 2371 break; 2372 case JCTree.TYPEBOUNDKIND: 2373 retVal = diffTypeBoundKind((TypeBoundKind)oldT, (TypeBoundKind)newT, elementBounds); 2374 break; 2375 case JCTree.ANNOTATION: 2376 retVal = diffAnnotation((JCAnnotation)oldT, (JCAnnotation)newT, elementBounds); 2377 break; 2378 case JCTree.LETEXPR: 2379 diffLetExpr((LetExpr)oldT, (LetExpr)newT); 2380 break; 2381 case JCTree.POS: 2382 case JCTree.NEG: 2383 case JCTree.NOT: 2384 case JCTree.COMPL: 2385 case JCTree.PREINC: 2386 case JCTree.PREDEC: 2387 case JCTree.POSTINC: 2388 case JCTree.POSTDEC: 2389 case JCTree.NULLCHK: 2390 retVal = diffUnary((JCUnary)oldT, (JCUnary)newT, elementBounds); 2391 break; 2392 case JCTree.OR: 2393 case JCTree.AND: 2394 case JCTree.BITOR: 2395 case JCTree.BITXOR: 2396 case JCTree.BITAND: 2397 case JCTree.EQ: 2398 case JCTree.NE: 2399 case JCTree.LT: 2400 case JCTree.GT: 2401 case JCTree.LE: 2402 case JCTree.GE: 2403 case JCTree.SL: 2404 case JCTree.SR: 2405 case JCTree.USR: 2406 case JCTree.PLUS: 2407 case JCTree.MINUS: 2408 case JCTree.MUL: 2409 case JCTree.DIV: 2410 case JCTree.MOD: 2411 retVal = diffBinary((JCBinary)oldT, (JCBinary)newT, elementBounds); 2412 break; 2413 case JCTree.BITOR_ASG: 2414 case JCTree.BITXOR_ASG: 2415 case JCTree.BITAND_ASG: 2416 case JCTree.SL_ASG: 2417 case JCTree.SR_ASG: 2418 case JCTree.USR_ASG: 2419 case JCTree.PLUS_ASG: 2420 case JCTree.MINUS_ASG: 2421 case JCTree.MUL_ASG: 2422 case JCTree.DIV_ASG: 2423 case JCTree.MOD_ASG: 2424 retVal = diffAssignop((JCAssignOp)oldT, (JCAssignOp)newT, elementBounds); 2425 break; 2426 case JCTree.ERRONEOUS: 2427 diffErroneous((JCErroneous)oldT, (JCErroneous)newT); 2428 break; 2429 default: 2430 String msg = "Diff not implemented: " + 2431 ((com.sun.source.tree.Tree)oldT).getKind().toString() + 2432 " " + oldT.getClass().getName(); 2433 throw new AssertionError (msg); 2434 } 2435 diffTrailingComments(oldT, newT); 2436 return retVal; 2437 } 2438 2439 2445 private static final EnumSet <Kind> compAssign = EnumSet.of( 2446 Kind.MULTIPLY_ASSIGNMENT, 2447 Kind.DIVIDE_ASSIGNMENT, 2448 Kind.REMAINDER_ASSIGNMENT, 2449 Kind.PLUS_ASSIGNMENT, 2450 Kind.MINUS_ASSIGNMENT, 2451 Kind.LEFT_SHIFT_ASSIGNMENT, 2452 Kind.RIGHT_SHIFT_ASSIGNMENT, 2453 Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT, 2454 Kind.AND_ASSIGNMENT, 2455 Kind.XOR_ASSIGNMENT, 2456 Kind.OR_ASSIGNMENT 2457 ); 2458 2459 private static final EnumSet <Kind> binaries = EnumSet.of( 2460 Kind.MULTIPLY, 2461 Kind.DIVIDE, 2462 Kind.REMAINDER, 2463 Kind.PLUS, 2464 Kind.MINUS, 2465 Kind.LEFT_SHIFT, 2466 Kind.RIGHT_SHIFT, 2467 Kind.UNSIGNED_RIGHT_SHIFT, 2468 Kind.LESS_THAN, 2469 Kind.GREATER_THAN, 2470 Kind.LESS_THAN_EQUAL, 2471 Kind.GREATER_THAN_EQUAL, 2472 Kind.EQUAL_TO, 2473 Kind.NOT_EQUAL_TO, 2474 Kind.AND, 2475 Kind.XOR, 2476 Kind.OR, 2477 Kind.CONDITIONAL_AND, 2478 Kind.CONDITIONAL_OR 2479 ); 2480 2481 private static final EnumSet <Kind> unaries = EnumSet.of( 2482 Kind.POSTFIX_INCREMENT, 2483 Kind.POSTFIX_DECREMENT, 2484 Kind.PREFIX_INCREMENT, 2485 Kind.PREFIX_DECREMENT, 2486 Kind.UNARY_PLUS, 2487 Kind.UNARY_MINUS, 2488 Kind.BITWISE_COMPLEMENT, 2489 Kind.LOGICAL_COMPLEMENT 2490 ); 2491 2492 private int diffTree(JCTree oldT, JCTree newT, int lastPrinted) { 2493 return diffTree(oldT, newT, new int[] { lastPrinted, -1 }); 2494 } 2495 2496 protected boolean listsMatch(List<? extends JCTree> oldList, List<? extends JCTree> newList) { 2497 if (oldList == newList) 2498 return true; 2499 int n = oldList.size(); 2500 if (newList.size() != n) 2501 return false; 2502 for (int i = 0; i < n; i++) 2503 if (!treesMatch(oldList.get(i), newList.get(i))) 2504 return false; 2505 return true; 2506 } 2507 2508 private boolean matchImport(JCImport t1, JCImport t2) { 2509 return t1.staticImport == t2.staticImport && treesMatch(t1.qualid, t2.qualid); 2510 } 2511 2512 private boolean matchBlock(JCBlock t1, JCBlock t2) { 2513 return t1.flags == t2.flags && listsMatch(t1.stats, t2.stats); 2514 } 2515 2516 private boolean matchDoLoop(JCDoWhileLoop t1, JCDoWhileLoop t2) { 2517 return treesMatch(t1.cond, t2.cond) && treesMatch(t1.body, t2.body); 2518 } 2519 2520 private boolean matchWhileLoop(JCWhileLoop t1, JCWhileLoop t2) { 2521 return treesMatch(t1.cond, t2.cond) && treesMatch(t1.body, t2.body); 2522 } 2523 2524 private boolean matchForLoop(JCForLoop t1, JCForLoop t2) { 2525 return listsMatch(t1.init, t2.init) && treesMatch(t1.cond, t2.cond) && 2526 listsMatch(t1.step, t2.step) && treesMatch(t1.body, t2.body); 2527 } 2528 2529 private boolean matchForeachLoop(JCEnhancedForLoop t1, JCEnhancedForLoop t2) { 2530 return treesMatch(t1.var, t2.var) && treesMatch(t1.expr, t2.expr) && 2531 treesMatch(t1.body, t2.body); 2532 } 2533 2534 private boolean matchLabelled(JCLabeledStatement t1, JCLabeledStatement t2) { 2535 return t1.label == t2.label && treesMatch(t1.body, t2.body); 2536 } 2537 2538 private boolean matchSwitch(JCSwitch t1, JCSwitch t2) { 2539 return treesMatch(t1.selector, t2.selector) && listsMatch(t1.cases, t2.cases); 2540 } 2541 2542 private boolean matchCase(JCCase t1, JCCase t2) { 2543 return treesMatch(t1.pat, t2.pat) && listsMatch(t1.stats, t2.stats); 2544 } 2545 2546 private boolean matchSynchronized(JCSynchronized t1, JCSynchronized t2) { 2547 return treesMatch(t1.lock, t2.lock) && treesMatch(t1.body, t2.body); 2548 } 2549 2550 private boolean matchTry(JCTry t1, JCTry t2) { 2551 return treesMatch(t1.finalizer, t2.finalizer) && 2552 listsMatch(t1.catchers, t2.catchers) && 2553 treesMatch(t1.body, t2.body); 2554 } 2555 2556 private boolean matchCatch(JCCatch t1, JCCatch t2) { 2557 return treesMatch(t1.param, t2.param) && treesMatch(t1.body, t2.body); 2558 } 2559 2560 private boolean matchConditional(JCConditional t1, JCConditional t2) { 2561 return treesMatch(t1.cond, t2.cond) && treesMatch(t1.truepart, t2.truepart) && 2562 treesMatch(t1.falsepart, t2.falsepart); 2563 } 2564 2565 private boolean matchIf(JCIf t1, JCIf t2) { 2566 return treesMatch(t1.cond, t2.cond) && treesMatch(t1.thenpart, t2.thenpart) && 2567 treesMatch(t1.elsepart, t2.elsepart); 2568 } 2569 2570 private boolean matchBreak(JCBreak t1, JCBreak t2) { 2571 return t1.label == t2.label && treesMatch(t1.target, t2.target); 2572 } 2573 2574 private boolean matchContinue(JCContinue t1, JCContinue t2) { 2575 return t1.label == t2.label && treesMatch(t1.target, t2.target); 2576 } 2577 2578 private boolean matchAssert(JCAssert t1, JCAssert t2) { 2579 return treesMatch(t1.cond, t2.cond) && treesMatch(t1.detail, t2.detail); 2580 } 2581 2582 private boolean matchApply(JCMethodInvocation t1, JCMethodInvocation t2) { 2583 return t1.varargsElement == t2.varargsElement && 2584 listsMatch(t1.typeargs, t2.typeargs) && 2585 treesMatch(t1.meth, t2.meth) && 2586 listsMatch(t1.args, t2.args); 2587 } 2588 2589 private boolean matchNewClass(JCNewClass t1, JCNewClass t2) { 2590 return t1.constructor == t2.constructor && 2591 listsMatch(t1.typeargs, t2.typeargs) && 2592 listsMatch(t1.args, t2.args) && 2593 (t1.varargsElement == t2.varargsElement) && 2594 treesMatch(t1.def, t2.def); 2595 } 2596 2597 private boolean matchNewArray(JCNewArray t1, JCNewArray t2) { 2598 return treesMatch(t1.elemtype, t2.elemtype) && 2599 listsMatch(t1.dims, t2.dims) && listsMatch(t1.elems, t2.elems); 2600 } 2601 2602 private boolean matchAssign(JCAssign t1, JCAssign t2) { 2603 return treesMatch(t1.lhs, t2.lhs) && treesMatch(t1.rhs, t2.rhs); 2604 } 2605 2606 private boolean matchAssignop(JCAssignOp t1, JCAssignOp t2) { 2607 return t1.operator == t2.operator && 2608 treesMatch(t1.lhs, t2.lhs) && treesMatch(t1.rhs, t2.rhs); 2609 } 2610 2611 private boolean matchUnary(JCUnary t1, JCUnary t2) { 2612 return t1.operator == t2.operator && treesMatch(t1.arg, t2.arg); 2613 } 2614 2615 private boolean matchBinary(JCBinary t1, JCBinary t2) { 2616 return t1.operator == t2.operator && 2617 treesMatch(t1.lhs, t2.lhs) && treesMatch(t1.rhs, t2.rhs); 2618 } 2619 2620 private boolean matchTypeCast(JCTypeCast t1, JCTypeCast t2) { 2621 return treesMatch(t1.clazz, t2.clazz) && treesMatch(t1.expr, t2.expr); 2622 } 2623 2624 private boolean matchTypeTest(JCInstanceOf t1, JCInstanceOf t2) { 2625 return treesMatch(t1.clazz, t2.clazz) && treesMatch(t1.expr, t2.expr); 2626 } 2627 2628 private boolean matchIndexed(JCArrayAccess t1, JCArrayAccess t2) { 2629 return treesMatch(t1.indexed, t2.indexed) && treesMatch(t1.index, t2.index); 2630 } 2631 2632 private boolean matchSelect(JCFieldAccess t1, JCFieldAccess t2) { 2633 return treesMatch(t1.selected, t2.selected) && t1.sym == t2.sym; 2634 } 2635 2636 private boolean matchLiteral(JCLiteral t1, JCLiteral t2) { 2637 return t1.typetag == t2.typetag && t1.value == t2.value; 2638 } 2639 2640 private boolean matchTypeApply(JCTypeApply t1, JCTypeApply t2) { 2641 return treesMatch(t1.clazz, t2.clazz) && 2642 listsMatch(t1.arguments, t2.arguments); 2643 } 2644 2645 private boolean matchTypeParameter(JCTypeParameter t1, JCTypeParameter t2) { 2646 return t1.name == t2.name && listsMatch(t1.bounds, t2.bounds); 2647 } 2648 2649 private boolean matchWildcard(JCWildcard t1, JCWildcard t2) { 2650 return t1.kind == t2.kind && treesMatch(t1.inner, t2.inner); 2651 } 2652 2653 private boolean matchAnnotation(JCAnnotation t1, JCAnnotation t2) { 2654 return treesMatch(t1.annotationType, t2.annotationType) && 2655 listsMatch(t1.args, t2.args); 2656 } 2657 2658 private boolean matchModifiers(JCModifiers t1, JCModifiers t2) { 2659 return t1.flags == t2.flags && listsMatch(t1.annotations, t2.annotations); 2660 } 2661 2662 private boolean matchLetExpr(LetExpr t1, LetExpr t2) { 2663 return listsMatch(t1.defs, t2.defs) && treesMatch(t1.expr, t2.expr); 2664 } 2665 2666 private int[] getBounds(JCTree tree) { 2667 return new int[] { getOldPos(tree), endPos(tree) }; 2668 } 2669 2670 private void copyTo(int from, int to) { 2671 copyTo(from, to, printer); 2672 } 2673 2674 private void copyTo(int from, int to, VeryPretty loc) { 2675 if (from == to) { 2676 return; 2677 } else if (from > to || from < 0 || to < 0) { 2678 throw new IllegalArgumentException ("Illegal values: from = " + from + "; to = " + to + "."); 2679 } 2680 loc.print(origText.substring(from, to)); 2681 } 2682 2683 private static class Line { 2684 Line(String data, int start, int end) { 2685 this.start = start; 2686 this.end = end; 2687 this.data = data; 2688 } 2689 2690 @Override 2691 public String toString() { 2692 return data.toString(); 2693 } 2694 2695 @Override 2696 public boolean equals(Object o) { 2697 if (o instanceof Line) { 2698 return data.equals(((Line) o).data); 2699 } else { 2700 return false; 2701 } 2702 } 2703 2704 @Override 2705 public int hashCode() { 2706 return data.hashCode(); 2707 } 2708 2709 String data; 2710 int end; 2711 int start; 2712 } 2713 2714 private List<Line> getLines(String text) { 2715 char[] chars = text.toCharArray(); 2716 List<Line> list = new ArrayList <Line>(); 2717 int pointer = 0; 2718 for (int i = 0; i < chars.length; i++) { 2719 if (chars[i] == '\n') { 2720 list.add(new Line(new String (chars, pointer, i-pointer+1), pointer, i+1)); 2721 pointer = i+1; 2722 } 2723 } 2724 if (pointer < chars.length) { 2725 list.add(new Line(new String (chars, pointer, chars.length-pointer), pointer, chars.length)); 2726 } 2727 return list; 2728 } 2729 2730 public List<Diff> makeListMatch(String text1, String text2) { 2731 List<Line> list1 = getLines(text1); 2732 List<Line> list2 = getLines(text2); 2733 Line[] lines1 = list1.toArray(new Line[list1.size()]); 2734 Line[] lines2 = list2.toArray(new Line[list2.size()]); 2735 2736 List diffs = new ComputeDiff(lines1, lines2).diff(); 2737 for (Object o : diffs) { 2738 Difference diff = (Difference)o; int delStart = diff.getDeletedStart(); 2740 int delEnd = diff.getDeletedEnd(); 2741 int addStart = diff.getAddedStart(); 2742 int addEnd = diff.getAddedEnd(); 2743 2744 String from = toString(delStart, delEnd); 2745 String to = toString(addStart, addEnd); 2746 char type = delEnd != Difference.NONE && addEnd != Difference.NONE ? 'c' : (delEnd == Difference.NONE ? 'a' : 'd'); 2747 2748 if (logDiffs) { 2749 System.out.println(from + type + to); 2750 if (delEnd != Difference.NONE) { 2751 printLines(delStart, delEnd, "<", lines1); 2752 if (addEnd != Difference.NONE) { 2753 System.out.println("---"); 2754 } 2755 } 2756 if (addEnd != Difference.NONE) { 2757 printLines(addStart, addEnd, ">", lines2); 2758 } 2759 } 2760 if (type == 'a') { 2762 StringBuilder builder = new StringBuilder (); 2763 for (int i = addStart; i <= addEnd; i++) { 2764 builder.append(lines2[i].data); 2765 } 2766 append(Diff.insert(delEnd == Difference.NONE ? lines1[delStart].start : lines1[delEnd].end, 2767 builder.toString(), null, "", LineInsertionType.NONE)); 2768 } 2769 2770 else if (type == 'd') { 2772 append(Diff.delete(lines1[delStart].start, lines1[delEnd].end)); 2773 } 2774 2775 else { StringBuilder builder = new StringBuilder (); 2778 for (int i = delStart; i <= delEnd; i++) { 2779 builder.append(lines1[i].data); 2780 } 2781 String match1 = builder.toString(); 2782 builder = new StringBuilder (); 2783 for (int i = addStart; i <= addEnd; i++) { 2784 builder.append(lines2[i].data); 2785 } 2786 String match2 = builder.toString(); 2787 makeTokenListMatch(match1, match2, lines1[delStart].start); 2788 } 2789 } 2790 return null; 2791 } 2792 2793 2796 private static boolean logDiffs = false; 2797 2798 public List<Diff> makeTokenListMatch(String text1, String text2, int currentPos) { 2799 if (logDiffs) System.out.println("----- token match for change -"); 2800 TokenSequence<JavaTokenId> seq1 = TokenHierarchy.create(text1, JavaTokenId.language()).tokenSequence(JavaTokenId.language()); 2801 TokenSequence<JavaTokenId> seq2 = TokenHierarchy.create(text2, JavaTokenId.language()).tokenSequence(JavaTokenId.language()); 2802 List<Line> list1 = new ArrayList <Line>(); 2803 List<Line> list2 = new ArrayList <Line>(); 2804 while (seq1.moveNext()) { 2805 String data = seq1.token().text().toString(); 2806 list1.add(new Line(data, seq1.offset(), seq1.offset() + data.length())); 2807 } 2808 while (seq2.moveNext()) { 2809 String data = seq2.token().text().toString(); 2810 list2.add(new Line(data, seq2.offset(), seq2.offset() + data.length())); 2811 } 2812 Line[] lines1 = list1.toArray(new Line[list1.size()]); 2813 Line[] lines2 = list2.toArray(new Line[list2.size()]); 2814 2815 List diffs = new ComputeDiff(lines1, lines2).diff(); 2816 for (Object o : diffs) { 2817 Difference diff = (Difference)o; int delStart = diff.getDeletedStart(); 2819 int delEnd = diff.getDeletedEnd(); 2820 int addStart = diff.getAddedStart(); 2821 int addEnd = diff.getAddedEnd(); 2822 2823 String from = toString(delStart, delEnd); 2824 String to = toString(addStart, addEnd); 2825 char type = delEnd != Difference.NONE && addEnd != Difference.NONE ? 'c' : (delEnd == Difference.NONE ? 'a' : 'd'); 2826 2827 if (logDiffs) { 2828 System.out.println(from + type + to); 2829 if (delEnd != Difference.NONE) { 2830 printTokens(delStart, delEnd, "<", lines1); 2831 if (addEnd != Difference.NONE) { 2832 System.out.println("---"); 2833 } 2834 } 2835 if (addEnd != Difference.NONE) { 2836 printTokens(addStart, addEnd, ">", lines2); 2837 } 2838 } 2839 if (type == 'a') { 2841 StringBuilder builder = new StringBuilder (); 2842 for (int i = addStart; i <= addEnd; i++) { 2843 builder.append(lines2[i].data); 2844 } 2845 append(Diff.insert(currentPos + (delEnd == Difference.NONE ? lines1[delStart].start : lines1[delEnd].end), 2846 builder.toString(), null, "", LineInsertionType.NONE)); 2847 } 2848 2849 else if (type == 'd') { 2851 append(Diff.delete(currentPos + lines1[delStart].start, currentPos + lines1[delEnd].end)); 2852 } 2853 2854 else { StringBuilder builder = new StringBuilder (); 2857 2860 append(Diff.delete(currentPos + lines1[delStart].start, currentPos + lines1[delEnd].end)); 2861 for (int i = addStart; i <= addEnd; i++) { 2863 builder.append(lines2[i].data); 2864 } 2865 append(Diff.insert(currentPos + (delEnd == Difference.NONE ? lines1[delStart].start : lines1[delEnd].end), 2866 builder.toString(), null, "", LineInsertionType.NONE)); 2867 } 2868 2869 } 2870 if (logDiffs) System.out.println("----- end token match -"); 2871 return null; 2872 } 2873 2874 protected String toString(int start, int end) { 2875 2877 StringBuffer buf = new StringBuffer (); 2878 2879 buf.append(end == Difference.NONE ? start : (1 + start)); 2881 2882 if (end != Difference.NONE && start != end) { 2883 buf.append(",").append(1 + end); 2884 } 2885 return buf.toString(); 2886 } 2887 2888 private void printLines(int start, int end, String ind, Line[] lines) { 2889 for (int lnum = start; lnum <= end; ++lnum) { 2890 System.out.print(ind + " " + lines[lnum]); 2891 } 2892 } 2893 2894 private void printTokens(int start, int end, String ind, Line[] lines) { 2895 for (int lnum = start; lnum <= end; ++lnum) { 2896 System.out.println(ind + " '" + lines[lnum] + "'"); 2897 } 2898 } 2899 2900} 2901 | Popular Tags |