View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.bcel.classfile;
20  
21  import java.util.Objects;
22  import java.util.Stack;
23  import java.util.stream.Stream;
24  
25  import org.apache.commons.lang3.stream.Streams;
26  
27  /**
28   * Traverses a JavaClass with another Visitor object 'piggy-backed' that is applied to all components of a JavaClass
29   * object. I.e. this class supplies the traversal strategy, other classes can make use of it.
30   */
31  public class DescendingVisitor implements Visitor {
32      private final JavaClass clazz;
33  
34      private final Visitor visitor;
35  
36      private final Stack<Object> stack = new Stack<>();
37  
38      /**
39       * Constructs a DescendingVisitor.
40       *
41       * @param clazz Class to traverse.
42       * @param visitor visitor object to apply to all components.
43       */
44      public DescendingVisitor(final JavaClass clazz, final Visitor visitor) {
45          this.clazz = clazz;
46          this.visitor = visitor;
47      }
48  
49      private <E extends Node> void accept(final E[] node) {
50          Streams.of(node).forEach(e -> e.accept(this));
51      }
52  
53      /**
54       * Gets the current object.
55       *
56       * @return current object.
57       */
58      public Object current() {
59          return stack.peek();
60      }
61  
62      /**
63       * Gets the container of current entity, that is, predecessor during traversal.
64       *
65       * @return container of current entity, that is, predecessor during traversal.
66       */
67      public Object predecessor() {
68          return predecessor(0);
69      }
70  
71      /**
72       * Gets the container of current entity, that is, predecessor during traversal.
73       *
74       * @param level nesting level, that is, 0 returns the direct predecessor.
75       * @return container of current entity, that is, predecessor during traversal.
76       */
77      public Object predecessor(final int level) {
78          final int size = stack.size();
79          if (size < 2 || level < 0) {
80              return null;
81          }
82          return stack.elementAt(size - (level + 2)); // size - 1 == current
83      }
84  
85      /**
86       * Start traversal.
87       */
88      public void visit() {
89          clazz.accept(this);
90      }
91  
92      /**
93       * @since 6.0
94       */
95      @Override
96      public void visitAnnotation(final Annotations annotation) {
97          stack.push(annotation);
98          annotation.accept(visitor);
99          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 }