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