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