001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.bcel.classfile; 018 019import java.util.Objects; 020import java.util.Stack; 021import java.util.stream.Stream; 022 023import org.apache.commons.lang3.stream.Streams; 024 025/** 026 * Traverses a JavaClass with another Visitor object 'piggy-backed' that is applied to all components of a JavaClass 027 * object. I.e. this class supplies the traversal strategy, other classes can make use of it. 028 */ 029public class DescendingVisitor implements Visitor { 030 private final JavaClass clazz; 031 032 private final Visitor visitor; 033 034 private final Stack<Object> stack = new Stack<>(); 035 036 /** 037 * @param clazz Class to traverse 038 * @param visitor visitor object to apply to all components 039 */ 040 public DescendingVisitor(final JavaClass clazz, final Visitor visitor) { 041 this.clazz = clazz; 042 this.visitor = visitor; 043 } 044 045 private <E extends Node> void accept(final E[] node) { 046 Streams.of(node).forEach(e -> e.accept(this)); 047 } 048 049 /** 050 * @return current object 051 */ 052 public Object current() { 053 return stack.peek(); 054 } 055 056 /** 057 * @return container of current entitity, i.e., predecessor during traversal 058 */ 059 public Object predecessor() { 060 return predecessor(0); 061 } 062 063 /** 064 * @param level nesting level, i.e., 0 returns the direct predecessor 065 * @return container of current entitity, i.e., predecessor during traversal 066 */ 067 public Object predecessor(final int level) { 068 final int size = stack.size(); 069 if (size < 2 || level < 0) { 070 return null; 071 } 072 return stack.elementAt(size - (level + 2)); // size - 1 == current 073 } 074 075 /** 076 * Start traversal. 077 */ 078 public void visit() { 079 clazz.accept(this); 080 } 081 082 /** 083 * @since 6.0 084 */ 085 @Override 086 public void visitAnnotation(final Annotations annotation) { 087 stack.push(annotation); 088 annotation.accept(visitor); 089 accept(annotation.getAnnotationEntries()); 090 stack.pop(); 091 } 092 093 /** 094 * @since 6.0 095 */ 096 @Override 097 public void visitAnnotationDefault(final AnnotationDefault obj) { 098 stack.push(obj); 099 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}