    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}