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 
TreeDiffer( Collection<? extends Symbol> symbols, Collection<? extends Symbol> otherSymbols)103     public TreeDiffer(
104             Collection<? extends Symbol> symbols, Collection<? extends Symbol> otherSymbols) {
105         this.equiv = equiv(symbols, otherSymbols);
106     }
107 
equiv( Collection<? extends Symbol> symbols, Collection<? extends Symbol> otherSymbols)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 
scan(JCTree tree, JCTree parameter)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 
scan(Iterable<? extends JCTree> xs, Iterable<? extends JCTree> ys)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 
scanDimAnnotations(List<List<JCAnnotation>> xs, List<List<JCAnnotation>> ys)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
visitIdent(JCIdent tree)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
visitSelect(JCFieldAccess tree)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
visitAnnotatedType(JCAnnotatedType tree)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
visitAnnotation(JCAnnotation tree)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
visitApply(JCMethodInvocation tree)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
visitAssert(JCAssert tree)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
visitAssign(JCAssign tree)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
visitAssignop(JCAssignOp tree)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
visitBinary(JCBinary tree)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
visitBlock(JCBlock tree)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
visitBreak(JCBreak tree)262     public void visitBreak(JCBreak tree) {
263         JCBreak that = (JCBreak) parameter;
264         result = tree.label == that.label;
265     }
266 
267     @Override
visitYield(JCYield tree)268     public void visitYield(JCYield tree) {
269         JCYield that = (JCYield) parameter;
270         result = scan(tree.value, that.value);
271     }
272 
273     @Override
visitCase(JCCase tree)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
visitCatch(JCCatch tree)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
visitClassDef(JCClassDecl tree)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
visitConditional(JCConditional tree)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
visitContinue(JCContinue tree)307     public void visitContinue(JCContinue tree) {
308         JCContinue that = (JCContinue) parameter;
309         result = tree.label == that.label;
310     }
311 
312     @Override
visitDoLoop(JCDoWhileLoop tree)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
visitErroneous(JCErroneous tree)319     public void visitErroneous(JCErroneous tree) {
320         JCErroneous that = (JCErroneous) parameter;
321         result = scan(tree.errs, that.errs);
322     }
323 
324     @Override
visitExec(JCExpressionStatement tree)325     public void visitExec(JCExpressionStatement tree) {
326         JCExpressionStatement that = (JCExpressionStatement) parameter;
327         result = scan(tree.expr, that.expr);
328     }
329 
330     @Override
visitExports(JCExports tree)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
visitForLoop(JCForLoop tree)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
visitForeachLoop(JCEnhancedForLoop tree)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
visitIf(JCIf tree)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
visitImport(JCImport tree)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
visitIndexed(JCArrayAccess tree)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
visitLabelled(JCLabeledStatement tree)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
visitLambda(JCLambda tree)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
visitLetExpr(LetExpr tree)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
visitLiteral(JCLiteral tree)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
visitMethodDef(JCMethodDecl tree)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
visitModifiers(JCModifiers tree)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
visitModuleDef(JCModuleDecl tree)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
visitNewArray(JCNewArray tree)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
visitNewClass(JCNewClass tree)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
visitOpens(JCOpens tree)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
visitPackageDef(JCPackageDecl tree)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
visitProvides(JCProvides tree)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
visitReference(JCMemberReference tree)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
visitRequires(JCRequires tree)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
visitReturn(JCReturn tree)498     public void visitReturn(JCReturn tree) {
499         JCReturn that = (JCReturn) parameter;
500         result = scan(tree.expr, that.expr);
501     }
502 
503     @Override
visitSwitch(JCSwitch tree)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
visitSwitchExpression(JCSwitchExpression tree)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
visitSynchronized(JCSynchronized tree)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
visitThrow(JCThrow tree)522     public void visitThrow(JCThrow tree) {
523         JCThrow that = (JCThrow) parameter;
524         result = scan(tree.expr, that.expr);
525     }
526 
527     @Override
visitTopLevel(JCCompilationUnit tree)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
visitTry(JCTry tree)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
visitTypeApply(JCTypeApply tree)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
visitTypeArray(JCArrayTypeTree tree)553     public void visitTypeArray(JCArrayTypeTree tree) {
554         JCArrayTypeTree that = (JCArrayTypeTree) parameter;
555         result = scan(tree.elemtype, that.elemtype);
556     }
557 
558     @Override
visitTypeBoundKind(TypeBoundKind tree)559     public void visitTypeBoundKind(TypeBoundKind tree) {
560         TypeBoundKind that = (TypeBoundKind) parameter;
561         result = tree.kind == that.kind;
562     }
563 
564     @Override
visitTypeCast(JCTypeCast tree)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
visitTypeIdent(JCPrimitiveTypeTree tree)571     public void visitTypeIdent(JCPrimitiveTypeTree tree) {
572         JCPrimitiveTypeTree that = (JCPrimitiveTypeTree) parameter;
573         result = tree.typetag == that.typetag;
574     }
575 
576     @Override
visitTypeIntersection(JCTypeIntersection tree)577     public void visitTypeIntersection(JCTypeIntersection tree) {
578         JCTypeIntersection that = (JCTypeIntersection) parameter;
579         result = scan(tree.bounds, that.bounds);
580     }
581 
582     @Override
visitTypeParameter(JCTypeParameter tree)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
visitTypeTest(JCInstanceOf tree)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
visitTypeUnion(JCTypeUnion tree)598     public void visitTypeUnion(JCTypeUnion tree) {
599         JCTypeUnion that = (JCTypeUnion) parameter;
600         result = scan(tree.alternatives, that.alternatives);
601     }
602 
603     @Override
visitUnary(JCUnary tree)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
visitUses(JCUses tree)610     public void visitUses(JCUses tree) {
611         JCUses that = (JCUses) parameter;
612         result = scan(tree.qualid, that.qualid);
613     }
614 
615     @Override
visitVarDef(JCVariableDecl tree)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
visitWhileLoop(JCWhileLoop tree)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
visitWildcard(JCWildcard tree)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 }
642