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