b9f49fd34fccc96a9314aecc26ded5f5f6429f27
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / core / dom / ASTMatcher.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.core.dom;
12
13 import java.util.Iterator;
14 import java.util.List;
15
16 /**
17  * Concrete superclass and default implementation of an AST subtree matcher.
18  * <p>
19  * For example, to compute whether two ASTs subtrees are structurally 
20  * isomorphic, use <code>n1.subtreeMatch(new ASTMatcher(), n2)</code> where 
21  * <code>n1</code> and <code>n2</code> are the AST root nodes of the subtrees.
22  * </p>
23  * <p>
24  * For each different concrete AST node type <i>T</i> there is a
25  * <code>public boolean match(<i>T</i> node, Object other)</code> method
26  * that matches the given node against another object (typically another
27  * AST node, although this is not essential). The default implementations
28  * provided by this class tests whether the other object is a node of the
29  * same type with structurally isomorphic child subtrees. For nodes with 
30  * list-valued properties, the child nodes within the list are compared in
31  * order. For nodes with multiple properties, the child nodes are compared
32  * in the order that most closely corresponds to the lexical reading order
33  * of the source program. For instance, for a type declaration node, the 
34  * child ordering is: name, superclass, superinterfaces, and body 
35  * declarations.
36  * </p>
37  * <p>
38  * Subclasses may override (extend or reimplement) some or all of the 
39  * <code>match</code> methods in order to define more specialized subtree
40  * matchers.
41  * </p>
42  * 
43  * @see org.eclipse.jdt.core.dom.ASTNode#subtreeMatch(ASTMatcher, Object)
44  * @since 2.0
45  */
46 public class ASTMatcher {
47         
48         /**
49          * Indicates whether doc tags should be matched.
50          * @since 3.0
51          */
52         private boolean matchDocTags;
53         
54         /**
55          * Creates a new AST matcher instance.
56          * <p>
57          * For backwards compatibility, the matcher ignores tag
58          * elements below doc comments by default. Use 
59          * {@link #ASTMatcher(boolean) ASTMatcher(true)}
60          * for a matcher that compares doc tags by default.
61          * </p>
62          */
63         public ASTMatcher() {
64                 this(false);
65         }
66
67         /**
68          * Creates a new AST matcher instance.
69          * 
70          * @param matchDocTags <code>true</code> if doc comment tags are
71          * to be compared by default, and <code>false</code> otherwise
72          * @see #match(Javadoc,Object)
73          * @since 3.0
74          */
75         public ASTMatcher(boolean matchDocTags) {
76                 this.matchDocTags = matchDocTags;
77         }
78
79         /**
80          * Returns whether the given lists of AST nodes match pair wise according
81          * to <code>ASTNode.subtreeMatch</code>.
82          * <p>
83          * Note that this is a convenience method, useful for writing recursive
84          * subtree matchers.
85          * </p>
86          * 
87          * @param list1 the first list of AST nodes
88          *    (element type: <code>ASTNode</code>)
89          * @param list2 the second list of AST nodes
90          *    (element type: <code>ASTNode</code>)
91          * @return <code>true</code> if the lists have the same number of elements
92          *    and match pair-wise according to <code>ASTNode.subtreeMatch</code> 
93          * @see ASTNode#subtreeMatch(ASTMatcher matcher, Object other)
94          */
95         public final boolean safeSubtreeListMatch(List list1, List list2) {
96                 int size1 = list1.size();
97                 int size2 = list2.size();
98                 if (size1 != size2) {
99                         return false;
100                 }
101                 for (Iterator it1 = list1.iterator(), it2 = list2.iterator(); it1.hasNext();) {
102                         ASTNode n1 = (ASTNode) it1.next();
103                         ASTNode n2 = (ASTNode) it2.next();
104                         if (!n1.subtreeMatch(this, n2)) {
105                                 return false;
106                         }
107                 }
108                 return true;
109         }
110
111         /**
112          * Returns whether the given nodes match according to
113          * <code>AST.subtreeMatch</code>. Returns <code>false</code> if one or
114          * the other of the nodes are <code>null</code>. Returns <code>true</code>
115          * if both nodes are <code>null</code>.
116          * <p>
117          * Note that this is a convenience method, useful for writing recursive
118          * subtree matchers.
119          * </p>
120          * 
121          * @param node1 the first AST node, or <code>null</code>; must be an
122          *    instance of <code>ASTNode</code>
123          * @param node2 the second AST node, or <code>null</code>; must be an
124          *    instance of <code>ASTNode</code>
125          * @return <code>true</code> if the nodes match according
126          *    to <code>AST.subtreeMatch</code> or both are <code>null</code>, and 
127          *    <code>false</code> otherwise
128          * @see ASTNode#subtreeMatch(ASTMatcher, Object)
129          */
130         public final boolean safeSubtreeMatch(Object node1, Object node2) {
131                 if (node1 == null && node2 == null) {
132                         return true;
133                 }
134                 if (node1 == null || node2 == null) {
135                         return false;
136                 }
137                 // N.B. call subtreeMatch even node1==node2!=null
138                 return ((ASTNode) node1).subtreeMatch(this, node2);
139         }
140
141         /**
142          * Returns whether the given objects are equal according to
143          * <code>equals</code>. Returns <code>false</code> if either
144          * node is <code>null</code>.
145          * 
146          * @param o1 the first object, or <code>null</code>
147          * @param o2 the second object, or <code>null</code>
148          * @return <code>true</code> if the nodes are equal according to
149          *    <code>equals</code> or both <code>null</code>, and 
150          *    <code>false</code> otherwise
151          */
152         public static boolean safeEquals(Object o1, Object o2) {
153                 if (o1 == o2) {
154                         return true;
155                 }
156                 if (o1 == null || o2 == null) {
157                         return false;
158                 }
159                 return o1.equals(o2);
160         }
161
162         /**
163          * Returns whether the given node and the other object match.
164          * <p>
165          * The default implementation provided by this class tests whether the
166          * other object is a node of the same type with structurally isomorphic
167          * child subtrees. Subclasses may override this method as needed.
168          * </p>
169          * 
170          * @param node the node
171          * @param other the other object, or <code>null</code>
172          * @return <code>true</code> if the subtree matches, or 
173          *   <code>false</code> if they do not match or the other object has a
174          *   different node type or is <code>null</code>
175          * @since 3.1
176          */
177         public boolean match(AnnotationTypeDeclaration node, Object other) {
178                 if (!(other instanceof AnnotationTypeDeclaration)) {
179                         return false;
180                 }
181                 AnnotationTypeDeclaration o = (AnnotationTypeDeclaration) other;
182                 // node type added in JLS3 - ignore old JLS2-style modifiers
183                 return (safeSubtreeMatch(node.getJavadoc(), o.getJavadoc())
184                                 && safeSubtreeListMatch(node.modifiers(), o.modifiers())
185                                 && safeSubtreeMatch(node.getName(), o.getName())
186                                 && safeSubtreeListMatch(node.bodyDeclarations(), o.bodyDeclarations()));
187         }
188
189         /**
190          * Returns whether the given node and the other object match.
191          * <p>
192          * The default implementation provided by this class tests whether the
193          * other object is a node of the same type with structurally isomorphic
194          * child subtrees. Subclasses may override this method as needed.
195          * </p>
196          * 
197          * @param node the node
198          * @param other the other object, or <code>null</code>
199          * @return <code>true</code> if the subtree matches, or 
200          *   <code>false</code> if they do not match or the other object has a
201          *   different node type or is <code>null</code>
202          * @since 3.1
203          */
204         public boolean match(AnnotationTypeMemberDeclaration node, Object other) {
205                 if (!(other instanceof AnnotationTypeMemberDeclaration)) {
206                         return false;
207                 }
208                 AnnotationTypeMemberDeclaration o = (AnnotationTypeMemberDeclaration) other;
209                 // node type added in JLS3 - ignore old JLS2-style modifiers
210                 return (safeSubtreeMatch(node.getJavadoc(), o.getJavadoc())
211                                 && safeSubtreeListMatch(node.modifiers(), o.modifiers())
212                                 && safeSubtreeMatch(node.getType(), o.getType())
213                                 && safeSubtreeMatch(node.getName(), o.getName())
214                                 && safeSubtreeMatch(node.getDefault(), o.getDefault()));
215         }
216
217         /**
218          * Returns whether the given node and the other object match.
219          * <p>
220          * The default implementation provided by this class tests whether the
221          * other object is a node of the same type with structurally isomorphic
222          * child subtrees. Subclasses may override this method as needed.
223          * </p>
224          * 
225          * @param node the node
226          * @param other the other object, or <code>null</code>
227          * @return <code>true</code> if the subtree matches, or 
228          *   <code>false</code> if they do not match or the other object has a
229          *   different node type or is <code>null</code>
230          */
231         public boolean match(AnonymousClassDeclaration node, Object other) {
232                 if (!(other instanceof AnonymousClassDeclaration)) {
233                         return false;
234                 }
235                 AnonymousClassDeclaration o = (AnonymousClassDeclaration) other;
236                 return safeSubtreeListMatch(node.bodyDeclarations(), o.bodyDeclarations());
237         }
238
239         /**
240          * Returns whether the given node and the other object match.
241          * <p>
242          * The default implementation provided by this class tests whether the
243          * other object is a node of the same type with structurally isomorphic
244          * child subtrees. Subclasses may override this method as needed.
245          * </p>
246          * 
247          * @param node the node
248          * @param other the other object, or <code>null</code>
249          * @return <code>true</code> if the subtree matches, or 
250          *   <code>false</code> if they do not match or the other object has a
251          *   different node type or is <code>null</code>
252          */
253         public boolean match(ArrayAccess node, Object other) {
254                 if (!(other instanceof ArrayAccess)) {
255                         return false;
256                 }
257                 ArrayAccess o = (ArrayAccess) other;
258                 return (
259                         safeSubtreeMatch(node.getArray(), o.getArray())
260                                 && safeSubtreeMatch(node.getIndex(), o.getIndex()));
261         }
262
263         /**
264          * Returns whether the given node and the other object object match.
265          * <p>
266          * The default implementation provided by this class tests whether the
267          * other object is a node of the same type with structurally isomorphic
268          * child subtrees. Subclasses may override this method as needed.
269          * </p>
270          * 
271          * @param node the node
272          * @param other the other object, or <code>null</code>
273          * @return <code>true</code> if the subtree matches, or 
274          *   <code>false</code> if they do not match or the other object has a
275          *   different node type or is <code>null</code>
276          */
277         public boolean match(ArrayCreation node, Object other) {
278                 if (!(other instanceof ArrayCreation)) {
279                         return false;
280                 }
281                 ArrayCreation o = (ArrayCreation) other;
282                 return (
283                         safeSubtreeMatch(node.getType(), o.getType())
284                                 && safeSubtreeListMatch(node.dimensions(), o.dimensions())
285                                 && safeSubtreeMatch(node.getInitializer(), o.getInitializer()));
286         }
287
288         /**
289          * Returns whether the given node and the other object match.
290          * <p>
291          * The default implementation provided by this class tests whether the
292          * other object is a node of the same type with structurally isomorphic
293          * child subtrees. Subclasses may override this method as needed.
294          * </p>
295          * 
296          * @param node the node
297          * @param other the other object, or <code>null</code>
298          * @return <code>true</code> if the subtree matches, or 
299          *   <code>false</code> if they do not match or the other object has a
300          *   different node type or is <code>null</code>
301          */
302         public boolean match(ArrayInitializer node, Object other) {
303                 if (!(other instanceof ArrayInitializer)) {
304                         return false;
305                 }
306                 ArrayInitializer o = (ArrayInitializer) other;
307                 return safeSubtreeListMatch(node.expressions(), o.expressions());
308         }
309
310         /**
311          * Returns whether the given node and the other object match.
312          * <p>
313          * The default implementation provided by this class tests whether the
314          * other object is a node of the same type with structurally isomorphic
315          * child subtrees. Subclasses may override this method as needed.
316          * </p>
317          * 
318          * @param node the node
319          * @param other the other object, or <code>null</code>
320          * @return <code>true</code> if the subtree matches, or 
321          *   <code>false</code> if they do not match or the other object has a
322          *   different node type or is <code>null</code>
323          */
324         public boolean match(ArrayType node, Object other) {
325                 if (!(other instanceof ArrayType)) {
326                         return false;
327                 }
328                 ArrayType o = (ArrayType) other;
329                 return safeSubtreeMatch(node.getComponentType(), o.getComponentType());
330         }
331
332         /**
333          * Returns whether the given node and the other object match.
334          * <p>
335          * The default implementation provided by this class tests whether the
336          * other object is a node of the same type with structurally isomorphic
337          * child subtrees. Subclasses may override this method as needed.
338          * </p>
339          * 
340          * @param node the node
341          * @param other the other object, or <code>null</code>
342          * @return <code>true</code> if the subtree matches, or 
343          *   <code>false</code> if they do not match or the other object has a
344          *   different node type or is <code>null</code>
345          */
346         public boolean match(AssertStatement node, Object other) {
347                 if (!(other instanceof AssertStatement)) {
348                         return false;
349                 }
350                 AssertStatement o = (AssertStatement) other;
351                 return (
352                         safeSubtreeMatch(node.getExpression(), o.getExpression())
353                                 && safeSubtreeMatch(node.getMessage(), o.getMessage()));
354         }
355
356         /**
357          * Returns whether the given node and the other object match.
358          * <p>
359          * The default implementation provided by this class tests whether the
360          * other object is a node of the same type with structurally isomorphic
361          * child subtrees. Subclasses may override this method as needed.
362          * </p>
363          * 
364          * @param node the node
365          * @param other the other object, or <code>null</code>
366          * @return <code>true</code> if the subtree matches, or 
367          *   <code>false</code> if they do not match or the other object has a
368          *   different node type or is <code>null</code>
369          */
370         public boolean match(Assignment node, Object other) {
371                 if (!(other instanceof Assignment)) {
372                         return false;
373                 }
374                 Assignment o = (Assignment) other;
375                 return (
376                         node.getOperator().equals(o.getOperator())
377                                 && safeSubtreeMatch(node.getLeftHandSide(), o.getLeftHandSide())
378                                 && safeSubtreeMatch(node.getRightHandSide(), o.getRightHandSide()));
379         }
380
381         /**
382          * Returns whether the given node and the other object match.
383          * <p>
384          * The default implementation provided by this class tests whether the
385          * other object is a node of the same type with structurally isomorphic
386          * child subtrees. Subclasses may override this method as needed.
387          * </p>
388          * 
389          * @param node the node
390          * @param other the other object, or <code>null</code>
391          * @return <code>true</code> if the subtree matches, or 
392          *   <code>false</code> if they do not match or the other object has a
393          *   different node type or is <code>null</code>
394          */
395         public boolean match(Block node, Object other) {
396                 if (!(other instanceof Block)) {
397                         return false;
398                 }
399                 Block o = (Block) other;
400                 return safeSubtreeListMatch(node.statements(), o.statements());
401         }
402
403         /**
404          * Returns whether the given node and the other object match.
405          * <p>
406          * The default implementation provided by this class tests whether the
407          * other object is a node of the same type. Subclasses may override
408          * this method as needed.
409          * </p>
410          * <p>Note: {@link LineComment} and {@link BlockComment} nodes are
411          * not considered part of main structure of the AST. This method will
412          * only be called if a client goes out of their way to visit this
413          * kind of node explicitly.
414          * </p>
415          * 
416          * @param node the node
417          * @param other the other object, or <code>null</code>
418          * @return <code>true</code> if the subtree matches, or 
419          *   <code>false</code> if they do not match or the other object has a
420          *   different node type or is <code>null</code>
421          * @since 3.0
422          */
423         public boolean match(BlockComment node, Object other) {
424                 if (!(other instanceof BlockComment)) {
425                         return false;
426                 }
427                 return true;
428         }
429
430         /**
431          * Returns whether the given node and the other object match.
432          * <p>
433          * The default implementation provided by this class tests whether the
434          * other object is a node of the same type with structurally isomorphic
435          * child subtrees. Subclasses may override this method as needed.
436          * </p>
437          * 
438          * @param node the node
439          * @param other the other object, or <code>null</code>
440          * @return <code>true</code> if the subtree matches, or 
441          *   <code>false</code> if they do not match or the other object has a
442          *   different node type or is <code>null</code>
443          */
444         public boolean match(BooleanLiteral node, Object other) {
445                 if (!(other instanceof BooleanLiteral)) {
446                         return false;
447                 }
448                 BooleanLiteral o = (BooleanLiteral) other;
449                 return node.booleanValue() == o.booleanValue();
450         }
451
452         /**
453          * Returns whether the given node and the other object match.
454          * <p>
455          * The default implementation provided by this class tests whether the
456          * other object is a node of the same type with structurally isomorphic
457          * child subtrees. Subclasses may override this method as needed.
458          * </p>
459          * 
460          * @param node the node
461          * @param other the other object, or <code>null</code>
462          * @return <code>true</code> if the subtree matches, or 
463          *   <code>false</code> if they do not match or the other object has a
464          *   different node type or is <code>null</code>
465          */
466         public boolean match(BreakStatement node, Object other) {
467                 if (!(other instanceof BreakStatement)) {
468                         return false;
469                 }
470                 BreakStatement o = (BreakStatement) other;
471                 return safeSubtreeMatch(node.getLabel(), o.getLabel());
472         }
473
474         /**
475          * Returns whether the given node and the other object match.
476          * <p>
477          * The default implementation provided by this class tests whether the
478          * other object is a node of the same type with structurally isomorphic
479          * child subtrees. Subclasses may override this method as needed.
480          * </p>
481          * 
482          * @param node the node
483          * @param other the other object, or <code>null</code>
484          * @return <code>true</code> if the subtree matches, or 
485          *   <code>false</code> if they do not match or the other object has a
486          *   different node type or is <code>null</code>
487          */
488         public boolean match(CastExpression node, Object other) {
489                 if (!(other instanceof CastExpression)) {
490                         return false;
491                 }
492                 CastExpression o = (CastExpression) other;
493                 return (
494                         safeSubtreeMatch(node.getType(), o.getType())
495                                 && safeSubtreeMatch(node.getExpression(), o.getExpression()));
496         }
497
498         /**
499          * Returns whether the given node and the other object match.
500          * <p>
501          * The default implementation provided by this class tests whether the
502          * other object is a node of the same type with structurally isomorphic
503          * child subtrees. Subclasses may override this method as needed.
504          * </p>
505          * 
506          * @param node the node
507          * @param other the other object, or <code>null</code>
508          * @return <code>true</code> if the subtree matches, or 
509          *   <code>false</code> if they do not match or the other object has a
510          *   different node type or is <code>null</code>
511          */
512         public boolean match(CatchClause node, Object other) {
513                 if (!(other instanceof CatchClause)) {
514                         return false;
515                 }
516                 CatchClause o = (CatchClause) other;
517                 return (
518                         safeSubtreeMatch(node.getException(), o.getException())
519                                 && safeSubtreeMatch(node.getBody(), o.getBody()));
520         }
521
522         /**
523          * Returns whether the given node and the other object match.
524          * <p>
525          * The default implementation provided by this class tests whether the
526          * other object is a node of the same type with structurally isomorphic
527          * child subtrees. Subclasses may override this method as needed.
528          * </p>
529          * 
530          * @param node the node
531          * @param other the other object, or <code>null</code>
532          * @return <code>true</code> if the subtree matches, or 
533          *   <code>false</code> if they do not match or the other object has a
534          *   different node type or is <code>null</code>
535          */
536         public boolean match(CharacterLiteral node, Object other) {
537                 if (!(other instanceof CharacterLiteral)) {
538                         return false;
539                 }
540                 CharacterLiteral o = (CharacterLiteral) other;
541                 return safeEquals(node.getEscapedValue(), o.getEscapedValue());
542         }
543
544         /**
545          * Returns whether the given node and the other object match.
546          * <p>
547          * The default implementation provided by this class tests whether the
548          * other object is a node of the same type with structurally isomorphic
549          * child subtrees. Subclasses may override this method as needed.
550          * </p>
551          * 
552          * @param node the node
553          * @param other the other object, or <code>null</code>
554          * @return <code>true</code> if the subtree matches, or 
555          *   <code>false</code> if they do not match or the other object has a
556          *   different node type or is <code>null</code>
557          */
558         public boolean match(ClassInstanceCreation node, Object other) {
559                 if (!(other instanceof ClassInstanceCreation)) {
560                         return false;
561                 }
562                 ClassInstanceCreation o = (ClassInstanceCreation) other;
563                 int level = node.getAST().apiLevel;
564                 if (level == AST.JLS2_INTERNAL) {
565                         if (!safeSubtreeMatch(node.internalGetName(), o.internalGetName())) {
566                                 return false;
567                         }
568                 }
569                 if (level >= AST.JLS3) {
570                         if (!safeSubtreeListMatch(node.typeArguments(), o.typeArguments())) {
571                                 return false;
572                         }
573                         if (!safeSubtreeMatch(node.getType(), o.getType())) {
574                                 return false;
575                         }
576                 }
577                 return 
578                         safeSubtreeMatch(node.getExpression(), o.getExpression())
579                                 && safeSubtreeListMatch(node.arguments(), o.arguments())
580                                 && safeSubtreeMatch(
581                                         node.getAnonymousClassDeclaration(),
582                                         o.getAnonymousClassDeclaration());
583         }
584
585         /**
586          * Returns whether the given node and the other object match.
587          * <p>
588          * The default implementation provided by this class tests whether the
589          * other object is a node of the same type with structurally isomorphic
590          * child subtrees. Subclasses may override this method as needed.
591          * </p>
592          * 
593          * @param node the node
594          * @param other the other object, or <code>null</code>
595          * @return <code>true</code> if the subtree matches, or 
596          *   <code>false</code> if they do not match or the other object has a
597          *   different node type or is <code>null</code>
598          */
599         public boolean match(CompilationUnit node, Object other) {
600                 if (!(other instanceof CompilationUnit)) {
601                         return false;
602                 }
603                 CompilationUnit o = (CompilationUnit) other;
604                 return (
605                         safeSubtreeMatch(node.getPackage(), o.getPackage())
606                                 && safeSubtreeListMatch(node.imports(), o.imports())
607                                 && safeSubtreeListMatch(node.types(), o.types()));
608         }
609
610         /**
611          * Returns whether the given node and the other object match.
612          * <p>
613          * The default implementation provided by this class tests whether the
614          * other object is a node of the same type with structurally isomorphic
615          * child subtrees. Subclasses may override this method as needed.
616          * </p>
617          * 
618          * @param node the node
619          * @param other the other object, or <code>null</code>
620          * @return <code>true</code> if the subtree matches, or 
621          *   <code>false</code> if they do not match or the other object has a
622          *   different node type or is <code>null</code>
623          */
624         public boolean match(ConditionalExpression node, Object other) {
625                 if (!(other instanceof ConditionalExpression)) {
626                         return false;
627                 }
628                 ConditionalExpression o = (ConditionalExpression) other;
629                 return (
630                         safeSubtreeMatch(node.getExpression(), o.getExpression())
631                                 && safeSubtreeMatch(node.getThenExpression(), o.getThenExpression())
632                                 && safeSubtreeMatch(node.getElseExpression(), o.getElseExpression()));
633         }
634
635         /**
636          * Returns whether the given node and the other object match.
637          * <p>
638          * The default implementation provided by this class tests whether the
639          * other object is a node of the same type with structurally isomorphic
640          * child subtrees. Subclasses may override this method as needed.
641          * </p>
642          * 
643          * @param node the node
644          * @param other the other object, or <code>null</code>
645          * @return <code>true</code> if the subtree matches, or 
646          *   <code>false</code> if they do not match or the other object has a
647          *   different node type or is <code>null</code>
648          */
649         public boolean match(ConstructorInvocation node, Object other) {
650                 if (!(other instanceof ConstructorInvocation)) {
651                         return false;
652                 }
653                 ConstructorInvocation o = (ConstructorInvocation) other;
654                 if (node.getAST().apiLevel >= AST.JLS3) {
655                         if (!safeSubtreeListMatch(node.typeArguments(), o.typeArguments())) {
656                                 return false;
657                         }
658                 }
659                 return safeSubtreeListMatch(node.arguments(), o.arguments());
660         }
661
662         /**
663          * Returns whether the given node and the other object match.
664          * <p>
665          * The default implementation provided by this class tests whether the
666          * other object is a node of the same type with structurally isomorphic
667          * child subtrees. Subclasses may override this method as needed.
668          * </p>
669          * 
670          * @param node the node
671          * @param other the other object, or <code>null</code>
672          * @return <code>true</code> if the subtree matches, or 
673          *   <code>false</code> if they do not match or the other object has a
674          *   different node type or is <code>null</code>
675          */
676         public boolean match(ContinueStatement node, Object other) {
677                 if (!(other instanceof ContinueStatement)) {
678                         return false;
679                 }
680                 ContinueStatement o = (ContinueStatement) other;
681                 return safeSubtreeMatch(node.getLabel(), o.getLabel());
682         }
683
684         /**
685          * Returns whether the given node and the other object match.
686          * <p>
687          * The default implementation provided by this class tests whether the
688          * other object is a node of the same type with structurally isomorphic
689          * child subtrees. Subclasses may override this method as needed.
690          * </p>
691          * 
692          * @param node the node
693          * @param other the other object, or <code>null</code>
694          * @return <code>true</code> if the subtree matches, or 
695          *   <code>false</code> if they do not match or the other object has a
696          *   different node type or is <code>null</code>
697          */
698         public boolean match(DoStatement node, Object other) {
699                 if (!(other instanceof DoStatement)) {
700                         return false;
701                 }
702                 DoStatement o = (DoStatement) other;
703                 return (
704                         safeSubtreeMatch(node.getExpression(), o.getExpression())
705                                 && safeSubtreeMatch(node.getBody(), o.getBody()));
706         }
707         
708         /**
709          * Returns whether the given node and the other object match.
710          * <p>
711          * The default implementation provided by this class tests whether the
712          * other object is a node of the same type with structurally isomorphic
713          * child subtrees. Subclasses may override this method as needed.
714          * </p>
715          * 
716          * @param node the node
717          * @param other the other object, or <code>null</code>
718          * @return <code>true</code> if the subtree matches, or 
719          *   <code>false</code> if they do not match or the other object has a
720          *   different node type or is <code>null</code>
721          */
722         public boolean match(EmptyStatement node, Object other) {
723                 if (!(other instanceof EmptyStatement)) {
724                         return false;
725                 }
726                 return true;
727         }
728
729         /**
730          * Returns whether the given node and the other object match.
731          * <p>
732          * The default implementation provided by this class tests whether the
733          * other object is a node of the same type with structurally isomorphic
734          * child subtrees. Subclasses may override this method as needed.
735          * </p>
736          * 
737          * @param node the node
738          * @param other the other object, or <code>null</code>
739          * @return <code>true</code> if the subtree matches, or 
740          *   <code>false</code> if they do not match or the other object has a
741          *   different node type or is <code>null</code>
742          * @since 3.1
743          */
744         public boolean match(EnhancedForStatement node, Object other) {
745                 if (!(other instanceof EnhancedForStatement)) {
746                         return false;
747                 }
748                 EnhancedForStatement o = (EnhancedForStatement) other;
749                 return (
750                         safeSubtreeMatch(node.getParameter(), o.getParameter())
751                                 && safeSubtreeMatch(node.getExpression(), o.getExpression())
752                                 && safeSubtreeMatch(node.getBody(), o.getBody()));
753         }
754
755         /**
756          * Returns whether the given node and the other object match.
757          * <p>
758          * The default implementation provided by this class tests whether the
759          * other object is a node of the same type with structurally isomorphic
760          * child subtrees. Subclasses may override this method as needed.
761          * </p>
762          * 
763          * @param node the node
764          * @param other the other object, or <code>null</code>
765          * @return <code>true</code> if the subtree matches, or 
766          *   <code>false</code> if they do not match or the other object has a
767          *   different node type or is <code>null</code>
768          * @since 3.1
769          */
770         public boolean match(EnumConstantDeclaration node, Object other) {
771                 if (!(other instanceof EnumConstantDeclaration)) {
772                         return false;
773                 }
774                 EnumConstantDeclaration o = (EnumConstantDeclaration) other;
775                 return (
776                         safeSubtreeMatch(node.getJavadoc(), o.getJavadoc())
777                                 && safeSubtreeListMatch(node.modifiers(), o.modifiers())
778                                 && safeSubtreeMatch(node.getName(), o.getName())
779                                 && safeSubtreeListMatch(node.arguments(), o.arguments())
780                                 && safeSubtreeMatch(
781                                         node.getAnonymousClassDeclaration(),
782                                         o.getAnonymousClassDeclaration()));
783         }
784         
785         /**
786          * Returns whether the given node and the other object match.
787          * <p>
788          * The default implementation provided by this class tests whether the
789          * other object is a node of the same type with structurally isomorphic
790          * child subtrees. Subclasses may override this method as needed.
791          * </p>
792          * 
793          * @param node the node
794          * @param other the other object, or <code>null</code>
795          * @return <code>true</code> if the subtree matches, or 
796          *   <code>false</code> if they do not match or the other object has a
797          *   different node type or is <code>null</code>
798          * @since 3.1
799          */
800         public boolean match(EnumDeclaration node, Object other) {
801                 if (!(other instanceof EnumDeclaration)) {
802                         return false;
803                 }
804                 EnumDeclaration o = (EnumDeclaration) other;
805                 return (
806                         safeSubtreeMatch(node.getJavadoc(), o.getJavadoc())
807                                 && safeSubtreeListMatch(node.modifiers(), o.modifiers())
808                                 && safeSubtreeMatch(node.getName(), o.getName())
809                                 && safeSubtreeListMatch(node.superInterfaceTypes(), o.superInterfaceTypes())
810                                 && safeSubtreeListMatch(node.enumConstants(), o.enumConstants())
811                                 && safeSubtreeListMatch(
812                                         node.bodyDeclarations(),
813                                         o.bodyDeclarations()));
814         }
815         
816         /**
817          * Returns whether the given node and the other object match.
818          * <p>
819          * The default implementation provided by this class tests whether the
820          * other object is a node of the same type with structurally isomorphic
821          * child subtrees. Subclasses may override this method as needed.
822          * </p>
823          * 
824          * @param node the node
825          * @param other the other object, or <code>null</code>
826          * @return <code>true</code> if the subtree matches, or 
827          *   <code>false</code> if they do not match or the other object has a
828          *   different node type or is <code>null</code>
829          */
830         public boolean match(ExpressionStatement node, Object other) {
831                 if (!(other instanceof ExpressionStatement)) {
832                         return false;
833                 }
834                 ExpressionStatement o = (ExpressionStatement) other;
835                 return safeSubtreeMatch(node.getExpression(), o.getExpression());
836         }
837
838         /**
839          * Returns whether the given node and the other object match.
840          * <p>
841          * The default implementation provided by this class tests whether the
842          * other object is a node of the same type with structurally isomorphic
843          * child subtrees. Subclasses may override this method as needed.
844          * </p>
845          * 
846          * @param node the node
847          * @param other the other object, or <code>null</code>
848          * @return <code>true</code> if the subtree matches, or 
849          *   <code>false</code> if they do not match or the other object has a
850          *   different node type or is <code>null</code>
851          */
852         public boolean match(FieldAccess node, Object other) {
853                 if (!(other instanceof FieldAccess)) {
854                         return false;
855                 }
856                 FieldAccess o = (FieldAccess) other;
857                 return (
858                         safeSubtreeMatch(node.getExpression(), o.getExpression())
859                                 && safeSubtreeMatch(node.getName(), o.getName()));
860         }
861
862         /**
863          * Returns whether the given node and the other object match.
864          * <p>
865          * The default implementation provided by this class tests whether the
866          * other object is a node of the same type with structurally isomorphic
867          * child subtrees. Subclasses may override this method as needed.
868          * </p>
869          * 
870          * @param node the node
871          * @param other the other object, or <code>null</code>
872          * @return <code>true</code> if the subtree matches, or 
873          *   <code>false</code> if they do not match or the other object has a
874          *   different node type or is <code>null</code>
875          */
876         public boolean match(FieldDeclaration node, Object other) {
877                 if (!(other instanceof FieldDeclaration)) {
878                         return false;
879                 }
880                 FieldDeclaration o = (FieldDeclaration) other;
881                 int level = node.getAST().apiLevel;
882                 if (level == AST.JLS2_INTERNAL) {
883                         if (node.getModifiers() != o.getModifiers()) {
884                                 return false;
885                         }
886                 }
887                 if (level >= AST.JLS3) {
888                         if (!safeSubtreeListMatch(node.modifiers(), o.modifiers())) {
889                                 return false;
890                         }
891                 }
892                 return 
893                         safeSubtreeMatch(node.getJavadoc(), o.getJavadoc())
894                         && safeSubtreeMatch(node.getType(), o.getType())
895                         && safeSubtreeListMatch(node.fragments(), o.fragments());
896         }
897
898         /**
899          * Returns whether the given node and the other object match.
900          * <p>
901          * The default implementation provided by this class tests whether the
902          * other object is a node of the same type with structurally isomorphic
903          * child subtrees. Subclasses may override this method as needed.
904          * </p>
905          * 
906          * @param node the node
907          * @param other the other object, or <code>null</code>
908          * @return <code>true</code> if the subtree matches, or 
909          *   <code>false</code> if they do not match or the other object has a
910          *   different node type or is <code>null</code>
911          */
912         public boolean match(ForStatement node, Object other) {
913                 if (!(other instanceof ForStatement)) {
914                         return false;
915                 }
916                 ForStatement o = (ForStatement) other;
917                 return (
918                         safeSubtreeListMatch(node.initializers(), o.initializers())
919                                 && safeSubtreeMatch(node.getExpression(), o.getExpression())
920                                 && safeSubtreeListMatch(node.updaters(), o.updaters())
921                                 && safeSubtreeMatch(node.getBody(), o.getBody()));
922         }
923
924         /**
925          * Returns whether the given node and the other object match.
926          * <p>
927          * The default implementation provided by this class tests whether the
928          * other object is a node of the same type with structurally isomorphic
929          * child subtrees. Subclasses may override this method as needed.
930          * </p>
931          * 
932          * @param node the node
933          * @param other the other object, or <code>null</code>
934          * @return <code>true</code> if the subtree matches, or 
935          *   <code>false</code> if they do not match or the other object has a
936          *   different node type or is <code>null</code>
937          */
938         public boolean match(IfStatement node, Object other) {
939                 if (!(other instanceof IfStatement)) {
940                         return false;
941                 }
942                 IfStatement o = (IfStatement) other;
943                 return (
944                         safeSubtreeMatch(node.getExpression(), o.getExpression())
945                                 && safeSubtreeMatch(node.getThenStatement(), o.getThenStatement())
946                                 && safeSubtreeMatch(node.getElseStatement(), o.getElseStatement()));
947         }
948
949         /**
950          * Returns whether the given node and the other object match.
951          * <p>
952          * The default implementation provided by this class tests whether the
953          * other object is a node of the same type with structurally isomorphic
954          * child subtrees. Subclasses may override this method as needed.
955          * </p>
956          * 
957          * @param node the node
958          * @param other the other object, or <code>null</code>
959          * @return <code>true</code> if the subtree matches, or 
960          *   <code>false</code> if they do not match or the other object has a
961          *   different node type or is <code>null</code>
962          */
963         public boolean match(ImportDeclaration node, Object other) {
964                 if (!(other instanceof ImportDeclaration)) {
965                         return false;
966                 }
967                 ImportDeclaration o = (ImportDeclaration) other;
968                 if (node.getAST().apiLevel >= AST.JLS3) {
969                         if (node.isStatic() != o.isStatic()) {
970                                 return false;
971                         }
972                 }
973                 return (
974                         safeSubtreeMatch(node.getName(), o.getName())
975                                 && node.isOnDemand() == o.isOnDemand());
976         }
977
978         /**
979          * Returns whether the given node and the other object match.
980          * <p>
981          * The default implementation provided by this class tests whether the
982          * other object is a node of the same type with structurally isomorphic
983          * child subtrees. Subclasses may override this method as needed.
984          * </p>
985          * 
986          * @param node the node
987          * @param other the other object, or <code>null</code>
988          * @return <code>true</code> if the subtree matches, or 
989          *   <code>false</code> if they do not match or the other object has a
990          *   different node type or is <code>null</code>
991          */
992         public boolean match(InfixExpression node, Object other) {
993                 if (!(other instanceof InfixExpression)) {
994                         return false;
995                 }
996                 InfixExpression o = (InfixExpression) other;
997                 // be careful not to trigger lazy creation of extended operand lists
998                 if (node.hasExtendedOperands() && o.hasExtendedOperands()) {
999                         if (!safeSubtreeListMatch(node.extendedOperands(), o.extendedOperands())) {
1000                                 return false;
1001                         }
1002                 }
1003                 if (node.hasExtendedOperands() != o.hasExtendedOperands()) {
1004                         return false;
1005                 }
1006                 return (
1007                         node.getOperator().equals(o.getOperator())
1008                                 && safeSubtreeMatch(node.getLeftOperand(), o.getLeftOperand())
1009                                 && safeSubtreeMatch(node.getRightOperand(), o.getRightOperand()));
1010         }
1011
1012         /**
1013          * Returns whether the given node and the other object match.
1014          * <p>
1015          * The default implementation provided by this class tests whether the
1016          * other object is a node of the same type with structurally isomorphic
1017          * child subtrees. Subclasses may override this method as needed.
1018          * </p>
1019          * 
1020          * @param node the node
1021          * @param other the other object, or <code>null</code>
1022          * @return <code>true</code> if the subtree matches, or 
1023          *   <code>false</code> if they do not match or the other object has a
1024          *   different node type or is <code>null</code>
1025          */
1026         public boolean match(InstanceofExpression node, Object other) {
1027                 if (!(other instanceof InstanceofExpression)) {
1028                         return false;
1029                 }
1030                 InstanceofExpression o = (InstanceofExpression) other;
1031                 return (
1032                                 safeSubtreeMatch(node.getLeftOperand(), o.getLeftOperand())
1033                                 && safeSubtreeMatch(node.getRightOperand(), o.getRightOperand()));
1034         }
1035
1036         /**
1037          * Returns whether the given node and the other object match.
1038          * <p>
1039          * The default implementation provided by this class tests whether the
1040          * other object is a node of the same type with structurally isomorphic
1041          * child subtrees. Subclasses may override this method as needed.
1042          * </p>
1043          * 
1044          * @param node the node
1045          * @param other the other object, or <code>null</code>
1046          * @return <code>true</code> if the subtree matches, or 
1047          *   <code>false</code> if they do not match or the other object has a
1048          *   different node type or is <code>null</code>
1049          */
1050         public boolean match(Initializer node, Object other) {
1051                 if (!(other instanceof Initializer)) {
1052                         return false;
1053                 }
1054                 Initializer o = (Initializer) other;
1055                 int level = node.getAST().apiLevel;
1056                 if (level == AST.JLS2_INTERNAL) {
1057                         if (node.getModifiers() != o.getModifiers()) {
1058                                 return false;
1059                         }
1060                 }
1061                 if (level >= AST.JLS3) {
1062                         if (!safeSubtreeListMatch(node.modifiers(), o.modifiers())) {
1063                                 return false;
1064                         }
1065                 }
1066                 return (
1067                                 safeSubtreeMatch(node.getJavadoc(), o.getJavadoc())
1068                                 && safeSubtreeMatch(node.getBody(), o.getBody()));
1069         }
1070
1071         /**
1072          * Returns whether the given node and the other object match.
1073          * <p>
1074          * Unlike other node types, the behavior of the default
1075          * implementation is controlled by a constructor-supplied
1076          * parameter  {@link #ASTMatcher(boolean) ASTMatcher(boolean)} 
1077          * which is <code>false</code> if not specified. 
1078          * When this parameter is <code>true</code>, the implementation
1079          * tests whether the other object is also a <code>Javadoc</code>
1080          * with structurally isomorphic child subtrees; the comment string 
1081          * (<code>Javadoc.getComment()</code>) is ignored.
1082          * Conversely, when the parameter is <code>false</code>, the
1083          * implementation tests whether the other object is also a
1084          * <code>Javadoc</code> with exactly the same comment string; 
1085          * the tag elements ({@link Javadoc#tags() Javadoc.tags} are
1086          * ignored. Subclasses may reimplement.
1087          * </p>
1088          * 
1089          * @param node the node
1090          * @param other the other object, or <code>null</code>
1091          * @return <code>true</code> if the subtree matches, or 
1092          *   <code>false</code> if they do not match or the other object has a
1093          *   different node type or is <code>null</code>
1094          * @see #ASTMatcher()
1095          * @see #ASTMatcher(boolean)
1096          */
1097         public boolean match(Javadoc node, Object other) {
1098                 if (!(other instanceof Javadoc)) {
1099                         return false;
1100                 }
1101                 Javadoc o = (Javadoc) other;
1102                 if (this.matchDocTags) {
1103                         return safeSubtreeListMatch(node.tags(), o.tags());
1104                 } else {
1105                         return compareDeprecatedComment(node, o);
1106                 }
1107         }
1108
1109         /**
1110          * Return whether the deprecated comment strings of the given java doc are equals.
1111          * <p>
1112          * Note the only purpose of this method is to hide deprecated warnings.
1113          * @deprecated mark deprecated to hide deprecated usage
1114          */
1115         private boolean compareDeprecatedComment(Javadoc first, Javadoc second) {
1116                 if (first.getAST().apiLevel == AST.JLS2_INTERNAL) {
1117                         return safeEquals(first.getComment(), second.getComment());
1118                 } else {
1119                         return true;
1120                 }
1121         }
1122
1123         /**
1124          * Returns whether the given node and the other object match.
1125          * <p>
1126          * The default implementation provided by this class tests whether the
1127          * other object is a node of the same type with structurally isomorphic
1128          * child subtrees. Subclasses may override this method as needed.
1129          * </p>
1130          * 
1131          * @param node the node
1132          * @param other the other object, or <code>null</code>
1133          * @return <code>true</code> if the subtree matches, or 
1134          *   <code>false</code> if they do not match or the other object has a
1135          *   different node type or is <code>null</code>
1136          */
1137         public boolean match(LabeledStatement node, Object other) {
1138                 if (!(other instanceof LabeledStatement)) {
1139                         return false;
1140                 }
1141                 LabeledStatement o = (LabeledStatement) other;
1142                 return (
1143                         safeSubtreeMatch(node.getLabel(), o.getLabel())
1144                                 && safeSubtreeMatch(node.getBody(), o.getBody()));
1145         }
1146
1147         /**
1148          * Returns whether the given node and the other object match.
1149          * <p>
1150          * The default implementation provided by this class tests whether the
1151          * other object is a node of the same type. Subclasses may override
1152          * this method as needed.
1153          * </p>
1154          * <p>Note: {@link LineComment} and {@link BlockComment} nodes are
1155          * not considered part of main structure of the AST. This method will
1156          * only be called if a client goes out of their way to visit this
1157          * kind of node explicitly.
1158          * </p>
1159          * 
1160          * @param node the node
1161          * @param other the other object, or <code>null</code>
1162          * @return <code>true</code> if the subtree matches, or 
1163          *   <code>false</code> if they do not match or the other object has a
1164          *   different node type or is <code>null</code>
1165          * @since 3.0
1166          */
1167         public boolean match(LineComment node, Object other) {
1168                 if (!(other instanceof LineComment)) {
1169                         return false;
1170                 }
1171                 return true;
1172         }
1173         
1174         /**
1175          * Returns whether the given node and the other object match.
1176          * <p>
1177          * The default implementation provided by this class tests whether the
1178          * other object is a node of the same type with structurally isomorphic
1179          * child subtrees. Subclasses may override this method as needed.
1180          * </p>
1181          * 
1182          * @param node the node
1183          * @param other the other object, or <code>null</code>
1184          * @return <code>true</code> if the subtree matches, or 
1185          *   <code>false</code> if they do not match or the other object has a
1186          *   different node type or is <code>null</code>
1187          * @since 3.1
1188          */
1189         public boolean match(MarkerAnnotation node, Object other) {
1190                 if (!(other instanceof MarkerAnnotation)) {
1191                         return false;
1192                 }
1193                 MarkerAnnotation o = (MarkerAnnotation) other;
1194                 return safeSubtreeMatch(node.getTypeName(), o.getTypeName());
1195         }
1196
1197         /**
1198          * Returns whether the given node and the other object match.
1199          * <p>
1200          * The default implementation provided by this class tests whether the
1201          * other object is a node of the same type with structurally isomorphic
1202          * child subtrees. Subclasses may override this method as needed.
1203          * </p>
1204          * 
1205          * @param node the node
1206          * @param other the other object, or <code>null</code>
1207          * @return <code>true</code> if the subtree matches, or 
1208          *   <code>false</code> if they do not match or the other object has a
1209          *   different node type or is <code>null</code>
1210          * @since 3.0
1211          */
1212         public boolean match(MemberRef node, Object other) {
1213                 if (!(other instanceof MemberRef)) {
1214                         return false;
1215                 }
1216                 MemberRef o = (MemberRef) other;
1217                 return (
1218                                 safeSubtreeMatch(node.getQualifier(), o.getQualifier())
1219                                 && safeSubtreeMatch(node.getName(), o.getName()));
1220         }
1221         
1222         /**
1223          * Returns whether the given node and the other object match.
1224          * <p>
1225          * The default implementation provided by this class tests whether the
1226          * other object is a node of the same type with structurally isomorphic
1227          * child subtrees. Subclasses may override this method as needed.
1228          * </p>
1229          * 
1230          * @param node the node
1231          * @param other the other object, or <code>null</code>
1232          * @return <code>true</code> if the subtree matches, or 
1233          *   <code>false</code> if they do not match or the other object has a
1234          *   different node type or is <code>null</code>
1235          * @since 3.1
1236          */
1237         public boolean match(MemberValuePair node, Object other) {
1238                 if (!(other instanceof MemberValuePair)) {
1239                         return false;
1240                 }
1241                 MemberValuePair o = (MemberValuePair) other;
1242                 return (safeSubtreeMatch(node.getName(), o.getName())
1243                                 && safeSubtreeMatch(node.getValue(), o.getValue()));
1244         }
1245
1246         /**
1247          * Returns whether the given node and the other object match.
1248          * <p>
1249          * The default implementation provided by this class tests whether the
1250          * other object is a node of the same type with structurally isomorphic
1251          * child subtrees. Subclasses may override this method as needed.
1252          * </p>
1253          * 
1254          * @param node the node
1255          * @param other the other object, or <code>null</code>
1256          * @return <code>true</code> if the subtree matches, or 
1257          *   <code>false</code> if they do not match or the other object has a
1258          *   different node type or is <code>null</code>
1259          * @since 3.0
1260          */
1261         public boolean match(MethodRef node, Object other) {
1262                 if (!(other instanceof MethodRef)) {
1263                         return false;
1264                 }
1265                 MethodRef o = (MethodRef) other;
1266                 return (
1267                                 safeSubtreeMatch(node.getQualifier(), o.getQualifier())
1268                                 && safeSubtreeMatch(node.getName(), o.getName())
1269                         && safeSubtreeListMatch(node.parameters(), o.parameters()));
1270         }
1271
1272         /**
1273          * Returns whether the given node and the other object match.
1274          * <p>
1275          * The default implementation provided by this class tests whether the
1276          * other object is a node of the same type with structurally isomorphic
1277          * child subtrees. Subclasses may override this method as needed.
1278          * </p>
1279          * 
1280          * @param node the node
1281          * @param other the other object, or <code>null</code>
1282          * @return <code>true</code> if the subtree matches, or 
1283          *   <code>false</code> if they do not match or the other object has a
1284          *   different node type or is <code>null</code>
1285          * @since 3.0
1286          */
1287         public boolean match(MethodRefParameter node, Object other) {
1288                 if (!(other instanceof MethodRefParameter)) {
1289                         return false;
1290                 }
1291                 MethodRefParameter o = (MethodRefParameter) other;
1292                 int level = node.getAST().apiLevel;
1293                 if (level >= AST.JLS3) {
1294                         if (node.isVarargs() != o.isVarargs()) {
1295                                 return false;
1296                         }
1297                 }
1298                 return (
1299                                 safeSubtreeMatch(node.getType(), o.getType())
1300                                 && safeSubtreeMatch(node.getName(), o.getName()));
1301         }
1302         
1303         /**
1304          * Returns whether the given node and the other object match.
1305          * <p>
1306          * The default implementation provided by this class tests whether the
1307          * other object is a node of the same type with structurally isomorphic
1308          * child subtrees. Subclasses may override this method as needed.
1309          * </p>
1310          * <p>
1311          * Note that extra array dimensions are compared since they are an
1312          * important part of the method declaration.
1313          * </p>
1314          * <p>
1315          * Note that the method return types are compared even for constructor
1316          * declarations.
1317          * </p>
1318          * 
1319          * @param node the node
1320          * @param other the other object, or <code>null</code>
1321          * @return <code>true</code> if the subtree matches, or 
1322          *   <code>false</code> if they do not match or the other object has a
1323          *   different node type or is <code>null</code>
1324          */
1325         public boolean match(MethodDeclaration node, Object other) {
1326                 if (!(other instanceof MethodDeclaration)) {
1327                         return false;
1328                 }
1329                 MethodDeclaration o = (MethodDeclaration) other;
1330                 int level = node.getAST().apiLevel;
1331                 if (level == AST.JLS2_INTERNAL) {
1332                         if (node.getModifiers() != o.getModifiers()) {
1333                                 return false;
1334                         }
1335                         if (!safeSubtreeMatch(node.internalGetReturnType(), o.internalGetReturnType())) {
1336                                 return false;
1337                         }
1338                 }
1339                 if (level >= AST.JLS3) {
1340                         if (!safeSubtreeListMatch(node.modifiers(), o.modifiers())) {
1341                                 return false;
1342                         }
1343                         if (!safeSubtreeMatch(node.getReturnType2(), o.getReturnType2())) {
1344                                 return false;
1345                         }
1346                         // n.b. compare type parameters even for constructors
1347                         if (!safeSubtreeListMatch(node.typeParameters(), o.typeParameters())) {
1348                                 return false;
1349                         }
1350                 }
1351                 return ((node.isConstructor() == o.isConstructor())
1352                                 && safeSubtreeMatch(node.getJavadoc(), o.getJavadoc())
1353                                 && safeSubtreeMatch(node.getName(), o.getName())
1354                                 // n.b. compare return type even for constructors
1355                                 && safeSubtreeListMatch(node.parameters(), o.parameters())
1356                                 && node.getExtraDimensions() == o.getExtraDimensions()
1357                                 && safeSubtreeListMatch(node.thrownExceptions(), o.thrownExceptions())
1358                                 && safeSubtreeMatch(node.getBody(), o.getBody()));
1359         }
1360
1361         /**
1362          * Returns whether the given node and the other object match.
1363          * <p>
1364          * The default implementation provided by this class tests whether the
1365          * other object is a node of the same type with structurally isomorphic
1366          * child subtrees. Subclasses may override this method as needed.
1367          * </p>
1368          * 
1369          * @param node the node
1370          * @param other the other object, or <code>null</code>
1371          * @return <code>true</code> if the subtree matches, or 
1372          *   <code>false</code> if they do not match or the other object has a
1373          *   different node type or is <code>null</code>
1374          */
1375         public boolean match(MethodInvocation node, Object other) {
1376                 if (!(other instanceof MethodInvocation)) {
1377                         return false;
1378                 }
1379                 MethodInvocation o = (MethodInvocation) other;
1380                 if (node.getAST().apiLevel >= AST.JLS3) {
1381                         if (!safeSubtreeListMatch(node.typeArguments(), o.typeArguments())) {
1382                                 return false;
1383                         }
1384                 }
1385                 return (
1386                         safeSubtreeMatch(node.getExpression(), o.getExpression())
1387                                 && safeSubtreeMatch(node.getName(), o.getName())
1388                                 && safeSubtreeListMatch(node.arguments(), o.arguments()));
1389         }
1390
1391         /**
1392          * Returns whether the given node and the other object match.
1393          * <p>
1394          * The default implementation provided by this class tests whether the
1395          * other object is a node of the same type with structurally isomorphic
1396          * child subtrees. Subclasses may override this method as needed.
1397          * </p>
1398          * 
1399          * @param node the node
1400          * @param other the other object, or <code>null</code>
1401          * @return <code>true</code> if the subtree matches, or 
1402          *   <code>false</code> if they do not match or the other object has a
1403          *   different node type or is <code>null</code>
1404          * @since 3.1
1405          */
1406         public boolean match(Modifier node, Object other) {
1407                 if (!(other instanceof Modifier)) {
1408                         return false;
1409                 }
1410                 Modifier o = (Modifier) other;
1411                 return (node.getKeyword() == o.getKeyword());
1412         }
1413
1414         /**
1415          * Returns whether the given node and the other object match.
1416          * <p>
1417          * The default implementation provided by this class tests whether the
1418          * other object is a node of the same type with structurally isomorphic
1419          * child subtrees. Subclasses may override this method as needed.
1420          * </p>
1421          * 
1422          * @param node the node
1423          * @param other the other object, or <code>null</code>
1424          * @return <code>true</code> if the subtree matches, or 
1425          *   <code>false</code> if they do not match or the other object has a
1426          *   different node type or is <code>null</code>
1427          * @since 3.1
1428          */
1429         public boolean match(NormalAnnotation node, Object other) {
1430                 if (!(other instanceof NormalAnnotation)) {
1431                         return false;
1432                 }
1433                 NormalAnnotation o = (NormalAnnotation) other;
1434                 return (safeSubtreeMatch(node.getTypeName(), o.getTypeName())
1435                                         && safeSubtreeListMatch(node.values(), o.values()));
1436         }
1437
1438         /**
1439          * Returns whether the given node and the other object match.
1440          * <p>
1441          * The default implementation provided by this class tests whether the
1442          * other object is a node of the same type with structurally isomorphic
1443          * child subtrees. Subclasses may override this method as needed.
1444          * </p>
1445          * 
1446          * @param node the node
1447          * @param other the other object, or <code>null</code>
1448          * @return <code>true</code> if the subtree matches, or 
1449          *   <code>false</code> if they do not match or the other object has a
1450          *   different node type or is <code>null</code>
1451          */
1452         public boolean match(NullLiteral node, Object other) {
1453                 if (!(other instanceof NullLiteral)) {
1454                         return false;
1455                 }
1456                 return true;
1457         }
1458
1459         /**
1460          * Returns whether the given node and the other object match.
1461          * <p>
1462          * The default implementation provided by this class tests whether the
1463          * other object is a node of the same type with structurally isomorphic
1464          * child subtrees. Subclasses may override this method as needed.
1465          * </p>
1466          * 
1467          * @param node the node
1468          * @param other the other object, or <code>null</code>
1469          * @return <code>true</code> if the subtree matches, or 
1470          *   <code>false</code> if they do not match or the other object has a
1471          *   different node type or is <code>null</code>
1472          */
1473         public boolean match(NumberLiteral node, Object other) {
1474                 if (!(other instanceof NumberLiteral)) {
1475                         return false;
1476                 }
1477                 NumberLiteral o = (NumberLiteral) other;
1478                 return safeEquals(node.getToken(), o.getToken());
1479         }
1480
1481         /**
1482          * Returns whether the given node and the other object match.
1483          * <p>
1484          * The default implementation provided by this class tests whether the
1485          * other object is a node of the same type with structurally isomorphic
1486          * child subtrees. Subclasses may override this method as needed.
1487          * </p>
1488          * 
1489          * @param node the node
1490          * @param other the other object, or <code>null</code>
1491          * @return <code>true</code> if the subtree matches, or 
1492          *   <code>false</code> if they do not match or the other object has a
1493          *   different node type or is <code>null</code>
1494          */
1495         public boolean match(PackageDeclaration node, Object other) {
1496                 if (!(other instanceof PackageDeclaration)) {
1497                         return false;
1498                 }
1499                 PackageDeclaration o = (PackageDeclaration) other;
1500                 if (node.getAST().apiLevel >= AST.JLS3) {
1501                         if (!safeSubtreeMatch(node.getJavadoc(), o.getJavadoc())) {
1502                                 return false;
1503                         }
1504                         if (!safeSubtreeListMatch(node.annotations(), o.annotations())) {
1505                                 return false;
1506                         }
1507                 }
1508                 return safeSubtreeMatch(node.getName(), o.getName());
1509         }
1510
1511         /**
1512          * Returns whether the given node and the other object match.
1513          * <p>
1514          * The default implementation provided by this class tests whether the
1515          * other object is a node of the same type with structurally isomorphic
1516          * child subtrees. Subclasses may override this method as needed.
1517          * </p>
1518          * 
1519          * @param node the node
1520          * @param other the other object, or <code>null</code>
1521          * @return <code>true</code> if the subtree matches, or 
1522          *   <code>false</code> if they do not match or the other object has a
1523          *   different node type or is <code>null</code>
1524          * @since 3.1
1525          */
1526         public boolean match(ParameterizedType node, Object other) {
1527                 if (!(other instanceof ParameterizedType)) {
1528                         return false;
1529                 }
1530                 ParameterizedType o = (ParameterizedType) other;
1531                 return safeSubtreeMatch(node.getType(), o.getType())
1532                                 && safeSubtreeListMatch(node.typeArguments(), o.typeArguments());
1533         }
1534
1535         /**
1536          * Returns whether the given node and the other object match.
1537          * <p>
1538          * The default implementation provided by this class tests whether the
1539          * other object is a node of the same type with structurally isomorphic
1540          * child subtrees. Subclasses may override this method as needed.
1541          * </p>
1542          * 
1543          * @param node the node
1544          * @param other the other object, or <code>null</code>
1545          * @return <code>true</code> if the subtree matches, or 
1546          *   <code>false</code> if they do not match or the other object has a
1547          *   different node type or is <code>null</code>
1548          */
1549         public boolean match(ParenthesizedExpression node, Object other) {
1550                 if (!(other instanceof ParenthesizedExpression)) {
1551                         return false;
1552                 }
1553                 ParenthesizedExpression o = (ParenthesizedExpression) other;
1554                 return safeSubtreeMatch(node.getExpression(), o.getExpression());
1555         }
1556
1557         /**
1558          * Returns whether the given node and the other object match.
1559          * <p>
1560          * The default implementation provided by this class tests whether the
1561          * other object is a node of the same type with structurally isomorphic
1562          * child subtrees. Subclasses may override this method as needed.
1563          * </p>
1564          * 
1565          * @param node the node
1566          * @param other the other object, or <code>null</code>
1567          * @return <code>true</code> if the subtree matches, or 
1568          *   <code>false</code> if they do not match or the other object has a
1569          *   different node type or is <code>null</code>
1570          */
1571         public boolean match(PostfixExpression node, Object other) {
1572                 if (!(other instanceof PostfixExpression)) {
1573                         return false;
1574                 }
1575                 PostfixExpression o = (PostfixExpression) other;
1576                 return (
1577                         node.getOperator().equals(o.getOperator())
1578                                 && safeSubtreeMatch(node.getOperand(), o.getOperand()));
1579         }
1580
1581         /**
1582          * Returns whether the given node and the other object match.
1583          * <p>
1584          * The default implementation provided by this class tests whether the
1585          * other object is a node of the same type with structurally isomorphic
1586          * child subtrees. Subclasses may override this method as needed.
1587          * </p>
1588          * 
1589          * @param node the node
1590          * @param other the other object, or <code>null</code>
1591          * @return <code>true</code> if the subtree matches, or 
1592          *   <code>false</code> if they do not match or the other object has a
1593          *   different node type or is <code>null</code>
1594          */
1595         public boolean match(PrefixExpression node, Object other) {
1596                 if (!(other instanceof PrefixExpression)) {
1597                         return false;
1598                 }
1599                 PrefixExpression o = (PrefixExpression) other;
1600                 return (
1601                         node.getOperator().equals(o.getOperator())
1602                                 && safeSubtreeMatch(node.getOperand(), o.getOperand()));
1603         }
1604
1605         /**
1606          * Returns whether the given node and the other object match.
1607          * <p>
1608          * The default implementation provided by this class tests whether the
1609          * other object is a node of the same type with structurally isomorphic
1610          * child subtrees. Subclasses may override this method as needed.
1611          * </p>
1612          * 
1613          * @param node the node
1614          * @param other the other object, or <code>null</code>
1615          * @return <code>true</code> if the subtree matches, or 
1616          *   <code>false</code> if they do not match or the other object has a
1617          *   different node type or is <code>null</code>
1618          */
1619         public boolean match(PrimitiveType node, Object other) {
1620                 if (!(other instanceof PrimitiveType)) {
1621                         return false;
1622                 }
1623                 PrimitiveType o = (PrimitiveType) other;
1624                 return (node.getPrimitiveTypeCode() == o.getPrimitiveTypeCode());
1625         }
1626
1627         /**
1628          * Returns whether the given node and the other object match.
1629          * <p>
1630          * The default implementation provided by this class tests whether the
1631          * other object is a node of the same type with structurally isomorphic
1632          * child subtrees. Subclasses may override this method as needed.
1633          * </p>
1634          * 
1635          * @param node the node
1636          * @param other the other object, or <code>null</code>
1637          * @return <code>true</code> if the subtree matches, or 
1638          *   <code>false</code> if they do not match or the other object has a
1639          *   different node type or is <code>null</code>
1640          */
1641         public boolean match(QualifiedName node, Object other) {
1642                 if (!(other instanceof QualifiedName)) {
1643                         return false;
1644                 }
1645                 QualifiedName o = (QualifiedName) other;
1646                 return (
1647                         safeSubtreeMatch(node.getQualifier(), o.getQualifier())
1648                                 && safeSubtreeMatch(node.getName(), o.getName()));
1649         }
1650
1651         /**
1652          * Returns whether the given node and the other object match.
1653          * <p>
1654          * The default implementation provided by this class tests whether the
1655          * other object is a node of the same type with structurally isomorphic
1656          * child subtrees. Subclasses may override this method as needed.
1657          * </p>
1658          * 
1659          * @param node the node
1660          * @param other the other object, or <code>null</code>
1661          * @return <code>true</code> if the subtree matches, or 
1662          *   <code>false</code> if they do not match or the other object has a
1663          *   different node type or is <code>null</code>
1664          * @since 3.1
1665          */
1666         public boolean match(QualifiedType node, Object other) {
1667                 if (!(other instanceof QualifiedType)) {
1668                         return false;
1669                 }
1670                 QualifiedType o = (QualifiedType) other;
1671                 return (
1672                         safeSubtreeMatch(node.getQualifier(), o.getQualifier())
1673                                 && safeSubtreeMatch(node.getName(), o.getName()));
1674         }
1675
1676         /**
1677          * Returns whether the given node and the other object match.
1678          * <p>
1679          * The default implementation provided by this class tests whether the
1680          * other object is a node of the same type with structurally isomorphic
1681          * child subtrees. Subclasses may override this method as needed.
1682          * </p>
1683          * 
1684          * @param node the node
1685          * @param other the other object, or <code>null</code>
1686          * @return <code>true</code> if the subtree matches, or 
1687          *   <code>false</code> if they do not match or the other object has a
1688          *   different node type or is <code>null</code>
1689          */
1690         public boolean match(ReturnStatement node, Object other) {
1691                 if (!(other instanceof ReturnStatement)) {
1692                         return false;
1693                 }
1694                 ReturnStatement o = (ReturnStatement) other;
1695                 return safeSubtreeMatch(node.getExpression(), o.getExpression());
1696         }
1697
1698         /**
1699          * Returns whether the given node and the other object match.
1700          * <p>
1701          * The default implementation provided by this class tests whether the
1702          * other object is a node of the same type with structurally isomorphic
1703          * child subtrees. Subclasses may override this method as needed.
1704          * </p>
1705          * 
1706          * @param node the node
1707          * @param other the other object, or <code>null</code>
1708          * @return <code>true</code> if the subtree matches, or 
1709          *   <code>false</code> if they do not match or the other object has a
1710          *   different node type or is <code>null</code>
1711          */
1712         public boolean match(SimpleName node, Object other) {
1713                 if (!(other instanceof SimpleName)) {
1714                         return false;
1715                 }
1716                 SimpleName o = (SimpleName) other;
1717                 return node.getIdentifier().equals(o.getIdentifier());
1718         }
1719
1720         /**
1721          * Returns whether the given node and the other object match.
1722          * <p>
1723          * The default implementation provided by this class tests whether the
1724          * other object is a node of the same type with structurally isomorphic
1725          * child subtrees. Subclasses may override this method as needed.
1726          * </p>
1727          * 
1728          * @param node the node
1729          * @param other the other object, or <code>null</code>
1730          * @return <code>true</code> if the subtree matches, or 
1731          *   <code>false</code> if they do not match or the other object has a
1732          *   different node type or is <code>null</code>
1733          */
1734         public boolean match(SimpleType node, Object other) {
1735                 if (!(other instanceof SimpleType)) {
1736                         return false;
1737                 }
1738                 SimpleType o = (SimpleType) other;
1739                 return safeSubtreeMatch(node.getName(), o.getName());
1740         }
1741
1742         /**
1743          * Returns whether the given node and the other object match.
1744          * <p>
1745          * The default implementation provided by this class tests whether the
1746          * other object is a node of the same type with structurally isomorphic
1747          * child subtrees. Subclasses may override this method as needed.
1748          * </p>
1749          * 
1750          * @param node the node
1751          * @param other the other object, or <code>null</code>
1752          * @return <code>true</code> if the subtree matches, or 
1753          *   <code>false</code> if they do not match or the other object has a
1754          *   different node type or is <code>null</code>
1755          * @since 3.1
1756          */
1757         public boolean match(SingleMemberAnnotation node, Object other) {
1758                 if (!(other instanceof SingleMemberAnnotation)) {
1759                         return false;
1760                 }
1761                 SingleMemberAnnotation o = (SingleMemberAnnotation) other;
1762                 return (safeSubtreeMatch(node.getTypeName(), o.getTypeName())
1763                                 && safeSubtreeMatch(node.getValue(), o.getValue()));
1764         }
1765
1766         /**
1767          * Returns whether the given node and the other object match.
1768          * <p>
1769          * The default implementation provided by this class tests whether the
1770          * other object is a node of the same type with structurally isomorphic
1771          * child subtrees. Subclasses may override this method as needed.
1772          * </p>
1773          * <p>
1774          * Note that extra array dimensions and the variable arity flag 
1775          * are compared since they are both important parts of the declaration.
1776          * </p>
1777          * 
1778          * @param node the node
1779          * @param other the other object, or <code>null</code>
1780          * @return <code>true</code> if the subtree matches, or 
1781          *   <code>false</code> if they do not match or the other object has a
1782          *   different node type or is <code>null</code>
1783          */
1784         public boolean match(SingleVariableDeclaration node, Object other) {
1785                 if (!(other instanceof SingleVariableDeclaration)) {
1786                         return false;
1787                 }
1788                 SingleVariableDeclaration o = (SingleVariableDeclaration) other;
1789                 int level = node.getAST().apiLevel;
1790                 if (level == AST.JLS2_INTERNAL) {
1791                         if (node.getModifiers() != o.getModifiers()) {
1792                                 return false;
1793                         }
1794                 }
1795                 if (level >= AST.JLS3) {
1796                         if (!safeSubtreeListMatch(node.modifiers(), o.modifiers())) {
1797                                 return false;
1798                         }
1799                         if (node.isVarargs() != o.isVarargs()) {
1800                                 return false;
1801                         }
1802                 }
1803                 return 
1804                     safeSubtreeMatch(node.getType(), o.getType())
1805                                 && safeSubtreeMatch(node.getName(), o.getName())
1806                                 && node.getExtraDimensions() == o.getExtraDimensions()
1807                                 && safeSubtreeMatch(node.getInitializer(), o.getInitializer());
1808         }
1809
1810         /**
1811          * Returns whether the given node and the other object match.
1812          * <p>
1813          * The default implementation provided by this class tests whether the
1814          * other object is a node of the same type with structurally isomorphic
1815          * child subtrees. Subclasses may override this method as needed.
1816          * </p>
1817          * 
1818          * @param node the node
1819          * @param other the other object, or <code>null</code>
1820          * @return <code>true</code> if the subtree matches, or 
1821          *   <code>false</code> if they do not match or the other object has a
1822          *   different node type or is <code>null</code>
1823          */
1824         public boolean match(StringLiteral node, Object other) {
1825                 if (!(other instanceof StringLiteral)) {
1826                         return false;
1827                 }
1828                 StringLiteral o = (StringLiteral) other;
1829                 return safeEquals(node.getEscapedValue(), o.getEscapedValue());
1830         }
1831
1832         /**
1833          * Returns whether the given node and the other object match.
1834          * <p>
1835          * The default implementation provided by this class tests whether the
1836          * other object is a node of the same type with structurally isomorphic
1837          * child subtrees. Subclasses may override this method as needed.
1838          * </p>
1839          * 
1840          * @param node the node
1841          * @param other the other object, or <code>null</code>
1842          * @return <code>true</code> if the subtree matches, or 
1843          *   <code>false</code> if they do not match or the other object has a
1844          *   different node type or is <code>null</code>
1845          */
1846         public boolean match(SuperConstructorInvocation node, Object other) {
1847                 if (!(other instanceof SuperConstructorInvocation)) {
1848                         return false;
1849                 }
1850                 SuperConstructorInvocation o = (SuperConstructorInvocation) other;
1851                 if (node.getAST().apiLevel >= AST.JLS3) {
1852                         if (!safeSubtreeListMatch(node.typeArguments(), o.typeArguments())) {
1853                                 return false;
1854                         }
1855                 }
1856                 return (
1857                         safeSubtreeMatch(node.getExpression(), o.getExpression())
1858                                 && safeSubtreeListMatch(node.arguments(), o.arguments()));
1859         }
1860
1861         /**
1862          * Returns whether the given node and the other object match.
1863          * <p>
1864          * The default implementation provided by this class tests whether the
1865          * other object is a node of the same type with structurally isomorphic
1866          * child subtrees. Subclasses may override this method as needed.
1867          * </p>
1868          * 
1869          * @param node the node
1870          * @param other the other object, or <code>null</code>
1871          * @return <code>true</code> if the subtree matches, or 
1872          *   <code>false</code> if they do not match or the other object has a
1873          *   different node type or is <code>null</code>
1874          */
1875         public boolean match(SuperFieldAccess node, Object other) {
1876                 if (!(other instanceof SuperFieldAccess)) {
1877                         return false;
1878                 }
1879                 SuperFieldAccess o = (SuperFieldAccess) other;
1880                 return (
1881                         safeSubtreeMatch(node.getName(), o.getName())
1882                                 && safeSubtreeMatch(node.getQualifier(), o.getQualifier()));
1883         }
1884
1885         /**
1886          * Returns whether the given node and the other object match.
1887          * <p>
1888          * The default implementation provided by this class tests whether the
1889          * other object is a node of the same type with structurally isomorphic
1890          * child subtrees. Subclasses may override this method as needed.
1891          * </p>
1892          * 
1893          * @param node the node
1894          * @param other the other object, or <code>null</code>
1895          * @return <code>true</code> if the subtree matches, or 
1896          *   <code>false</code> if they do not match or the other object has a
1897          *   different node type or is <code>null</code>
1898          */
1899         public boolean match(SuperMethodInvocation node, Object other) {
1900                 if (!(other instanceof SuperMethodInvocation)) {
1901                         return false;
1902                 }
1903                 SuperMethodInvocation o = (SuperMethodInvocation) other;
1904                 if (node.getAST().apiLevel >= AST.JLS3) {
1905                         if (!safeSubtreeListMatch(node.typeArguments(), o.typeArguments())) {
1906                                 return false;
1907                         }
1908                 }
1909                 return (
1910                         safeSubtreeMatch(node.getQualifier(), o.getQualifier())
1911                                 && safeSubtreeMatch(node.getName(), o.getName())
1912                                 && safeSubtreeListMatch(node.arguments(), o.arguments()));
1913         }
1914
1915         /**
1916          * Returns whether the given node and the other object match.
1917          * <p>
1918          * The default implementation provided by this class tests whether the
1919          * other object is a node of the same type with structurally isomorphic
1920          * child subtrees. Subclasses may override this method as needed.
1921          * </p>
1922          * 
1923          * @param node the node
1924          * @param other the other object, or <code>null</code>
1925          * @return <code>true</code> if the subtree matches, or 
1926          *   <code>false</code> if they do not match or the other object has a
1927          *   different node type or is <code>null</code>
1928          */
1929         public boolean match(SwitchCase node, Object other) {
1930                 if (!(other instanceof SwitchCase)) {
1931                         return false;
1932                 }
1933                 SwitchCase o = (SwitchCase) other;
1934                 return safeSubtreeMatch(node.getExpression(), o.getExpression());
1935         }
1936
1937         /**
1938          * Returns whether the given node and the other object match.
1939          * <p>
1940          * The default implementation provided by this class tests whether the
1941          * other object is a node of the same type with structurally isomorphic
1942          * child subtrees. Subclasses may override this method as needed.
1943          * </p>
1944          * 
1945          * @param node the node
1946          * @param other the other object, or <code>null</code>
1947          * @return <code>true</code> if the subtree matches, or 
1948          *   <code>false</code> if they do not match or the other object has a
1949          *   different node type or is <code>null</code>
1950          */
1951         public boolean match(SwitchStatement node, Object other) {
1952                 if (!(other instanceof SwitchStatement)) {
1953                         return false;
1954                 }
1955                 SwitchStatement o = (SwitchStatement) other;
1956                 return (
1957                         safeSubtreeMatch(node.getExpression(), o.getExpression())
1958                                 && safeSubtreeListMatch(node.statements(), o.statements()));
1959         }
1960
1961         /**
1962          * Returns whether the given node and the other object match.
1963          * <p>
1964          * The default implementation provided by this class tests whether the
1965          * other object is a node of the same type with structurally isomorphic
1966          * child subtrees. Subclasses may override this method as needed.
1967          * </p>
1968          * 
1969          * @param node the node
1970          * @param other the other object, or <code>null</code>
1971          * @return <code>true</code> if the subtree matches, or 
1972          *   <code>false</code> if they do not match or the other object has a
1973          *   different node type or is <code>null</code>
1974          */
1975         public boolean match(SynchronizedStatement node, Object other) {
1976                 if (!(other instanceof SynchronizedStatement)) {
1977                         return false;
1978                 }
1979                 SynchronizedStatement o = (SynchronizedStatement) other;
1980                 return (
1981                         safeSubtreeMatch(node.getExpression(), o.getExpression())
1982                                 && safeSubtreeMatch(node.getBody(), o.getBody()));
1983         }
1984
1985         /**
1986          * Returns whether the given node and the other object match.
1987          * <p>
1988          * The default implementation provided by this class tests whether the
1989          * other object is a node of the same type with structurally isomorphic
1990          * child subtrees. Subclasses may override this method as needed.
1991          * </p>
1992          * 
1993          * @param node the node
1994          * @param other the other object, or <code>null</code>
1995          * @return <code>true</code> if the subtree matches, or 
1996          *   <code>false</code> if they do not match or the other object has a
1997          *   different node type or is <code>null</code>
1998          * @since 3.0
1999          */
2000         public boolean match(TagElement node, Object other) {
2001                 if (!(other instanceof TagElement)) {
2002                         return false;
2003                 }
2004                 TagElement o = (TagElement) other;
2005                 return (
2006                                 safeEquals(node.getTagName(), o.getTagName())
2007                                 && safeSubtreeListMatch(node.fragments(), o.fragments()));
2008         }
2009
2010         /**
2011          * Returns whether the given node and the other object match.
2012          * <p>
2013          * The default implementation provided by this class tests whether the
2014          * other object is a node of the same type with structurally isomorphic
2015          * child subtrees. Subclasses may override this method as needed.
2016          * </p>
2017          * 
2018          * @param node the node
2019          * @param other the other object, or <code>null</code>
2020          * @return <code>true</code> if the subtree matches, or 
2021          *   <code>false</code> if they do not match or the other object has a
2022          *   different node type or is <code>null</code>
2023          * @since 3.0
2024          */
2025         public boolean match(TextElement node, Object other) {
2026                 if (!(other instanceof TextElement)) {
2027                         return false;
2028                 }
2029                 TextElement o = (TextElement) other;
2030                 return safeEquals(node.getText(), o.getText());
2031         }
2032
2033         /**
2034          * Returns whether the given node and the other object match.
2035          * <p>
2036          * The default implementation provided by this class tests whether the
2037          * other object is a node of the same type with structurally isomorphic
2038          * child subtrees. Subclasses may override this method as needed.
2039          * </p>
2040          * 
2041          * @param node the node
2042          * @param other the other object, or <code>null</code>
2043          * @return <code>true</code> if the subtree matches, or 
2044          *   <code>false</code> if they do not match or the other object has a
2045          *   different node type or is <code>null</code>
2046          */
2047         public boolean match(ThisExpression node, Object other) {
2048                 if (!(other instanceof ThisExpression)) {
2049                         return false;
2050                 }
2051                 ThisExpression o = (ThisExpression) other;
2052                 return safeSubtreeMatch(node.getQualifier(), o.getQualifier());
2053         }
2054
2055         /**
2056          * Returns whether the given node and the other object match.
2057          * <p>
2058          * The default implementation provided by this class tests whether the
2059          * other object is a node of the same type with structurally isomorphic
2060          * child subtrees. Subclasses may override this method as needed.
2061          * </p>
2062          * 
2063          * @param node the node
2064          * @param other the other object, or <code>null</code>
2065          * @return <code>true</code> if the subtree matches, or 
2066          *   <code>false</code> if they do not match or the other object has a
2067          *   different node type or is <code>null</code>
2068          */
2069         public boolean match(ThrowStatement node, Object other) {
2070                 if (!(other instanceof ThrowStatement)) {
2071                         return false;
2072                 }
2073                 ThrowStatement o = (ThrowStatement) other;
2074                 return safeSubtreeMatch(node.getExpression(), o.getExpression());
2075         }
2076
2077         /**
2078          * Returns whether the given node and the other object match.
2079          * <p>
2080          * The default implementation provided by this class tests whether the
2081          * other object is a node of the same type with structurally isomorphic
2082          * child subtrees. Subclasses may override this method as needed.
2083          * </p>
2084          * 
2085          * @param node the node
2086          * @param other the other object, or <code>null</code>
2087          * @return <code>true</code> if the subtree matches, or 
2088          *   <code>false</code> if they do not match or the other object has a
2089          *   different node type or is <code>null</code>
2090          */
2091         public boolean match(TryStatement node, Object other) {
2092                 if (!(other instanceof TryStatement)) {
2093                         return false;
2094                 }
2095                 TryStatement o = (TryStatement) other;
2096                 return (
2097                         safeSubtreeMatch(node.getBody(), o.getBody())
2098                                 && safeSubtreeListMatch(node.catchClauses(), o.catchClauses())
2099                                 && safeSubtreeMatch(node.getFinally(), o.getFinally()));
2100         }
2101
2102         /**
2103          * Returns whether the given node and the other object match.
2104          * <p>
2105          * The default implementation provided by this class tests whether the
2106          * other object is a node of the same type with structurally isomorphic
2107          * child subtrees. Subclasses may override this method as needed.
2108          * </p>
2109          * 
2110          * @param node the node
2111          * @param other the other object, or <code>null</code>
2112          * @return <code>true</code> if the subtree matches, or 
2113          *   <code>false</code> if they do not match or the other object has a
2114          *   different node type or is <code>null</code>
2115          */
2116         public boolean match(TypeDeclaration node, Object other) {
2117                 if (!(other instanceof TypeDeclaration)) {
2118                         return false;
2119                 }
2120                 TypeDeclaration o = (TypeDeclaration) other;
2121                 int level = node.getAST().apiLevel;
2122                 if (level == AST.JLS2_INTERNAL) {
2123                         if (node.getModifiers() != o.getModifiers()) {
2124                                 return false;
2125                         }
2126                         if (!safeSubtreeMatch(node.internalGetSuperclass(), o.internalGetSuperclass())) {
2127                                 return false;
2128                         }
2129                         if (!safeSubtreeListMatch(node.internalSuperInterfaces(), o.internalSuperInterfaces())) {
2130                                 return false;
2131                         }
2132                 }
2133                 if (level >= AST.JLS3) {
2134                         if (!safeSubtreeListMatch(node.modifiers(), o.modifiers())) {
2135                                 return false;
2136                         }
2137                         if (!safeSubtreeListMatch(node.typeParameters(), o.typeParameters())) {
2138                                 return false;
2139                         }
2140                         if (!safeSubtreeMatch(node.getSuperclassType(), o.getSuperclassType())) {
2141                                 return false;
2142                         }
2143                         if (!safeSubtreeListMatch(node.superInterfaceTypes(), o.superInterfaceTypes())) {
2144                                 return false;
2145                         }
2146                 }
2147                 return (
2148                                 (node.isInterface() == o.isInterface())
2149                                 && safeSubtreeMatch(node.getJavadoc(), o.getJavadoc())
2150                                 && safeSubtreeMatch(node.getName(), o.getName())
2151                                 && safeSubtreeListMatch(node.bodyDeclarations(), o.bodyDeclarations()));
2152         }
2153
2154         /**
2155          * Returns whether the given node and the other object match.
2156          * <p>
2157          * The default implementation provided by this class tests whether the
2158          * other object is a node of the same type with structurally isomorphic
2159          * child subtrees. Subclasses may override this method as needed.
2160          * </p>
2161          * 
2162          * @param node the node
2163          * @param other the other object, or <code>null</code>
2164          * @return <code>true</code> if the subtree matches, or 
2165          *   <code>false</code> if they do not match or the other object has a
2166          *   different node type or is <code>null</code>
2167          */
2168         public boolean match(TypeDeclarationStatement node, Object other) {
2169                 if (!(other instanceof TypeDeclarationStatement)) {
2170                         return false;
2171                 }
2172                 TypeDeclarationStatement o = (TypeDeclarationStatement) other;
2173                 return safeSubtreeMatch(node.getDeclaration(), o.getDeclaration());
2174         }
2175
2176         /**
2177          * Returns whether the given node and the other object match.
2178          * <p>
2179          * The default implementation provided by this class tests whether the
2180          * other object is a node of the same type with structurally isomorphic
2181          * child subtrees. Subclasses may override this method as needed.
2182          * </p>
2183          * 
2184          * @param node the node
2185          * @param other the other object, or <code>null</code>
2186          * @return <code>true</code> if the subtree matches, or 
2187          *   <code>false</code> if they do not match or the other object has a
2188          *   different node type or is <code>null</code>
2189          */
2190         public boolean match(TypeLiteral node, Object other) {
2191                 if (!(other instanceof TypeLiteral)) {
2192                         return false;
2193                 }
2194                 TypeLiteral o = (TypeLiteral) other;
2195                 return safeSubtreeMatch(node.getType(), o.getType());
2196         }
2197
2198         /**
2199          * Returns whether the given node and the other object match.
2200          * <p>
2201          * The default implementation provided by this class tests whether the
2202          * other object is a node of the same type with structurally isomorphic
2203          * child subtrees. Subclasses may override this method as needed.
2204          * </p>
2205          * 
2206          * @param node the node
2207          * @param other the other object, or <code>null</code>
2208          * @return <code>true</code> if the subtree matches, or 
2209          *   <code>false</code> if they do not match or the other object has a
2210          *   different node type or is <code>null</code>
2211          * @since 3.1
2212          */
2213         public boolean match(TypeParameter node, Object other) {
2214                 if (!(other instanceof TypeParameter)) {
2215                         return false;
2216                 }
2217                 TypeParameter o = (TypeParameter) other;
2218                 return safeSubtreeMatch(node.getName(), o.getName())
2219                                 && safeSubtreeListMatch(node.typeBounds(), o.typeBounds());
2220         }
2221
2222         /**
2223          * Returns whether the given node and the other object match.
2224          * <p>
2225          * The default implementation provided by this class tests whether the
2226          * other object is a node of the same type with structurally isomorphic
2227          * child subtrees. Subclasses may override this method as needed.
2228          * </p>
2229          * 
2230          * @param node the node
2231          * @param other the other object, or <code>null</code>
2232          * @return <code>true</code> if the subtree matches, or 
2233          *   <code>false</code> if they do not match or the other object has a
2234          *   different node type or is <code>null</code>
2235          */
2236         public boolean match(VariableDeclarationExpression node, Object other) {
2237                 if (!(other instanceof VariableDeclarationExpression)) {
2238                         return false;
2239                 }
2240                 VariableDeclarationExpression o = (VariableDeclarationExpression) other;
2241                 int level = node.getAST().apiLevel;
2242                 if (level == AST.JLS2_INTERNAL) {
2243                         if (node.getModifiers() != o.getModifiers()) {
2244                                 return false;
2245                         }
2246                 }
2247                 if (level >= AST.JLS3) {
2248                         if (!safeSubtreeListMatch(node.modifiers(), o.modifiers())) {
2249                                 return false;
2250                         }
2251                 }
2252                 return safeSubtreeMatch(node.getType(), o.getType())
2253                         && safeSubtreeListMatch(node.fragments(), o.fragments());
2254         }
2255
2256         /**
2257          * Returns whether the given node and the other object match.
2258          * <p>
2259          * The default implementation provided by this class tests whether the
2260          * other object is a node of the same type with structurally isomorphic
2261          * child subtrees. Subclasses may override this method as needed.
2262          * </p>
2263          * <p>
2264          * Note that extra array dimensions are compared since they are an
2265          * important part of the type of the variable.
2266          * </p>
2267          * 
2268          * @param node the node
2269          * @param other the other object, or <code>null</code>
2270          * @return <code>true</code> if the subtree matches, or 
2271          *   <code>false</code> if they do not match or the other object has a
2272          *   different node type or is <code>null</code>
2273          */
2274         public boolean match(VariableDeclarationFragment node, Object other) {
2275                 if (!(other instanceof VariableDeclarationFragment)) {
2276                         return false;
2277                 }
2278                 VariableDeclarationFragment o = (VariableDeclarationFragment) other;
2279                 return safeSubtreeMatch(node.getName(), o.getName())
2280                         && node.getExtraDimensions() == o.getExtraDimensions()
2281                         && safeSubtreeMatch(node.getInitializer(), o.getInitializer());
2282         }
2283
2284         /**
2285          * Returns whether the given node and the other object match.
2286          * <p>
2287          * The default implementation provided by this class tests whether the
2288          * other object is a node of the same type with structurally isomorphic
2289          * child subtrees. Subclasses may override this method as needed.
2290          * </p>
2291          * 
2292          * @param node the node
2293          * @param other the other object, or <code>null</code>
2294          * @return <code>true</code> if the subtree matches, or 
2295          *   <code>false</code> if they do not match or the other object has a
2296          *   different node type or is <code>null</code>
2297          */
2298         public boolean match(VariableDeclarationStatement node, Object other) {
2299                 if (!(other instanceof VariableDeclarationStatement)) {
2300                         return false;
2301                 }
2302                 VariableDeclarationStatement o = (VariableDeclarationStatement) other;
2303                 int level = node.getAST().apiLevel;
2304                 if (level == AST.JLS2_INTERNAL) {
2305                         if (node.getModifiers() != o.getModifiers()) {
2306                                 return false;
2307                         }
2308                 }
2309                 if (level >= AST.JLS3) {
2310                         if (!safeSubtreeListMatch(node.modifiers(), o.modifiers())) {
2311                                 return false;
2312                         }
2313                 }
2314                 return safeSubtreeMatch(node.getType(), o.getType())
2315                         && safeSubtreeListMatch(node.fragments(), o.fragments());
2316         }
2317
2318         /**
2319          * Returns whether the given node and the other object match.
2320          * <p>
2321          * The default implementation provided by this class tests whether the
2322          * other object is a node of the same type with structurally isomorphic
2323          * child subtrees. Subclasses may override this method as needed.
2324          * </p>
2325          * 
2326          * @param node the node
2327          * @param other the other object, or <code>null</code>
2328          * @return <code>true</code> if the subtree matches, or 
2329          *   <code>false</code> if they do not match or the other object has a
2330          *   different node type or is <code>null</code>
2331          */
2332         public boolean match(WhileStatement node, Object other) {
2333                 if (!(other instanceof WhileStatement)) {
2334                         return false;
2335                 }
2336                 WhileStatement o = (WhileStatement) other;
2337                 return (
2338                         safeSubtreeMatch(node.getExpression(), o.getExpression())
2339                                 && safeSubtreeMatch(node.getBody(), o.getBody()));
2340         }
2341
2342         /**
2343          * Returns whether the given node and the other object match.
2344          * <p>
2345          * The default implementation provided by this class tests whether the
2346          * other object is a node of the same type with structurally isomorphic
2347          * child subtrees. Subclasses may override this method as needed.
2348          * </p>
2349          * 
2350          * @param node the node
2351          * @param other the other object, or <code>null</code>
2352          * @return <code>true</code> if the subtree matches, or 
2353          *   <code>false</code> if they do not match or the other object has a
2354          *   different node type or is <code>null</code>
2355          * @since 3.1
2356          */
2357         public boolean match(WildcardType node, Object other) {
2358                 if (!(other instanceof WildcardType)) {
2359                         return false;
2360                 }
2361                 WildcardType o = (WildcardType) other;
2362                 return node.isUpperBound() == o.isUpperBound()
2363                 && safeSubtreeMatch(node.getBound(), o.getBound());
2364         }
2365         
2366 }