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