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}