View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  package org.apache.bcel.classfile;
18  
19  import java.util.Objects;
20  import java.util.Stack;
21  import java.util.stream.Stream;
22  
23  /**
24   * Traverses a JavaClass with another Visitor object 'piggy-backed' that is applied to all components of a JavaClass
25   * object. I.e. this class supplies the traversal strategy, other classes can make use of it.
26   */
27  public class DescendingVisitor implements Visitor {
28      private final JavaClass clazz;
29  
30      private final Visitor visitor;
31  
32      private final Stack<Object> stack = new Stack<>();
33  
34      /**
35       * @param clazz Class to traverse
36       * @param visitor visitor object to apply to all components
37       */
38      public DescendingVisitor(final JavaClass clazz, final Visitor visitor) {
39          this.clazz = clazz;
40          this.visitor = visitor;
41      }
42  
43      private <E extends Node> void accept(final E[] node) {
44          Stream.of(node).forEach(e -> e.accept(this));
45      }
46  
47      /**
48       * @return current object
49       */
50      public Object current() {
51          return stack.peek();
52      }
53  
54      /**
55       * @return container of current entitity, i.e., predecessor during traversal
56       */
57      public Object predecessor() {
58          return predecessor(0);
59      }
60  
61      /**
62       * @param level nesting level, i.e., 0 returns the direct predecessor
63       * @return container of current entitity, i.e., predecessor during traversal
64       */
65      public Object predecessor(final int level) {
66          final int size = stack.size();
67          if (size < 2 || level < 0) {
68              return null;
69          }
70          return stack.elementAt(size - (level + 2)); // size - 1 == current
71      }
72  
73      /**
74       * Start traversal.
75       */
76      public void visit() {
77          clazz.accept(this);
78      }
79  
80      /**
81       * @since 6.0
82       */
83      @Override
84      public void visitAnnotation(final Annotations annotation) {
85          stack.push(annotation);
86          annotation.accept(visitor);
87          accept(annotation.getAnnotationEntries());
88          stack.pop();
89      }
90  
91      /**
92       * @since 6.0
93       */
94      @Override
95      public void visitAnnotationDefault(final AnnotationDefault obj) {
96          stack.push(obj);
97          obj.accept(visitor);
98          stack.pop();
99      }
100 
101     /**
102      * @since 6.0
103      */
104     @Override
105     public void visitAnnotationEntry(final AnnotationEntry annotationEntry) {
106         stack.push(annotationEntry);
107         annotationEntry.accept(visitor);
108         stack.pop();
109     }
110 
111     /**
112      * @since 6.0
113      */
114     @Override
115     public void visitBootstrapMethods(final BootstrapMethods bm) {
116         stack.push(bm);
117         bm.accept(visitor);
118         // BootstrapMethod[] bms = bm.getBootstrapMethods();
119         // for (int i = 0; i < bms.length; i++)
120         // {
121         // bms[i].accept(this);
122         // }
123         stack.pop();
124     }
125 
126     @Override
127     public void visitCode(final Code code) {
128         stack.push(code);
129         code.accept(visitor);
130         accept(code.getExceptionTable());
131         accept(code.getAttributes());
132         stack.pop();
133     }
134 
135     @Override
136     public void visitCodeException(final CodeException ce) {
137         stack.push(ce);
138         ce.accept(visitor);
139         stack.pop();
140     }
141 
142     @Override
143     public void visitConstantClass(final ConstantClass constant) {
144         stack.push(constant);
145         constant.accept(visitor);
146         stack.pop();
147     }
148 
149     @Override
150     public void visitConstantDouble(final ConstantDouble constant) {
151         stack.push(constant);
152         constant.accept(visitor);
153         stack.pop();
154     }
155 
156     /** @since 6.3 */
157     @Override
158     public void visitConstantDynamic(final ConstantDynamic obj) {
159         stack.push(obj);
160         obj.accept(visitor);
161         stack.pop();
162     }
163 
164     @Override
165     public void visitConstantFieldref(final ConstantFieldref constant) {
166         stack.push(constant);
167         constant.accept(visitor);
168         stack.pop();
169     }
170 
171     @Override
172     public void visitConstantFloat(final ConstantFloat constant) {
173         stack.push(constant);
174         constant.accept(visitor);
175         stack.pop();
176     }
177 
178     @Override
179     public void visitConstantInteger(final ConstantInteger constant) {
180         stack.push(constant);
181         constant.accept(visitor);
182         stack.pop();
183     }
184 
185     @Override
186     public void visitConstantInterfaceMethodref(final ConstantInterfaceMethodref constant) {
187         stack.push(constant);
188         constant.accept(visitor);
189         stack.pop();
190     }
191 
192     /**
193      * @since 6.0
194      */
195     @Override
196     public void visitConstantInvokeDynamic(final ConstantInvokeDynamic constant) {
197         stack.push(constant);
198         constant.accept(visitor);
199         stack.pop();
200     }
201 
202     @Override
203     public void visitConstantLong(final ConstantLong constant) {
204         stack.push(constant);
205         constant.accept(visitor);
206         stack.pop();
207     }
208 
209     /** @since 6.0 */
210     @Override
211     public void visitConstantMethodHandle(final ConstantMethodHandle obj) {
212         stack.push(obj);
213         obj.accept(visitor);
214         stack.pop();
215     }
216 
217     @Override
218     public void visitConstantMethodref(final ConstantMethodref constant) {
219         stack.push(constant);
220         constant.accept(visitor);
221         stack.pop();
222     }
223 
224     /** @since 6.0 */
225     @Override
226     public void visitConstantMethodType(final ConstantMethodType obj) {
227         stack.push(obj);
228         obj.accept(visitor);
229         stack.pop();
230     }
231 
232     /** @since 6.1 */
233     @Override
234     public void visitConstantModule(final ConstantModule obj) {
235         stack.push(obj);
236         obj.accept(visitor);
237         stack.pop();
238     }
239 
240     @Override
241     public void visitConstantNameAndType(final ConstantNameAndType constant) {
242         stack.push(constant);
243         constant.accept(visitor);
244         stack.pop();
245     }
246 
247     /** @since 6.1 */
248     @Override
249     public void visitConstantPackage(final ConstantPackage obj) {
250         stack.push(obj);
251         obj.accept(visitor);
252         stack.pop();
253     }
254 
255     @Override
256     public void visitConstantPool(final ConstantPool cp) {
257         stack.push(cp);
258         cp.accept(visitor);
259         Stream.of(cp.getConstantPool()).filter(Objects::nonNull).forEach(e -> e.accept(this));
260         stack.pop();
261     }
262 
263     @Override
264     public void visitConstantString(final ConstantString constant) {
265         stack.push(constant);
266         constant.accept(visitor);
267         stack.pop();
268     }
269 
270     @Override
271     public void visitConstantUtf8(final ConstantUtf8 constant) {
272         stack.push(constant);
273         constant.accept(visitor);
274         stack.pop();
275     }
276 
277     @Override
278     public void visitConstantValue(final ConstantValue cv) {
279         stack.push(cv);
280         cv.accept(visitor);
281         stack.pop();
282     }
283 
284     @Override
285     public void visitDeprecated(final Deprecated attribute) {
286         stack.push(attribute);
287         attribute.accept(visitor);
288         stack.pop();
289     }
290 
291     /**
292      * @since 6.0
293      */
294     @Override
295     public void visitEnclosingMethod(final EnclosingMethod obj) {
296         stack.push(obj);
297         obj.accept(visitor);
298         stack.pop();
299     }
300 
301     @Override
302     public void visitExceptionTable(final ExceptionTable table) {
303         stack.push(table);
304         table.accept(visitor);
305         stack.pop();
306     }
307 
308     @Override
309     public void visitField(final Field field) {
310         stack.push(field);
311         field.accept(visitor);
312         accept(field.getAttributes());
313         stack.pop();
314     }
315 
316     @Override
317     public void visitInnerClass(final InnerClass inner) {
318         stack.push(inner);
319         inner.accept(visitor);
320         stack.pop();
321     }
322 
323     @Override
324     public void visitInnerClasses(final InnerClasses ic) {
325         stack.push(ic);
326         ic.accept(visitor);
327         accept(ic.getInnerClasses());
328         stack.pop();
329     }
330 
331     @Override
332     public void visitJavaClass(final JavaClass clazz) {
333         stack.push(clazz);
334         clazz.accept(visitor);
335         accept(clazz.getFields());
336         accept(clazz.getMethods());
337         accept(clazz.getAttributes());
338         clazz.getConstantPool().accept(this);
339         stack.pop();
340     }
341 
342     @Override
343     public void visitLineNumber(final LineNumber number) {
344         stack.push(number);
345         number.accept(visitor);
346         stack.pop();
347     }
348 
349     @Override
350     public void visitLineNumberTable(final LineNumberTable table) {
351         stack.push(table);
352         table.accept(visitor);
353         accept(table.getLineNumberTable());
354         stack.pop();
355     }
356 
357     @Override
358     public void visitLocalVariable(final LocalVariable var) {
359         stack.push(var);
360         var.accept(visitor);
361         stack.pop();
362     }
363 
364     @Override
365     public void visitLocalVariableTable(final LocalVariableTable table) {
366         stack.push(table);
367         table.accept(visitor);
368         accept(table.getLocalVariableTable());
369         stack.pop();
370     }
371 
372     /**
373      * @since 6.0
374      */
375     @Override
376     public void visitLocalVariableTypeTable(final LocalVariableTypeTable obj) {
377         stack.push(obj);
378         obj.accept(visitor);
379         stack.pop();
380     }
381 
382     @Override
383     public void visitMethod(final Method method) {
384         stack.push(method);
385         method.accept(visitor);
386         accept(method.getAttributes());
387         stack.pop();
388     }
389 
390     /**
391      * @since 6.4.0
392      */
393     @Override
394     public void visitMethodParameter(final MethodParameter obj) {
395         stack.push(obj);
396         obj.accept(visitor);
397         stack.pop();
398     }
399 
400     /**
401      * @since 6.0
402      */
403     @Override
404     public void visitMethodParameters(final MethodParameters obj) {
405         stack.push(obj);
406         obj.accept(visitor);
407         Stream.of(obj.getParameters()).forEach(e -> e.accept(this));
408         stack.pop();
409     }
410 
411     /** @since 6.4.0 */
412     @Override
413     public void visitModule(final Module obj) {
414         stack.push(obj);
415         obj.accept(visitor);
416         accept(obj.getRequiresTable());
417         accept(obj.getExportsTable());
418         accept(obj.getOpensTable());
419         accept(obj.getProvidesTable());
420         stack.pop();
421     }
422 
423     /** @since 6.4.0 */
424     @Override
425     public void visitModuleExports(final ModuleExports obj) {
426         stack.push(obj);
427         obj.accept(visitor);
428         stack.pop();
429     }
430 
431     /** @since 6.4.0 */
432     @Override
433     public void visitModuleMainClass(final ModuleMainClass obj) {
434         stack.push(obj);
435         obj.accept(visitor);
436         stack.pop();
437     }
438 
439     /** @since 6.4.0 */
440     @Override
441     public void visitModuleOpens(final ModuleOpens obj) {
442         stack.push(obj);
443         obj.accept(visitor);
444         stack.pop();
445     }
446 
447     /** @since 6.4.0 */
448     @Override
449     public void visitModulePackages(final ModulePackages obj) {
450         stack.push(obj);
451         obj.accept(visitor);
452         stack.pop();
453     }
454 
455     /** @since 6.4.0 */
456     @Override
457     public void visitModuleProvides(final ModuleProvides obj) {
458         stack.push(obj);
459         obj.accept(visitor);
460         stack.pop();
461     }
462 
463     /** @since 6.4.0 */
464     @Override
465     public void visitModuleRequires(final ModuleRequires obj) {
466         stack.push(obj);
467         obj.accept(visitor);
468         stack.pop();
469     }
470 
471     /** @since 6.4.0 */
472     @Override
473     public void visitNestHost(final NestHost obj) {
474         stack.push(obj);
475         obj.accept(visitor);
476         stack.pop();
477     }
478 
479     /** @since 6.4.0 */
480     @Override
481     public void visitNestMembers(final NestMembers obj) {
482         stack.push(obj);
483         obj.accept(visitor);
484         stack.pop();
485     }
486 
487     /**
488      * @since 6.0
489      */
490     @Override
491     public void visitParameterAnnotation(final ParameterAnnotations obj) {
492         stack.push(obj);
493         obj.accept(visitor);
494         stack.pop();
495     }
496 
497     /** @since 6.0 */
498     @Override
499     public void visitParameterAnnotationEntry(final ParameterAnnotationEntry obj) {
500         stack.push(obj);
501         obj.accept(visitor);
502         stack.pop();
503     }
504 
505     @Override
506     public void visitSignature(final Signature attribute) {
507         stack.push(attribute);
508         attribute.accept(visitor);
509         stack.pop();
510     }
511 
512     @Override
513     public void visitSourceFile(final SourceFile attribute) {
514         stack.push(attribute);
515         attribute.accept(visitor);
516         stack.pop();
517     }
518 
519     @Override
520     public void visitStackMap(final StackMap table) {
521         stack.push(table);
522         table.accept(visitor);
523         accept(table.getStackMap());
524         stack.pop();
525     }
526 
527     @Override
528     public void visitStackMapEntry(final StackMapEntry var) {
529         stack.push(var);
530         var.accept(visitor);
531         accept(var.getTypesOfLocals());
532         accept(var.getTypesOfStackItems());
533         stack.pop();
534     }
535 
536     /**
537      * Visits a {@link StackMapType} object.
538      * @param var object to visit
539      * @since 6.8.0
540      */
541     @Override
542     public void visitStackMapType(final StackMapType var) {
543         stack.push(var);
544         var.accept(visitor);
545         stack.pop();
546     }
547 
548     @Override
549     public void visitSynthetic(final Synthetic attribute) {
550         stack.push(attribute);
551         attribute.accept(visitor);
552         stack.pop();
553     }
554 
555     @Override
556     public void visitUnknown(final Unknown attribute) {
557         stack.push(attribute);
558         attribute.accept(visitor);
559         stack.pop();
560     }
561 }