1 /*
   2  * Copyright (c) 2018, Google LLC. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.comp;
  27 
  28 import com.sun.tools.javac.code.Symbol;
  29 import com.sun.tools.javac.tree.JCTree;
  30 import com.sun.tools.javac.tree.JCTree.JCAnnotatedType;
  31 import com.sun.tools.javac.tree.JCTree.JCAnnotation;
  32 import com.sun.tools.javac.tree.JCTree.JCArrayAccess;
  33 import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree;
  34 import com.sun.tools.javac.tree.JCTree.JCAssert;
  35 import com.sun.tools.javac.tree.JCTree.JCAssign;
  36 import com.sun.tools.javac.tree.JCTree.JCAssignOp;
  37 import com.sun.tools.javac.tree.JCTree.JCBinary;
  38 import com.sun.tools.javac.tree.JCTree.JCBlock;
  39 import com.sun.tools.javac.tree.JCTree.JCBreak;
  40 import com.sun.tools.javac.tree.JCTree.JCCase;
  41 import com.sun.tools.javac.tree.JCTree.JCCatch;
  42 import com.sun.tools.javac.tree.JCTree.JCClassDecl;
  43 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
  44 import com.sun.tools.javac.tree.JCTree.JCConditional;
  45 import com.sun.tools.javac.tree.JCTree.JCContinue;
  46 import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
  47 import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop;
  48 import com.sun.tools.javac.tree.JCTree.JCErroneous;
  49 import com.sun.tools.javac.tree.JCTree.JCExports;
  50 import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
  51 import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
  52 import com.sun.tools.javac.tree.JCTree.JCForLoop;
  53 import com.sun.tools.javac.tree.JCTree.JCIdent;
  54 import com.sun.tools.javac.tree.JCTree.JCIf;
  55 import com.sun.tools.javac.tree.JCTree.JCImport;
  56 import com.sun.tools.javac.tree.JCTree.JCInstanceOf;
  57 import com.sun.tools.javac.tree.JCTree.JCLabeledStatement;
  58 import com.sun.tools.javac.tree.JCTree.JCLambda;
  59 import com.sun.tools.javac.tree.JCTree.JCLiteral;
  60 import com.sun.tools.javac.tree.JCTree.JCMemberReference;
  61 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
  62 import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
  63 import com.sun.tools.javac.tree.JCTree.JCModifiers;
  64 import com.sun.tools.javac.tree.JCTree.JCModuleDecl;
  65 import com.sun.tools.javac.tree.JCTree.JCNewArray;
  66 import com.sun.tools.javac.tree.JCTree.JCNewClass;
  67 import com.sun.tools.javac.tree.JCTree.JCOpens;
  68 import com.sun.tools.javac.tree.JCTree.JCPackageDecl;
  69 import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree;
  70 import com.sun.tools.javac.tree.JCTree.JCProvides;
  71 import com.sun.tools.javac.tree.JCTree.JCRequires;
  72 import com.sun.tools.javac.tree.JCTree.JCReturn;
  73 import com.sun.tools.javac.tree.JCTree.JCSwitch;
  74 import com.sun.tools.javac.tree.JCTree.JCSwitchExpression;
  75 import com.sun.tools.javac.tree.JCTree.JCSynchronized;
  76 import com.sun.tools.javac.tree.JCTree.JCThrow;
  77 import com.sun.tools.javac.tree.JCTree.JCTry;
  78 import com.sun.tools.javac.tree.JCTree.JCTypeApply;
  79 import com.sun.tools.javac.tree.JCTree.JCTypeCast;
  80 import com.sun.tools.javac.tree.JCTree.JCTypeIntersection;
  81 import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
  82 import com.sun.tools.javac.tree.JCTree.JCTypeUnion;
  83 import com.sun.tools.javac.tree.JCTree.JCUnary;
  84 import com.sun.tools.javac.tree.JCTree.JCUses;
  85 import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
  86 import com.sun.tools.javac.tree.JCTree.JCWhileLoop;
  87 import com.sun.tools.javac.tree.JCTree.JCWildcard;
  88 import com.sun.tools.javac.tree.JCTree.JCYield;
  89 import com.sun.tools.javac.tree.JCTree.LetExpr;
  90 import com.sun.tools.javac.tree.JCTree.TypeBoundKind;
  91 import com.sun.tools.javac.tree.TreeInfo;
  92 import com.sun.tools.javac.tree.TreeScanner;
  93 import com.sun.tools.javac.util.List;
  94 import java.util.Collection;
  95 import java.util.HashMap;
  96 import java.util.Iterator;
  97 import java.util.Map;
  98 import java.util.Objects;
  99 
 100 /** A visitor that compares two lambda bodies for structural equality. */
 101 public class TreeDiffer extends TreeScanner {
 102 
 103     public TreeDiffer(
 104             Collection<? extends Symbol> symbols, Collection<? extends Symbol> otherSymbols) {
 105         this.equiv = equiv(symbols, otherSymbols);
 106     }
 107 
 108     private static Map<Symbol, Symbol> equiv(
 109             Collection<? extends Symbol> symbols, Collection<? extends Symbol> otherSymbols) {
 110         Map<Symbol, Symbol> result = new HashMap<>();
 111         Iterator<? extends Symbol> it = otherSymbols.iterator();
 112         for (Symbol symbol : symbols) {
 113             if (!it.hasNext()) break;
 114             result.put(symbol, it.next());
 115         }
 116         return result;
 117     }
 118 
 119     private JCTree parameter;
 120     private boolean result;
 121     private Map<Symbol, Symbol> equiv = new HashMap<>();
 122 
 123     public boolean scan(JCTree tree, JCTree parameter) {
 124         if (tree == null || parameter == null) {
 125             return tree == null && parameter == null;
 126         }
 127         tree = TreeInfo.skipParens(tree);
 128         parameter = TreeInfo.skipParens(parameter);
 129         if (tree.type != null
 130                 && tree.type.constValue() != null
 131                 && parameter.type != null
 132                 && parameter.type.constValue() != null) {
 133             return Objects.equals(tree.type.constValue(), parameter.type.constValue());
 134         }
 135         if (tree.getTag() != parameter.getTag()) {
 136             return false;
 137         }
 138         JCTree prevParameter = this.parameter;
 139         boolean prevResult = this.result;
 140         try {
 141             this.parameter = parameter;
 142             tree.accept(this);
 143             return result;
 144         } finally {
 145             this.parameter = prevParameter;
 146             this.result = prevResult;
 147         }
 148     }
 149 
 150     private boolean scan(Iterable<? extends JCTree> xs, Iterable<? extends JCTree> ys) {
 151         if (xs == null || ys == null) {
 152             return xs == null && ys == null;
 153         }
 154         Iterator<? extends JCTree> x = xs.iterator();
 155         Iterator<? extends JCTree> y = ys.iterator();
 156         while (x.hasNext() && y.hasNext()) {
 157             if (!scan(x.next(), y.next())) {
 158                 return false;
 159             }
 160         }
 161         return !x.hasNext() && !y.hasNext();
 162     }
 163 
 164     private boolean scanDimAnnotations(List<List<JCAnnotation>> xs, List<List<JCAnnotation>> ys) {
 165         if (xs == null || ys == null) {
 166             return xs == null && ys == null;
 167         }
 168         Iterator<List<JCAnnotation>> x = xs.iterator();
 169         Iterator<List<JCAnnotation>> y = ys.iterator();
 170         while (x.hasNext() && y.hasNext()) {
 171             if (!scan(x.next(), y.next())) {
 172                 return false;
 173             }
 174         }
 175         return !x.hasNext() && !y.hasNext();
 176     }
 177 
 178     @Override
 179     public void visitIdent(JCIdent tree) {
 180         JCIdent that = (JCIdent) parameter;
 181         // Identifiers are a special case: we want to ensure the identifiers correspond to the
 182         // same symbols (rather than just having the same name), but also consider lambdas
 183         // equal if they differ only in the names of the parameters.
 184         Symbol symbol = tree.sym;
 185         Symbol otherSymbol = that.sym;
 186         if (symbol != null && otherSymbol != null) {
 187             if (Objects.equals(equiv.get(symbol), otherSymbol)) {
 188                 result = true;
 189                 return;
 190             }
 191         }
 192         result = tree.sym == that.sym;
 193     }
 194 
 195     @Override
 196     public void visitSelect(JCFieldAccess tree) {
 197         JCFieldAccess that = (JCFieldAccess) parameter;
 198         result = scan(tree.selected, that.selected) && tree.sym == that.sym;
 199     }
 200 
 201     @Override
 202     public void visitAnnotatedType(JCAnnotatedType tree) {
 203         JCAnnotatedType that = (JCAnnotatedType) parameter;
 204         result =
 205                 scan(tree.annotations, that.annotations)
 206                         && scan(tree.underlyingType, that.underlyingType);
 207     }
 208 
 209     @Override
 210     public void visitAnnotation(JCAnnotation tree) {
 211         JCAnnotation that = (JCAnnotation) parameter;
 212         result = scan(tree.annotationType, that.annotationType) && scan(tree.args, that.args);
 213     }
 214 
 215     @Override
 216     public void visitApply(JCMethodInvocation tree) {
 217         JCMethodInvocation that = (JCMethodInvocation) parameter;
 218         result =
 219                 scan(tree.typeargs, that.typeargs)
 220                         && scan(tree.meth, that.meth)
 221                         && scan(tree.args, that.args)
 222                         && tree.polyKind == that.polyKind;
 223     }
 224 
 225     @Override
 226     public void visitAssert(JCAssert tree) {
 227         JCAssert that = (JCAssert) parameter;
 228         result = scan(tree.cond, that.cond) && scan(tree.detail, that.detail);
 229     }
 230 
 231     @Override
 232     public void visitAssign(JCAssign tree) {
 233         JCAssign that = (JCAssign) parameter;
 234         result = scan(tree.lhs, that.lhs) && scan(tree.rhs, that.rhs);
 235     }
 236 
 237     @Override
 238     public void visitAssignop(JCAssignOp tree) {
 239         JCAssignOp that = (JCAssignOp) parameter;
 240         result =
 241                 scan(tree.lhs, that.lhs)
 242                         && scan(tree.rhs, that.rhs)
 243                         && tree.operator == that.operator;
 244     }
 245 
 246     @Override
 247     public void visitBinary(JCBinary tree) {
 248         JCBinary that = (JCBinary) parameter;
 249         result =
 250                 scan(tree.lhs, that.lhs)
 251                         && scan(tree.rhs, that.rhs)
 252                         && tree.operator == that.operator;
 253     }
 254 
 255     @Override
 256     public void visitBlock(JCBlock tree) {
 257         JCBlock that = (JCBlock) parameter;
 258         result = tree.flags == that.flags && scan(tree.stats, that.stats);
 259     }
 260 
 261     @Override
 262     public void visitBreak(JCBreak tree) {
 263         JCBreak that = (JCBreak) parameter;
 264         result = tree.label == that.label;
 265     }
 266 
 267     @Override
 268     public void visitYield(JCYield tree) {
 269         JCYield that = (JCYield) parameter;
 270         result = scan(tree.value, that.value);
 271     }
 272 
 273     @Override
 274     public void visitCase(JCCase tree) {
 275         JCCase that = (JCCase) parameter;
 276         result = scan(tree.pats, that.pats) && scan(tree.stats, that.stats);
 277     }
 278 
 279     @Override
 280     public void visitCatch(JCCatch tree) {
 281         JCCatch that = (JCCatch) parameter;
 282         result = scan(tree.param, that.param) && scan(tree.body, that.body);
 283     }
 284 
 285     @Override
 286     public void visitClassDef(JCClassDecl tree) {
 287         JCClassDecl that = (JCClassDecl) parameter;
 288         result =
 289                 scan(tree.mods, that.mods)
 290                         && tree.name == that.name
 291                         && scan(tree.typarams, that.typarams)
 292                         && scan(tree.extending, that.extending)
 293                         && scan(tree.implementing, that.implementing)
 294                         && scan(tree.defs, that.defs);
 295     }
 296 
 297     @Override
 298     public void visitConditional(JCConditional tree) {
 299         JCConditional that = (JCConditional) parameter;
 300         result =
 301                 scan(tree.cond, that.cond)
 302                         && scan(tree.truepart, that.truepart)
 303                         && scan(tree.falsepart, that.falsepart);
 304     }
 305 
 306     @Override
 307     public void visitContinue(JCContinue tree) {
 308         JCContinue that = (JCContinue) parameter;
 309         result = tree.label == that.label;
 310     }
 311 
 312     @Override
 313     public void visitDoLoop(JCDoWhileLoop tree) {
 314         JCDoWhileLoop that = (JCDoWhileLoop) parameter;
 315         result = scan(tree.body, that.body) && scan(tree.cond, that.cond);
 316     }
 317 
 318     @Override
 319     public void visitErroneous(JCErroneous tree) {
 320         JCErroneous that = (JCErroneous) parameter;
 321         result = scan(tree.errs, that.errs);
 322     }
 323 
 324     @Override
 325     public void visitExec(JCExpressionStatement tree) {
 326         JCExpressionStatement that = (JCExpressionStatement) parameter;
 327         result = scan(tree.expr, that.expr);
 328     }
 329 
 330     @Override
 331     public void visitExports(JCExports tree) {
 332         JCExports that = (JCExports) parameter;
 333         result = scan(tree.qualid, that.qualid) && scan(tree.moduleNames, that.moduleNames);
 334     }
 335 
 336     @Override
 337     public void visitForLoop(JCForLoop tree) {
 338         JCForLoop that = (JCForLoop) parameter;
 339         result =
 340                 scan(tree.init, that.init)
 341                         && scan(tree.cond, that.cond)
 342                         && scan(tree.step, that.step)
 343                         && scan(tree.body, that.body);
 344     }
 345 
 346     @Override
 347     public void visitForeachLoop(JCEnhancedForLoop tree) {
 348         JCEnhancedForLoop that = (JCEnhancedForLoop) parameter;
 349         result =
 350                 scan(tree.var, that.var)
 351                         && scan(tree.expr, that.expr)
 352                         && scan(tree.body, that.body);
 353     }
 354 
 355     @Override
 356     public void visitIf(JCIf tree) {
 357         JCIf that = (JCIf) parameter;
 358         result =
 359                 scan(tree.cond, that.cond)
 360                         && scan(tree.thenpart, that.thenpart)
 361                         && scan(tree.elsepart, that.elsepart);
 362     }
 363 
 364     @Override
 365     public void visitImport(JCImport tree) {
 366         JCImport that = (JCImport) parameter;
 367         result = tree.staticImport == that.staticImport && scan(tree.qualid, that.qualid);
 368     }
 369 
 370     @Override
 371     public void visitIndexed(JCArrayAccess tree) {
 372         JCArrayAccess that = (JCArrayAccess) parameter;
 373         result = scan(tree.indexed, that.indexed) && scan(tree.index, that.index);
 374     }
 375 
 376     @Override
 377     public void visitLabelled(JCLabeledStatement tree) {
 378         JCLabeledStatement that = (JCLabeledStatement) parameter;
 379         result = tree.label == that.label && scan(tree.body, that.body);
 380     }
 381 
 382     @Override
 383     public void visitLambda(JCLambda tree) {
 384         JCLambda that = (JCLambda) parameter;
 385         result =
 386                 scan(tree.params, that.params)
 387                         && scan(tree.body, that.body)
 388                         && tree.paramKind == that.paramKind;
 389     }
 390 
 391     @Override
 392     public void visitLetExpr(LetExpr tree) {
 393         LetExpr that = (LetExpr) parameter;
 394         result = scan(tree.defs, that.defs) && scan(tree.expr, that.expr);
 395     }
 396 
 397     @Override
 398     public void visitLiteral(JCLiteral tree) {
 399         JCLiteral that = (JCLiteral) parameter;
 400         result = tree.typetag == that.typetag && Objects.equals(tree.value, that.value);
 401     }
 402 
 403     @Override
 404     public void visitMethodDef(JCMethodDecl tree) {
 405         JCMethodDecl that = (JCMethodDecl) parameter;
 406         result =
 407                 scan(tree.mods, that.mods)
 408                         && tree.name == that.name
 409                         && scan(tree.restype, that.restype)
 410                         && scan(tree.typarams, that.typarams)
 411                         && scan(tree.recvparam, that.recvparam)
 412                         && scan(tree.params, that.params)
 413                         && scan(tree.thrown, that.thrown)
 414                         && scan(tree.body, that.body)
 415                         && scan(tree.defaultValue, that.defaultValue);
 416     }
 417 
 418     @Override
 419     public void visitModifiers(JCModifiers tree) {
 420         JCModifiers that = (JCModifiers) parameter;
 421         result = tree.flags == that.flags && scan(tree.annotations, that.annotations);
 422     }
 423 
 424     @Override
 425     public void visitModuleDef(JCModuleDecl tree) {
 426         JCModuleDecl that = (JCModuleDecl) parameter;
 427         result =
 428                 scan(tree.mods, that.mods)
 429                         && scan(tree.qualId, that.qualId)
 430                         && scan(tree.directives, that.directives);
 431     }
 432 
 433     @Override
 434     public void visitNewArray(JCNewArray tree) {
 435         JCNewArray that = (JCNewArray) parameter;
 436         result =
 437                 scan(tree.elemtype, that.elemtype)
 438                         && scan(tree.dims, that.dims)
 439                         && scan(tree.annotations, that.annotations)
 440                         && scanDimAnnotations(tree.dimAnnotations, that.dimAnnotations)
 441                         && scan(tree.elems, that.elems);
 442     }
 443 
 444     @Override
 445     public void visitNewClass(JCNewClass tree) {
 446         JCNewClass that = (JCNewClass) parameter;
 447         result =
 448                 scan(tree.encl, that.encl)
 449                         && scan(tree.typeargs, that.typeargs)
 450                         && scan(tree.clazz, that.clazz)
 451                         && scan(tree.args, that.args)
 452                         && scan(tree.def, that.def)
 453                         && tree.constructor == that.constructor;
 454     }
 455 
 456     @Override
 457     public void visitOpens(JCOpens tree) {
 458         JCOpens that = (JCOpens) parameter;
 459         result = scan(tree.qualid, that.qualid) && scan(tree.moduleNames, that.moduleNames);
 460     }
 461 
 462     @Override
 463     public void visitPackageDef(JCPackageDecl tree) {
 464         JCPackageDecl that = (JCPackageDecl) parameter;
 465         result =
 466                 scan(tree.annotations, that.annotations)
 467                         && scan(tree.pid, that.pid)
 468                         && tree.packge == that.packge;
 469     }
 470 
 471     @Override
 472     public void visitProvides(JCProvides tree) {
 473         JCProvides that = (JCProvides) parameter;
 474         result = scan(tree.serviceName, that.serviceName) && scan(tree.implNames, that.implNames);
 475     }
 476 
 477     @Override
 478     public void visitReference(JCMemberReference tree) {
 479         JCMemberReference that = (JCMemberReference) parameter;
 480         result =
 481                 tree.mode == that.mode
 482                         && tree.kind == that.kind
 483                         && tree.name == that.name
 484                         && scan(tree.expr, that.expr)
 485                         && scan(tree.typeargs, that.typeargs);
 486     }
 487 
 488     @Override
 489     public void visitRequires(JCRequires tree) {
 490         JCRequires that = (JCRequires) parameter;
 491         result =
 492                 tree.isTransitive == that.isTransitive
 493                         && tree.isStaticPhase == that.isStaticPhase
 494                         && scan(tree.moduleName, that.moduleName);
 495     }
 496 
 497     @Override
 498     public void visitReturn(JCReturn tree) {
 499         JCReturn that = (JCReturn) parameter;
 500         result = scan(tree.expr, that.expr);
 501     }
 502 
 503     @Override
 504     public void visitSwitch(JCSwitch tree) {
 505         JCSwitch that = (JCSwitch) parameter;
 506         result = scan(tree.selector, that.selector) && scan(tree.cases, that.cases);
 507     }
 508 
 509     @Override
 510     public void visitSwitchExpression(JCSwitchExpression tree) {
 511         JCSwitchExpression that = (JCSwitchExpression) parameter;
 512         result = scan(tree.selector, that.selector) && scan(tree.cases, that.cases);
 513     }
 514 
 515     @Override
 516     public void visitSynchronized(JCSynchronized tree) {
 517         JCSynchronized that = (JCSynchronized) parameter;
 518         result = scan(tree.lock, that.lock) && scan(tree.body, that.body);
 519     }
 520 
 521     @Override
 522     public void visitThrow(JCThrow tree) {
 523         JCThrow that = (JCThrow) parameter;
 524         result = scan(tree.expr, that.expr);
 525     }
 526 
 527     @Override
 528     public void visitTopLevel(JCCompilationUnit tree) {
 529         JCCompilationUnit that = (JCCompilationUnit) parameter;
 530         result =
 531                 scan(tree.defs, that.defs)
 532                         && tree.modle == that.modle
 533                         && tree.packge == that.packge;
 534     }
 535 
 536     @Override
 537     public void visitTry(JCTry tree) {
 538         JCTry that = (JCTry) parameter;
 539         result =
 540                 scan(tree.body, that.body)
 541                         && scan(tree.catchers, that.catchers)
 542                         && scan(tree.finalizer, that.finalizer)
 543                         && scan(tree.resources, that.resources);
 544     }
 545 
 546     @Override
 547     public void visitTypeApply(JCTypeApply tree) {
 548         JCTypeApply that = (JCTypeApply) parameter;
 549         result = scan(tree.clazz, that.clazz) && scan(tree.arguments, that.arguments);
 550     }
 551 
 552     @Override
 553     public void visitTypeArray(JCArrayTypeTree tree) {
 554         JCArrayTypeTree that = (JCArrayTypeTree) parameter;
 555         result = scan(tree.elemtype, that.elemtype);
 556     }
 557 
 558     @Override
 559     public void visitTypeBoundKind(TypeBoundKind tree) {
 560         TypeBoundKind that = (TypeBoundKind) parameter;
 561         result = tree.kind == that.kind;
 562     }
 563 
 564     @Override
 565     public void visitTypeCast(JCTypeCast tree) {
 566         JCTypeCast that = (JCTypeCast) parameter;
 567         result = scan(tree.clazz, that.clazz) && scan(tree.expr, that.expr);
 568     }
 569 
 570     @Override
 571     public void visitTypeIdent(JCPrimitiveTypeTree tree) {
 572         JCPrimitiveTypeTree that = (JCPrimitiveTypeTree) parameter;
 573         result = tree.typetag == that.typetag;
 574     }
 575 
 576     @Override
 577     public void visitTypeIntersection(JCTypeIntersection tree) {
 578         JCTypeIntersection that = (JCTypeIntersection) parameter;
 579         result = scan(tree.bounds, that.bounds);
 580     }
 581 
 582     @Override
 583     public void visitTypeParameter(JCTypeParameter tree) {
 584         JCTypeParameter that = (JCTypeParameter) parameter;
 585         result =
 586                 tree.name == that.name
 587                         && scan(tree.bounds, that.bounds)
 588                         && scan(tree.annotations, that.annotations);
 589     }
 590 
 591     @Override
 592     public void visitTypeTest(JCInstanceOf tree) {
 593         JCInstanceOf that = (JCInstanceOf) parameter;
 594         result = scan(tree.expr, that.expr) && scan(tree.clazz, that.clazz);
 595     }
 596 
 597     @Override
 598     public void visitTypeUnion(JCTypeUnion tree) {
 599         JCTypeUnion that = (JCTypeUnion) parameter;
 600         result = scan(tree.alternatives, that.alternatives);
 601     }
 602 
 603     @Override
 604     public void visitUnary(JCUnary tree) {
 605         JCUnary that = (JCUnary) parameter;
 606         result = scan(tree.arg, that.arg) && tree.operator == that.operator;
 607     }
 608 
 609     @Override
 610     public void visitUses(JCUses tree) {
 611         JCUses that = (JCUses) parameter;
 612         result = scan(tree.qualid, that.qualid);
 613     }
 614 
 615     @Override
 616     public void visitVarDef(JCVariableDecl tree) {
 617         JCVariableDecl that = (JCVariableDecl) parameter;
 618         result =
 619                 scan(tree.mods, that.mods)
 620                         && tree.name == that.name
 621                         && scan(tree.nameexpr, that.nameexpr)
 622                         && scan(tree.vartype, that.vartype)
 623                         && scan(tree.init, that.init);
 624         if (!result) {
 625             return;
 626         }
 627         equiv.put(tree.sym, that.sym);
 628     }
 629 
 630     @Override
 631     public void visitWhileLoop(JCWhileLoop tree) {
 632         JCWhileLoop that = (JCWhileLoop) parameter;
 633         result = scan(tree.cond, that.cond) && scan(tree.body, that.body);
 634     }
 635 
 636     @Override
 637     public void visitWildcard(JCWildcard tree) {
 638         JCWildcard that = (JCWildcard) parameter;
 639         result = scan(tree.kind, that.kind) && scan(tree.inner, that.inner);
 640     }
 641 }