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 * Constructs a DescendingVisitor. 040 * 041 * @param clazz Class to traverse. 042 * @param visitor visitor object to apply to all components. 043 */ 044 public DescendingVisitor(final JavaClass clazz, final Visitor visitor) { 045 this.clazz = clazz; 046 this.visitor = visitor; 047 } 048 049 private <E extends Node> void accept(final E[] node) { 050 Streams.of(node).forEach(e -> e.accept(this)); 051 } 052 053 /** 054 * Gets the current object. 055 * 056 * @return current object. 057 */ 058 public Object current() { 059 return stack.peek(); 060 } 061 062 /** 063 * Gets the container of current entity, that is, predecessor during traversal. 064 * 065 * @return container of current entity, that is, predecessor during traversal. 066 */ 067 public Object predecessor() { 068 return predecessor(0); 069 } 070 071 /** 072 * Gets the container of current entity, that is, predecessor during traversal. 073 * 074 * @param level nesting level, that is, 0 returns the direct predecessor. 075 * @return container of current entity, that is, predecessor during traversal. 076 */ 077 public Object predecessor(final int level) { 078 final int size = stack.size(); 079 if (size < 2 || level < 0) { 080 return null; 081 } 082 return stack.elementAt(size - (level + 2)); // size - 1 == current 083 } 084 085 /** 086 * Start traversal. 087 */ 088 public void visit() { 089 clazz.accept(this); 090 } 091 092 /** 093 * @since 6.0 094 */ 095 @Override 096 public void visitAnnotation(final Annotations annotation) { 097 stack.push(annotation); 098 annotation.accept(visitor); 099 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}