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