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