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        final ModuleOpens[] otable = obj.getOpensTable();
583        for (final ModuleOpens element : otable) {
584            element.accept(this);
585        }
586        final ModuleProvides[] ptable = obj.getProvidesTable();
587        for (final ModuleProvides element : ptable) {
588            element.accept(this);
589        }
590        stack.pop();
591    }
592
593    /** @since 6.4.0 */
594    @Override
595    public void visitModuleRequires(final ModuleRequires obj) {
596        stack.push(obj);
597        obj.accept(visitor);
598        stack.pop();
599    }
600
601    /** @since 6.4.0 */
602    @Override
603    public void visitModuleExports(final ModuleExports obj) {
604        stack.push(obj);
605        obj.accept(visitor);
606        stack.pop();
607    }
608
609    /** @since 6.4.0 */
610    @Override
611    public void visitModuleOpens(final ModuleOpens obj) {
612        stack.push(obj);
613        obj.accept(visitor);
614        stack.pop();
615    }
616
617    /** @since 6.4.0 */
618    @Override
619    public void visitModuleProvides(final ModuleProvides obj) {
620        stack.push(obj);
621        obj.accept(visitor);
622        stack.pop();
623    }
624
625    /** @since 6.4.0 */
626    @Override
627    public void visitModulePackages(final ModulePackages obj) {
628        stack.push(obj);
629        obj.accept(visitor);
630        stack.pop();
631    }
632
633    /** @since 6.4.0 */
634    @Override
635    public void visitModuleMainClass(final ModuleMainClass obj) {
636        stack.push(obj);
637        obj.accept(visitor);
638        stack.pop();
639    }
640
641    /** @since 6.4.0 */
642    @Override
643    public void visitNestHost(final NestHost obj) {
644        stack.push(obj);
645        obj.accept(visitor);
646        stack.pop();
647    }
648
649    /** @since 6.4.0 */
650    @Override
651    public void visitNestMembers(final NestMembers obj) {
652        stack.push(obj);
653        obj.accept(visitor);
654        stack.pop();
655    }
656}