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