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       * @param clazz Class to traverse
40       * @param visitor visitor object to apply to all components
41       */
42      public DescendingVisitor(final JavaClass clazz, final Visitor visitor) {
43          this.clazz = clazz;
44          this.visitor = visitor;
45      }
46  
47      private <E extends Node> void accept(final E[] node) {
48          Streams.of(node).forEach(e -> e.accept(this));
49      }
50  
51      /**
52       * @return current object
53       */
54      public Object current() {
55          return stack.peek();
56      }
57  
58      /**
59       * @return container of current entitity, i.e., predecessor during traversal
60       */
61      public Object predecessor() {
62          return predecessor(0);
63      }
64  
65      /**
66       * @param level nesting level, i.e., 0 returns the direct predecessor
67       * @return container of current entitity, i.e., predecessor during traversal
68       */
69      public Object predecessor(final int level) {
70          final int size = stack.size();
71          if (size < 2 || level < 0) {
72              return null;
73          }
74          return stack.elementAt(size - (level + 2)); // size - 1 == current
75      }
76  
77      /**
78       * Start traversal.
79       */
80      public void visit() {
81          clazz.accept(this);
82      }
83  
84      /**
85       * @since 6.0
86       */
87      @Override
88      public void visitAnnotation(final Annotations annotation) {
89          stack.push(annotation);
90          annotation.accept(visitor);
91          accept(annotation.getAnnotationEntries());
92          stack.pop();
93      }
94  
95      /**
96       * @since 6.0
97       */
98      @Override
99      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 }