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