1/*
2 * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
3 */
4/*
5 * Licensed to the Apache Software Foundation (ASF) under one or more
6 * contributor license agreements.  See the NOTICE file distributed with
7 * this work for additional information regarding copyright ownership.
8 * The ASF licenses this file to You under the Apache License, Version 2.0
9 * (the "License"); you may not use this file except in compliance with
10 * the License.  You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20package com.sun.org.apache.bcel.internal.classfile;
21
22import java.util.Stack;
23
24/**
25 * Traverses a JavaClass with another Visitor object 'piggy-backed' that is
26 * applied to all components of a JavaClass object. I.e. this class supplies the
27 * traversal strategy, other classes can make use of it.
28 *
29 * @version $Id: DescendingVisitor.java 1749603 2016-06-21 20:50:19Z ggregory $
30 */
31public class DescendingVisitor implements Visitor {
32
33    private final JavaClass clazz;
34
35    private final Visitor visitor;
36
37    private final Stack<Object> stack = new Stack<>();
38
39    /**
40     * @return container of current entitity, i.e., predecessor during traversal
41     */
42    public Object predecessor() {
43        return predecessor(0);
44    }
45
46    /**
47     * @param level nesting level, i.e., 0 returns the direct predecessor
48     * @return container of current entitity, i.e., predecessor during traversal
49     */
50    public Object predecessor(final int level) {
51        final int size = stack.size();
52        if ((size < 2) || (level < 0)) {
53            return null;
54        }
55        return stack.elementAt(size - (level + 2)); // size - 1 == current
56    }
57
58    /**
59     * @return current object
60     */
61    public Object current() {
62        return stack.peek();
63    }
64
65    /**
66     * @param clazz Class to traverse
67     * @param visitor visitor object to apply to all components
68     */
69    public DescendingVisitor(final JavaClass clazz, final Visitor visitor) {
70        this.clazz = clazz;
71        this.visitor = visitor;
72    }
73
74    /**
75     * Start traversal.
76     */
77    public void visit() {
78        clazz.accept(this);
79    }
80
81    @Override
82    public void visitJavaClass(final JavaClass _clazz) {
83        stack.push(_clazz);
84        _clazz.accept(visitor);
85        final Field[] fields = _clazz.getFields();
86        for (final Field field : fields) {
87            field.accept(this);
88        }
89        final Method[] methods = _clazz.getMethods();
90        for (final Method method : methods) {
91            method.accept(this);
92        }
93        final Attribute[] attributes = _clazz.getAttributes();
94        for (final Attribute attribute : attributes) {
95            attribute.accept(this);
96        }
97        _clazz.getConstantPool().accept(this);
98        stack.pop();
99    }
100
101    /**
102     * @since 6.0
103     */
104    @Override
105    public void visitAnnotation(final Annotations annotation) {
106        stack.push(annotation);
107        annotation.accept(visitor);
108        final AnnotationEntry[] entries = annotation.getAnnotationEntries();
109        for (final AnnotationEntry entrie : entries) {
110            entrie.accept(this);
111        }
112        stack.pop();
113    }
114
115    /**
116     * @since 6.0
117     */
118    @Override
119    public void visitAnnotationEntry(final AnnotationEntry annotationEntry) {
120        stack.push(annotationEntry);
121        annotationEntry.accept(visitor);
122        stack.pop();
123    }
124
125    @Override
126    public void visitField(final Field field) {
127        stack.push(field);
128        field.accept(visitor);
129        final Attribute[] attributes = field.getAttributes();
130        for (final Attribute attribute : attributes) {
131            attribute.accept(this);
132        }
133        stack.pop();
134    }
135
136    @Override
137    public void visitConstantValue(final ConstantValue cv) {
138        stack.push(cv);
139        cv.accept(visitor);
140        stack.pop();
141    }
142
143    @Override
144    public void visitMethod(final Method method) {
145        stack.push(method);
146        method.accept(visitor);
147        final Attribute[] attributes = method.getAttributes();
148        for (final Attribute attribute : attributes) {
149            attribute.accept(this);
150        }
151        stack.pop();
152    }
153
154    @Override
155    public void visitExceptionTable(final ExceptionTable table) {
156        stack.push(table);
157        table.accept(visitor);
158        stack.pop();
159    }
160
161    @Override
162    public void visitCode(final Code code) {
163        stack.push(code);
164        code.accept(visitor);
165        final CodeException[] table = code.getExceptionTable();
166        for (final CodeException element : table) {
167            element.accept(this);
168        }
169        final Attribute[] attributes = code.getAttributes();
170        for (final Attribute attribute : attributes) {
171            attribute.accept(this);
172        }
173        stack.pop();
174    }
175
176    @Override
177    public void visitCodeException(final CodeException ce) {
178        stack.push(ce);
179        ce.accept(visitor);
180        stack.pop();
181    }
182
183    @Override
184    public void visitLineNumberTable(final LineNumberTable table) {
185        stack.push(table);
186        table.accept(visitor);
187        final LineNumber[] numbers = table.getLineNumberTable();
188        for (final LineNumber number : numbers) {
189            number.accept(this);
190        }
191        stack.pop();
192    }
193
194    @Override
195    public void visitLineNumber(final LineNumber number) {
196        stack.push(number);
197        number.accept(visitor);
198        stack.pop();
199    }
200
201    @Override
202    public void visitLocalVariableTable(final LocalVariableTable table) {
203        stack.push(table);
204        table.accept(visitor);
205        final LocalVariable[] vars = table.getLocalVariableTable();
206        for (final LocalVariable var : vars) {
207            var.accept(this);
208        }
209        stack.pop();
210    }
211
212    @Override
213    public void visitStackMap(final StackMap table) {
214        stack.push(table);
215        table.accept(visitor);
216        final StackMapEntry[] vars = table.getStackMap();
217        for (final StackMapEntry var : vars) {
218            var.accept(this);
219        }
220        stack.pop();
221    }
222
223    @Override
224    public void visitStackMapEntry(final StackMapEntry var) {
225        stack.push(var);
226        var.accept(visitor);
227        stack.pop();
228    }
229
230    @Override
231    public void visitLocalVariable(final LocalVariable var) {
232        stack.push(var);
233        var.accept(visitor);
234        stack.pop();
235    }
236
237    @Override
238    public void visitConstantPool(final ConstantPool cp) {
239        stack.push(cp);
240        cp.accept(visitor);
241        final Constant[] constants = cp.getConstantPool();
242        for (int i = 1; i < constants.length; i++) {
243            if (constants[i] != null) {
244                constants[i].accept(this);
245            }
246        }
247        stack.pop();
248    }
249
250    @Override
251    public void visitConstantClass(final ConstantClass constant) {
252        stack.push(constant);
253        constant.accept(visitor);
254        stack.pop();
255    }
256
257    @Override
258    public void visitConstantDouble(final ConstantDouble constant) {
259        stack.push(constant);
260        constant.accept(visitor);
261        stack.pop();
262    }
263
264    @Override
265    public void visitConstantFieldref(final ConstantFieldref constant) {
266        stack.push(constant);
267        constant.accept(visitor);
268        stack.pop();
269    }
270
271    @Override
272    public void visitConstantFloat(final ConstantFloat constant) {
273        stack.push(constant);
274        constant.accept(visitor);
275        stack.pop();
276    }
277
278    @Override
279    public void visitConstantInteger(final ConstantInteger constant) {
280        stack.push(constant);
281        constant.accept(visitor);
282        stack.pop();
283    }
284
285    @Override
286    public void visitConstantInterfaceMethodref(
287            final ConstantInterfaceMethodref constant) {
288        stack.push(constant);
289        constant.accept(visitor);
290        stack.pop();
291    }
292
293    /**
294     * @since 6.0
295     */
296    @Override
297    public void visitConstantInvokeDynamic(
298            final ConstantInvokeDynamic constant) {
299        stack.push(constant);
300        constant.accept(visitor);
301        stack.pop();
302    }
303
304    @Override
305    public void visitConstantLong(final ConstantLong constant) {
306        stack.push(constant);
307        constant.accept(visitor);
308        stack.pop();
309    }
310
311    @Override
312    public void visitConstantMethodref(final ConstantMethodref constant) {
313        stack.push(constant);
314        constant.accept(visitor);
315        stack.pop();
316    }
317
318    @Override
319    public void visitConstantNameAndType(final ConstantNameAndType constant) {
320        stack.push(constant);
321        constant.accept(visitor);
322        stack.pop();
323    }
324
325    @Override
326    public void visitConstantString(final ConstantString constant) {
327        stack.push(constant);
328        constant.accept(visitor);
329        stack.pop();
330    }
331
332    @Override
333    public void visitConstantUtf8(final ConstantUtf8 constant) {
334        stack.push(constant);
335        constant.accept(visitor);
336        stack.pop();
337    }
338
339    @Override
340    public void visitInnerClasses(final InnerClasses ic) {
341        stack.push(ic);
342        ic.accept(visitor);
343        final InnerClass[] ics = ic.getInnerClasses();
344        for (final InnerClass ic2 : ics) {
345            ic2.accept(this);
346        }
347        stack.pop();
348    }
349
350    @Override
351    public void visitInnerClass(final InnerClass inner) {
352        stack.push(inner);
353        inner.accept(visitor);
354        stack.pop();
355    }
356
357    /**
358     * @since 6.0
359     */
360    @Override
361    public void visitBootstrapMethods(final BootstrapMethods bm) {
362        stack.push(bm);
363        bm.accept(visitor);
364        // BootstrapMethod[] bms = bm.getBootstrapMethods();
365        // for (int i = 0; i < bms.length; i++)
366        // {
367        //     bms[i].accept(this);
368        // }
369        stack.pop();
370    }
371
372    @Override
373    public void visitDeprecated(final Deprecated attribute) {
374        stack.push(attribute);
375        attribute.accept(visitor);
376        stack.pop();
377    }
378
379    @Override
380    public void visitSignature(final Signature attribute) {
381        stack.push(attribute);
382        attribute.accept(visitor);
383        stack.pop();
384    }
385
386    @Override
387    public void visitSourceFile(final SourceFile attribute) {
388        stack.push(attribute);
389        attribute.accept(visitor);
390        stack.pop();
391    }
392
393    @Override
394    public void visitSynthetic(final Synthetic attribute) {
395        stack.push(attribute);
396        attribute.accept(visitor);
397        stack.pop();
398    }
399
400    @Override
401    public void visitUnknown(final Unknown attribute) {
402        stack.push(attribute);
403        attribute.accept(visitor);
404        stack.pop();
405    }
406
407    /**
408     * @since 6.0
409     */
410    @Override
411    public void visitAnnotationDefault(final AnnotationDefault obj) {
412        stack.push(obj);
413        obj.accept(visitor);
414        stack.pop();
415    }
416
417    /**
418     * @since 6.0
419     */
420    @Override
421    public void visitEnclosingMethod(final EnclosingMethod obj) {
422        stack.push(obj);
423        obj.accept(visitor);
424        stack.pop();
425    }
426
427    /**
428     * @since 6.0
429     */
430    @Override
431    public void visitLocalVariableTypeTable(final LocalVariableTypeTable obj) {
432        stack.push(obj);
433        obj.accept(visitor);
434        LocalVariable[] vars = obj.getLocalVariableTypeTable();
435        for (LocalVariable var : vars) {
436            var.accept(this);
437        }
438        stack.pop();
439    }
440
441    /**
442     * @since 6.0
443     */
444    @Override
445    public void visitParameterAnnotation(final ParameterAnnotations obj) {
446        stack.push(obj);
447        obj.accept(visitor);
448        stack.pop();
449    }
450
451    /**
452     * @since 6.0
453     */
454    @Override
455    public void visitMethodParameters(final MethodParameters obj) {
456        stack.push(obj);
457        obj.accept(visitor);
458        stack.pop();
459    }
460
461    /**
462     * @since 6.0
463     */
464    @Override
465    public void visitConstantMethodType(final ConstantMethodType obj) {
466        stack.push(obj);
467        obj.accept(visitor);
468        stack.pop();
469    }
470
471    /**
472     * @since 6.0
473     */
474    @Override
475    public void visitConstantMethodHandle(final ConstantMethodHandle obj) {
476        stack.push(obj);
477        obj.accept(visitor);
478        stack.pop();
479    }
480
481    /**
482     * @since 6.0
483     */
484    @Override
485    public void visitParameterAnnotationEntry(final ParameterAnnotationEntry obj) {
486        stack.push(obj);
487        obj.accept(visitor);
488        stack.pop();
489    }
490
491}
492