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