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