001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 *  Unless required by applicable law or agreed to in writing, software
012 *  distributed under the License is distributed on an "AS IS" BASIS,
013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 *  See the License for the specific language governing permissions and
015 *  limitations under the License.
016 */
017package org.apache.bcel.classfile;
018
019import java.util.Objects;
020import java.util.Stack;
021import java.util.stream.Stream;
022
023import org.apache.commons.lang3.stream.Streams;
024
025/**
026 * Traverses a JavaClass with another Visitor object 'piggy-backed' that is applied to all components of a JavaClass
027 * object. I.e. this class supplies the traversal strategy, other classes can make use of it.
028 */
029public class DescendingVisitor implements Visitor {
030    private final JavaClass clazz;
031
032    private final Visitor visitor;
033
034    private final Stack<Object> stack = new Stack<>();
035
036    /**
037     * @param clazz Class to traverse
038     * @param visitor visitor object to apply to all components
039     */
040    public DescendingVisitor(final JavaClass clazz, final Visitor visitor) {
041        this.clazz = clazz;
042        this.visitor = visitor;
043    }
044
045    private <E extends Node> void accept(final E[] node) {
046        Streams.of(node).forEach(e -> e.accept(this));
047    }
048
049    /**
050     * @return current object
051     */
052    public Object current() {
053        return stack.peek();
054    }
055
056    /**
057     * @return container of current entitity, i.e., predecessor during traversal
058     */
059    public Object predecessor() {
060        return predecessor(0);
061    }
062
063    /**
064     * @param level nesting level, i.e., 0 returns the direct predecessor
065     * @return container of current entitity, i.e., predecessor during traversal
066     */
067    public Object predecessor(final int level) {
068        final int size = stack.size();
069        if (size < 2 || level < 0) {
070            return null;
071        }
072        return stack.elementAt(size - (level + 2)); // size - 1 == current
073    }
074
075    /**
076     * Start traversal.
077     */
078    public void visit() {
079        clazz.accept(this);
080    }
081
082    /**
083     * @since 6.0
084     */
085    @Override
086    public void visitAnnotation(final Annotations annotation) {
087        stack.push(annotation);
088        annotation.accept(visitor);
089        accept(annotation.getAnnotationEntries());
090        stack.pop();
091    }
092
093    /**
094     * @since 6.0
095     */
096    @Override
097    public void visitAnnotationDefault(final AnnotationDefault obj) {
098        stack.push(obj);
099        obj.accept(visitor);
100        stack.pop();
101    }
102
103    /**
104     * @since 6.0
105     */
106    @Override
107    public void visitAnnotationEntry(final AnnotationEntry annotationEntry) {
108        stack.push(annotationEntry);
109        annotationEntry.accept(visitor);
110        stack.pop();
111    }
112
113    /**
114     * @since 6.0
115     */
116    @Override
117    public void visitBootstrapMethods(final BootstrapMethods bm) {
118        stack.push(bm);
119        bm.accept(visitor);
120        // BootstrapMethod[] bms = bm.getBootstrapMethods();
121        // for (int i = 0; i < bms.length; i++)
122        // {
123        // bms[i].accept(this);
124        // }
125        stack.pop();
126    }
127
128    @Override
129    public void visitCode(final Code code) {
130        stack.push(code);
131        code.accept(visitor);
132        accept(code.getExceptionTable());
133        accept(code.getAttributes());
134        stack.pop();
135    }
136
137    @Override
138    public void visitCodeException(final CodeException ce) {
139        stack.push(ce);
140        ce.accept(visitor);
141        stack.pop();
142    }
143
144    @Override
145    public void visitConstantClass(final ConstantClass constant) {
146        stack.push(constant);
147        constant.accept(visitor);
148        stack.pop();
149    }
150
151    @Override
152    public void visitConstantDouble(final ConstantDouble constant) {
153        stack.push(constant);
154        constant.accept(visitor);
155        stack.pop();
156    }
157
158    /** @since 6.3 */
159    @Override
160    public void visitConstantDynamic(final ConstantDynamic obj) {
161        stack.push(obj);
162        obj.accept(visitor);
163        stack.pop();
164    }
165
166    @Override
167    public void visitConstantFieldref(final ConstantFieldref constant) {
168        stack.push(constant);
169        constant.accept(visitor);
170        stack.pop();
171    }
172
173    @Override
174    public void visitConstantFloat(final ConstantFloat constant) {
175        stack.push(constant);
176        constant.accept(visitor);
177        stack.pop();
178    }
179
180    @Override
181    public void visitConstantInteger(final ConstantInteger constant) {
182        stack.push(constant);
183        constant.accept(visitor);
184        stack.pop();
185    }
186
187    @Override
188    public void visitConstantInterfaceMethodref(final ConstantInterfaceMethodref constant) {
189        stack.push(constant);
190        constant.accept(visitor);
191        stack.pop();
192    }
193
194    /**
195     * @since 6.0
196     */
197    @Override
198    public void visitConstantInvokeDynamic(final ConstantInvokeDynamic constant) {
199        stack.push(constant);
200        constant.accept(visitor);
201        stack.pop();
202    }
203
204    @Override
205    public void visitConstantLong(final ConstantLong constant) {
206        stack.push(constant);
207        constant.accept(visitor);
208        stack.pop();
209    }
210
211    /** @since 6.0 */
212    @Override
213    public void visitConstantMethodHandle(final ConstantMethodHandle obj) {
214        stack.push(obj);
215        obj.accept(visitor);
216        stack.pop();
217    }
218
219    @Override
220    public void visitConstantMethodref(final ConstantMethodref constant) {
221        stack.push(constant);
222        constant.accept(visitor);
223        stack.pop();
224    }
225
226    /** @since 6.0 */
227    @Override
228    public void visitConstantMethodType(final ConstantMethodType obj) {
229        stack.push(obj);
230        obj.accept(visitor);
231        stack.pop();
232    }
233
234    /** @since 6.1 */
235    @Override
236    public void visitConstantModule(final ConstantModule obj) {
237        stack.push(obj);
238        obj.accept(visitor);
239        stack.pop();
240    }
241
242    @Override
243    public void visitConstantNameAndType(final ConstantNameAndType constant) {
244        stack.push(constant);
245        constant.accept(visitor);
246        stack.pop();
247    }
248
249    /** @since 6.1 */
250    @Override
251    public void visitConstantPackage(final ConstantPackage obj) {
252        stack.push(obj);
253        obj.accept(visitor);
254        stack.pop();
255    }
256
257    @Override
258    public void visitConstantPool(final ConstantPool cp) {
259        stack.push(cp);
260        cp.accept(visitor);
261        Stream.of(cp.getConstantPool()).filter(Objects::nonNull).forEach(e -> e.accept(this));
262        stack.pop();
263    }
264
265    @Override
266    public void visitConstantString(final ConstantString constant) {
267        stack.push(constant);
268        constant.accept(visitor);
269        stack.pop();
270    }
271
272    @Override
273    public void visitConstantUtf8(final ConstantUtf8 constant) {
274        stack.push(constant);
275        constant.accept(visitor);
276        stack.pop();
277    }
278
279    @Override
280    public void visitConstantValue(final ConstantValue cv) {
281        stack.push(cv);
282        cv.accept(visitor);
283        stack.pop();
284    }
285
286    @Override
287    public void visitDeprecated(final Deprecated attribute) {
288        stack.push(attribute);
289        attribute.accept(visitor);
290        stack.pop();
291    }
292
293    /**
294     * @since 6.0
295     */
296    @Override
297    public void visitEnclosingMethod(final EnclosingMethod obj) {
298        stack.push(obj);
299        obj.accept(visitor);
300        stack.pop();
301    }
302
303    @Override
304    public void visitExceptionTable(final ExceptionTable table) {
305        stack.push(table);
306        table.accept(visitor);
307        stack.pop();
308    }
309
310    @Override
311    public void visitField(final Field field) {
312        stack.push(field);
313        field.accept(visitor);
314        accept(field.getAttributes());
315        stack.pop();
316    }
317
318    @Override
319    public void visitInnerClass(final InnerClass inner) {
320        stack.push(inner);
321        inner.accept(visitor);
322        stack.pop();
323    }
324
325    @Override
326    public void visitInnerClasses(final InnerClasses ic) {
327        stack.push(ic);
328        ic.accept(visitor);
329        accept(ic.getInnerClasses());
330        stack.pop();
331    }
332
333    @Override
334    public void visitJavaClass(final JavaClass clazz) {
335        stack.push(clazz);
336        clazz.accept(visitor);
337        accept(clazz.getFields());
338        accept(clazz.getMethods());
339        accept(clazz.getAttributes());
340        clazz.getConstantPool().accept(this);
341        stack.pop();
342    }
343
344    @Override
345    public void visitLineNumber(final LineNumber number) {
346        stack.push(number);
347        number.accept(visitor);
348        stack.pop();
349    }
350
351    @Override
352    public void visitLineNumberTable(final LineNumberTable table) {
353        stack.push(table);
354        table.accept(visitor);
355        accept(table.getLineNumberTable());
356        stack.pop();
357    }
358
359    @Override
360    public void visitLocalVariable(final LocalVariable var) {
361        stack.push(var);
362        var.accept(visitor);
363        stack.pop();
364    }
365
366    @Override
367    public void visitLocalVariableTable(final LocalVariableTable table) {
368        stack.push(table);
369        table.accept(visitor);
370        accept(table.getLocalVariableTable());
371        stack.pop();
372    }
373
374    /**
375     * @since 6.0
376     */
377    @Override
378    public void visitLocalVariableTypeTable(final LocalVariableTypeTable obj) {
379        stack.push(obj);
380        obj.accept(visitor);
381        stack.pop();
382    }
383
384    @Override
385    public void visitMethod(final Method method) {
386        stack.push(method);
387        method.accept(visitor);
388        accept(method.getAttributes());
389        stack.pop();
390    }
391
392    /**
393     * @since 6.4.0
394     */
395    @Override
396    public void visitMethodParameter(final MethodParameter obj) {
397        stack.push(obj);
398        obj.accept(visitor);
399        stack.pop();
400    }
401
402    /**
403     * @since 6.0
404     */
405    @Override
406    public void visitMethodParameters(final MethodParameters obj) {
407        stack.push(obj);
408        obj.accept(visitor);
409        Stream.of(obj.getParameters()).forEach(e -> e.accept(this));
410        stack.pop();
411    }
412
413    /** @since 6.4.0 */
414    @Override
415    public void visitModule(final Module obj) {
416        stack.push(obj);
417        obj.accept(visitor);
418        accept(obj.getRequiresTable());
419        accept(obj.getExportsTable());
420        accept(obj.getOpensTable());
421        accept(obj.getProvidesTable());
422        stack.pop();
423    }
424
425    /** @since 6.4.0 */
426    @Override
427    public void visitModuleExports(final ModuleExports obj) {
428        stack.push(obj);
429        obj.accept(visitor);
430        stack.pop();
431    }
432
433    /** @since 6.4.0 */
434    @Override
435    public void visitModuleMainClass(final ModuleMainClass obj) {
436        stack.push(obj);
437        obj.accept(visitor);
438        stack.pop();
439    }
440
441    /** @since 6.4.0 */
442    @Override
443    public void visitModuleOpens(final ModuleOpens obj) {
444        stack.push(obj);
445        obj.accept(visitor);
446        stack.pop();
447    }
448
449    /** @since 6.4.0 */
450    @Override
451    public void visitModulePackages(final ModulePackages obj) {
452        stack.push(obj);
453        obj.accept(visitor);
454        stack.pop();
455    }
456
457    /** @since 6.4.0 */
458    @Override
459    public void visitModuleProvides(final ModuleProvides obj) {
460        stack.push(obj);
461        obj.accept(visitor);
462        stack.pop();
463    }
464
465    /** @since 6.4.0 */
466    @Override
467    public void visitModuleRequires(final ModuleRequires obj) {
468        stack.push(obj);
469        obj.accept(visitor);
470        stack.pop();
471    }
472
473    /** @since 6.4.0 */
474    @Override
475    public void visitNestHost(final NestHost obj) {
476        stack.push(obj);
477        obj.accept(visitor);
478        stack.pop();
479    }
480
481    /** @since 6.4.0 */
482    @Override
483    public void visitNestMembers(final NestMembers obj) {
484        stack.push(obj);
485        obj.accept(visitor);
486        stack.pop();
487    }
488
489    /**
490     * @since 6.0
491     */
492    @Override
493    public void visitParameterAnnotation(final ParameterAnnotations obj) {
494        stack.push(obj);
495        obj.accept(visitor);
496        stack.pop();
497    }
498
499    /** @since 6.0 */
500    @Override
501    public void visitParameterAnnotationEntry(final ParameterAnnotationEntry obj) {
502        stack.push(obj);
503        obj.accept(visitor);
504        stack.pop();
505    }
506
507    @Override
508    public void visitRecord(final Record record) {
509        stack.push(record);
510        record.accept(visitor);
511        accept(record.getComponents());
512        stack.pop();
513    }
514
515    @Override
516    public void visitRecordComponent(final RecordComponentInfo recordComponentInfo) {
517        stack.push(recordComponentInfo);
518        recordComponentInfo.accept(visitor);
519        stack.pop();
520    }
521
522    @Override
523    public void visitSignature(final Signature attribute) {
524        stack.push(attribute);
525        attribute.accept(visitor);
526        stack.pop();
527    }
528
529    @Override
530    public void visitSourceFile(final SourceFile attribute) {
531        stack.push(attribute);
532        attribute.accept(visitor);
533        stack.pop();
534    }
535
536    @Override
537    public void visitStackMap(final StackMap table) {
538        stack.push(table);
539        table.accept(visitor);
540        accept(table.getStackMap());
541        stack.pop();
542    }
543
544    @Override
545    public void visitStackMapEntry(final StackMapEntry var) {
546        stack.push(var);
547        var.accept(visitor);
548        accept(var.getTypesOfLocals());
549        accept(var.getTypesOfStackItems());
550        stack.pop();
551    }
552
553    /**
554     * Visits a {@link StackMapType} object.
555     * @param var object to visit
556     * @since 6.8.0
557     */
558    @Override
559    public void visitStackMapType(final StackMapType var) {
560        stack.push(var);
561        var.accept(visitor);
562        stack.pop();
563    }
564
565    @Override
566    public void visitSynthetic(final Synthetic attribute) {
567        stack.push(attribute);
568        attribute.accept(visitor);
569        stack.pop();
570    }
571
572    @Override
573    public void visitUnknown(final Unknown attribute) {
574        stack.push(attribute);
575        attribute.accept(visitor);
576        stack.pop();
577    }
578
579}