1 package com.sun.org.apache.bcel.internal.verifier.statics; 2 3 56 57 import com.sun.org.apache.bcel.internal.Constants; 58 import com.sun.org.apache.bcel.internal.Repository; 59 import com.sun.org.apache.bcel.internal.classfile.*; 60 import com.sun.org.apache.bcel.internal.classfile.Deprecated; import com.sun.org.apache.bcel.internal.classfile.DescendingVisitor; import com.sun.org.apache.bcel.internal.classfile.EmptyVisitor; import com.sun.org.apache.bcel.internal.classfile.Visitor; import com.sun.org.apache.bcel.internal.generic.*; 65 import com.sun.org.apache.bcel.internal.verifier.*; 66 import com.sun.org.apache.bcel.internal.verifier.exc.*; 67 import java.util.HashMap ; 68 import java.util.HashSet ; 69 70 81 public final class Pass2Verifier extends PassVerifier implements Constants{ 82 83 89 private LocalVariablesInfo[] localVariablesInfos; 90 91 92 private Verifier myOwner; 93 94 99 public Pass2Verifier(Verifier owner){ 100 myOwner = owner; 101 } 102 103 112 public LocalVariablesInfo getLocalVariablesInfo(int method_nr){ 113 if (this.verify() != VerificationResult.VR_OK) return null; if (method_nr < 0 || method_nr >= localVariablesInfos.length){ 115 throw new AssertionViolatedException("Method number out of range."); 116 } 117 return localVariablesInfos[method_nr]; 118 } 119 120 142 public VerificationResult do_verify(){ 143 VerificationResult vr1 = myOwner.doPass1(); 144 if (vr1.equals(VerificationResult.VR_OK)){ 145 146 localVariablesInfos = new LocalVariablesInfo[Repository.lookupClass(myOwner.getClassName()).getMethods().length]; 149 150 VerificationResult vr = VerificationResult.VR_OK; try{ 152 constant_pool_entries_satisfy_static_constraints(); 153 field_and_method_refs_are_valid(); 154 every_class_has_an_accessible_superclass(); 155 final_methods_are_not_overridden(); 156 } 157 catch (ClassConstraintException cce){ 158 vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, cce.getMessage()); 159 } 160 return vr; 161 } 162 else 163 return VerificationResult.VR_NOTYET; 164 } 165 166 179 private void every_class_has_an_accessible_superclass(){ 180 HashSet hs = new HashSet (); JavaClass jc = Repository.lookupClass(myOwner.getClassName()); 182 int supidx = -1; 183 184 while (supidx != 0){ 185 supidx = jc.getSuperclassNameIndex(); 186 187 if (supidx == 0){ 188 if (jc != Repository.lookupClass(Type.OBJECT.getClassName())){ 189 throw new ClassConstraintException("Superclass of '"+jc.getClassName()+"' missing but not "+Type.OBJECT.getClassName()+" itself!"); 190 } 191 } 192 else{ 193 String supername = jc.getSuperclassName(); 194 if (! hs.add(supername)){ throw new ClassConstraintException("Circular superclass hierarchy detected."); 196 } 197 Verifier v = VerifierFactory.getVerifier(supername); 198 VerificationResult vr = v.doPass1(); 199 200 if (vr != VerificationResult.VR_OK){ 201 throw new ClassConstraintException("Could not load in ancestor class '"+supername+"'."); 202 } 203 jc = Repository.lookupClass(supername); 204 205 if (jc.isFinal()){ 206 throw new ClassConstraintException("Ancestor class '"+supername+"' has the FINAL access modifier and must therefore not be subclassed."); 207 } 208 } 209 } 210 } 211 212 223 private void final_methods_are_not_overridden(){ 224 HashMap hashmap = new HashMap (); 225 JavaClass jc = Repository.lookupClass(myOwner.getClassName()); 226 227 int supidx = -1; 228 while (supidx != 0){ 229 supidx = jc.getSuperclassNameIndex(); 230 231 ConstantPoolGen cpg = new ConstantPoolGen(jc.getConstantPool()); 232 Method[] methods = jc.getMethods(); 233 for (int i=0; i<methods.length; i++){ 234 String name_and_sig = (methods[i].getName()+methods[i].getSignature()); 235 236 if (hashmap.containsKey(name_and_sig)){ 237 if (methods[i].isFinal()){ 238 throw new ClassConstraintException("Method '"+name_and_sig+"' in class '"+hashmap.get(name_and_sig)+"' overrides the final (not-overridable) definition in class '"+jc.getClassName()+"'."); 239 } 240 else{ 241 if (!methods[i].isStatic()){ hashmap.put(name_and_sig, jc.getClassName()); 243 } 244 } 245 } 246 else{ 247 if (!methods[i].isStatic()){ hashmap.put(name_and_sig, jc.getClassName()); 249 } 250 } 251 } 252 253 jc = Repository.lookupClass(jc.getSuperclassName()); } 255 256 } 257 258 264 private void constant_pool_entries_satisfy_static_constraints(){ 265 JavaClass jc = Repository.lookupClass(myOwner.getClassName()); 269 new CPESSC_Visitor(jc); } 271 272 279 private class CPESSC_Visitor extends com.sun.org.apache.bcel.internal.classfile.EmptyVisitor implements Visitor{ 280 private Class CONST_Class; 281 private Class CONST_Fieldref; 282 private Class CONST_Methodref; 283 private Class CONST_InterfaceMethodref; 284 private Class CONST_String; 285 private Class CONST_Integer; 286 private Class CONST_Float; 287 private Class CONST_Long; 288 private Class CONST_Double; 289 private Class CONST_NameAndType; 290 private Class CONST_Utf8; 291 292 private final JavaClass jc; 293 private final ConstantPool cp; private final int cplen; private DescendingVisitor carrier; 296 297 private HashSet field_names = new HashSet (); 298 private HashSet field_names_and_desc = new HashSet (); 299 private HashSet method_names_and_desc = new HashSet (); 300 301 private CPESSC_Visitor(JavaClass _jc){ 302 jc = _jc; 303 cp = _jc.getConstantPool(); 304 cplen = cp.getLength(); 305 306 CONST_Class = com.sun.org.apache.bcel.internal.classfile.ConstantClass.class; 307 CONST_Fieldref = com.sun.org.apache.bcel.internal.classfile.ConstantFieldref.class; 308 CONST_Methodref = com.sun.org.apache.bcel.internal.classfile.ConstantMethodref.class; 309 CONST_InterfaceMethodref = com.sun.org.apache.bcel.internal.classfile.ConstantInterfaceMethodref.class; 310 CONST_String = com.sun.org.apache.bcel.internal.classfile.ConstantString.class; 311 CONST_Integer = com.sun.org.apache.bcel.internal.classfile.ConstantInteger.class; 312 CONST_Float = com.sun.org.apache.bcel.internal.classfile.ConstantFloat.class; 313 CONST_Long = com.sun.org.apache.bcel.internal.classfile.ConstantLong.class; 314 CONST_Double = com.sun.org.apache.bcel.internal.classfile.ConstantDouble.class; 315 CONST_NameAndType = com.sun.org.apache.bcel.internal.classfile.ConstantNameAndType.class; 316 CONST_Utf8 = com.sun.org.apache.bcel.internal.classfile.ConstantUtf8.class; 317 318 carrier = new DescendingVisitor(_jc, this); 319 carrier.visit(); 320 } 321 322 private void checkIndex(Node referrer, int index, Class shouldbe){ 323 if ((index < 0) || (index >= cplen)){ 324 throw new ClassConstraintException("Invalid index '"+index+"' used by '"+tostring(referrer)+"'."); 325 } 326 Constant c = cp.getConstant(index); 327 if (! shouldbe.isInstance(c)){ 328 String isnot = shouldbe.toString().substring(shouldbe.toString().lastIndexOf(".")+1); throw new ClassCastException ("Illegal constant '"+tostring(c)+"' at index '"+index+"'. '"+tostring(referrer)+"' expects a '"+shouldbe+"'."); 330 } 331 } 332 public void visitJavaClass(JavaClass obj){ 336 Attribute[] atts = obj.getAttributes(); 337 boolean foundSourceFile = false; 338 boolean foundInnerClasses = false; 339 340 boolean hasInnerClass = new InnerClassDetector(jc).innerClassReferenced(); 343 344 for (int i=0; i<atts.length; i++){ 345 if ((! (atts[i] instanceof SourceFile)) && 346 (! (atts[i] instanceof Deprecated )) && 347 (! (atts[i] instanceof InnerClasses)) && 348 (! (atts[i] instanceof Synthetic))){ 349 addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of the ClassFile structure '"+tostring(obj)+"' is unknown and will therefore be ignored."); 350 } 351 352 if (atts[i] instanceof SourceFile){ 353 if (foundSourceFile == false) foundSourceFile = true; 354 else throw new ClassConstraintException("A ClassFile structure (like '"+tostring(obj)+"') may have no more than one SourceFile attribute."); } 356 357 if (atts[i] instanceof InnerClasses){ 358 if (foundInnerClasses == false) foundInnerClasses = true; 359 else{ 360 if (hasInnerClass){ 361 throw new ClassConstraintException("A Classfile structure (like '"+tostring(obj)+"') must have exactly one InnerClasses attribute if at least one Inner Class is referenced (which is the case). More than one InnerClasses attribute was found."); 362 } 363 } 364 if (!hasInnerClass){ 365 addMessage("No referenced Inner Class found, but InnerClasses attribute '"+tostring(atts[i])+"' found. Strongly suggest removal of that attribute."); 366 } 367 } 368 369 } 370 if (hasInnerClass && !foundInnerClasses){ 371 addMessage("A Classfile structure (like '"+tostring(obj)+"') must have exactly one InnerClasses attribute if at least one Inner Class is referenced (which is the case). No InnerClasses attribute was found."); 376 } 377 } 378 public void visitConstantClass(ConstantClass obj){ 382 if (obj.getTag() != Constants.CONSTANT_Class){ 383 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 384 } 385 checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 386 387 } 388 public void visitConstantFieldref(ConstantFieldref obj){ 389 if (obj.getTag() != Constants.CONSTANT_Fieldref){ 390 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 391 } 392 checkIndex(obj, obj.getClassIndex(), CONST_Class); 393 checkIndex(obj, obj.getNameAndTypeIndex(), CONST_NameAndType); 394 } 395 public void visitConstantMethodref(ConstantMethodref obj){ 396 if (obj.getTag() != Constants.CONSTANT_Methodref){ 397 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 398 } 399 checkIndex(obj, obj.getClassIndex(), CONST_Class); 400 checkIndex(obj, obj.getNameAndTypeIndex(), CONST_NameAndType); 401 } 402 public void visitConstantInterfaceMethodref(ConstantInterfaceMethodref obj){ 403 if (obj.getTag() != Constants.CONSTANT_InterfaceMethodref){ 404 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 405 } 406 checkIndex(obj, obj.getClassIndex(), CONST_Class); 407 checkIndex(obj, obj.getNameAndTypeIndex(), CONST_NameAndType); 408 } 409 public void visitConstantString(ConstantString obj){ 410 if (obj.getTag() != Constants.CONSTANT_String){ 411 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 412 } 413 checkIndex(obj, obj.getStringIndex(), CONST_Utf8); 414 } 415 public void visitConstantInteger(ConstantInteger obj){ 416 if (obj.getTag() != Constants.CONSTANT_Integer){ 417 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 418 } 419 } 421 public void visitConstantFloat(ConstantFloat obj){ 422 if (obj.getTag() != Constants.CONSTANT_Float){ 423 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 424 } 425 } 427 public void visitConstantLong(ConstantLong obj){ 428 if (obj.getTag() != Constants.CONSTANT_Long){ 429 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 430 } 431 } 433 public void visitConstantDouble(ConstantDouble obj){ 434 if (obj.getTag() != Constants.CONSTANT_Double){ 435 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 436 } 437 } 439 public void visitConstantNameAndType(ConstantNameAndType obj){ 440 if (obj.getTag() != Constants.CONSTANT_NameAndType){ 441 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 442 } 443 checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 444 checkIndex(obj, obj.getSignatureIndex(), CONST_Utf8); 446 } 447 public void visitConstantUtf8(ConstantUtf8 obj){ 448 if (obj.getTag() != Constants.CONSTANT_Utf8){ 449 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 450 } 451 } 453 public void visitField(Field obj){ 457 458 if (jc.isClass()){ 459 int maxone=0; 460 if (obj.isPrivate()) maxone++; 461 if (obj.isProtected()) maxone++; 462 if (obj.isPublic()) maxone++; 463 if (maxone > 1){ 464 throw new ClassConstraintException("Field '"+tostring(obj)+"' must only have at most one of its ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC modifiers set."); 465 } 466 467 if (obj.isFinal() && obj.isVolatile()){ 468 throw new ClassConstraintException("Field '"+tostring(obj)+"' must only have at most one of its ACC_FINAL, ACC_VOLATILE modifiers set."); 469 } 470 } 471 else{ if (!obj.isPublic()){ 473 throw new ClassConstraintException("Interface field '"+tostring(obj)+"' must have the ACC_PUBLIC modifier set but hasn't!"); 474 } 475 if (!obj.isStatic()){ 476 throw new ClassConstraintException("Interface field '"+tostring(obj)+"' must have the ACC_STATIC modifier set but hasn't!"); 477 } 478 if (!obj.isFinal()){ 479 throw new ClassConstraintException("Interface field '"+tostring(obj)+"' must have the ACC_FINAL modifier set but hasn't!"); 480 } 481 } 482 483 if ((obj.getAccessFlags() & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_VOLATILE|ACC_TRANSIENT)) > 0){ 484 addMessage("Field '"+tostring(obj)+"' has access flag(s) other than ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_VOLATILE, ACC_TRANSIENT set (ignored)."); 485 } 486 487 checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 488 489 String name = obj.getName(); 490 if (! validFieldName(name)){ 491 throw new ClassConstraintException("Field '"+tostring(obj)+"' has illegal name '"+obj.getName()+"'."); 492 } 493 494 checkIndex(obj, obj.getSignatureIndex(), CONST_Utf8); 496 497 String sig = ((ConstantUtf8) (cp.getConstant(obj.getSignatureIndex()))).getBytes(); 499 try{ 500 Type t = Type.getType(sig); 501 } 502 catch (ClassFormatError cfe){ throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'."); 504 } 505 506 String nameanddesc = (name+sig); 507 if (field_names_and_desc.contains(nameanddesc)){ 508 throw new ClassConstraintException("No two fields (like '"+tostring(obj)+"') are allowed have same names and descriptors!"); 509 } 510 if (field_names.contains(name)){ 511 addMessage("More than one field of name '"+name+"' detected (but with different type descriptors). This is very unusual."); 512 } 513 field_names_and_desc.add(nameanddesc); 514 field_names.add(name); 515 516 Attribute[] atts = obj.getAttributes(); 517 for (int i=0; i<atts.length; i++){ 518 if ((! (atts[i] instanceof ConstantValue)) && 519 (! (atts[i] instanceof Synthetic)) && 520 (! (atts[i] instanceof Deprecated ))){ 521 addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Field '"+tostring(obj)+"' is unknown and will therefore be ignored."); 522 } 523 if (! (atts[i] instanceof ConstantValue)){ 524 addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Field '"+tostring(obj)+"' is not a ConstantValue and is therefore only of use for debuggers and such."); 525 } 526 } 527 } 528 public void visitMethod(Method obj){ 532 533 checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 534 535 String name = obj.getName(); 536 if (! validMethodName(name, true)){ 537 throw new ClassConstraintException("Method '"+tostring(obj)+"' has illegal name '"+name+"'."); 538 } 539 540 checkIndex(obj, obj.getSignatureIndex(), CONST_Utf8); 542 543 String sig = ((ConstantUtf8) (cp.getConstant(obj.getSignatureIndex()))).getBytes(); 545 Type t; 546 Type[] ts; try{ 548 t = Type.getReturnType(sig); 549 ts = Type.getArgumentTypes(sig); 550 } 551 catch (ClassFormatError cfe){ 552 throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by Method '"+tostring(obj)+"'."); 554 } 555 556 Type act = t; 558 if (act instanceof ArrayType) act = ((ArrayType) act).getBasicType(); 559 if (act instanceof ObjectType){ 560 Verifier v = VerifierFactory.getVerifier( ((ObjectType) act).getClassName() ); 561 VerificationResult vr = v.doPass1(); 562 if (vr != VerificationResult.VR_OK) { 563 throw new ClassConstraintException("Method '"+tostring(obj)+"' has a return type that does not pass verification pass 1: '"+vr+"'."); 564 } 565 } 566 567 for (int i=0; i<ts.length; i++){ 568 act = ts[i]; 569 if (act instanceof ArrayType) act = ((ArrayType) act).getBasicType(); 570 if (act instanceof ObjectType){ 571 Verifier v = VerifierFactory.getVerifier( ((ObjectType) act).getClassName() ); 572 VerificationResult vr = v.doPass1(); 573 if (vr != VerificationResult.VR_OK) { 574 throw new ClassConstraintException("Method '"+tostring(obj)+"' has an argument type that does not pass verification pass 1: '"+vr+"'."); 575 } 576 } 577 } 578 579 if (name.equals(STATIC_INITIALIZER_NAME) && (ts.length != 0)){ 581 throw new ClassConstraintException("Method '"+tostring(obj)+"' has illegal name '"+name+"'. It's name resembles the class or interface initialization method which it isn't because of its arguments (==descriptor)."); 582 } 583 584 if (jc.isClass()){ 585 int maxone=0; 586 if (obj.isPrivate()) maxone++; 587 if (obj.isProtected()) maxone++; 588 if (obj.isPublic()) maxone++; 589 if (maxone > 1){ 590 throw new ClassConstraintException("Method '"+tostring(obj)+"' must only have at most one of its ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC modifiers set."); 591 } 592 593 if (obj.isAbstract()){ 594 if (obj.isFinal()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_FINAL modifier set."); 595 if (obj.isNative()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_NATIVE modifier set."); 596 if (obj.isPrivate()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_PRIVATE modifier set."); 597 if (obj.isStatic()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_STATIC modifier set."); 598 if (obj.isStrictfp()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_STRICT modifier set."); 599 if (obj.isSynchronized()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_SYNCHRONIZED modifier set."); 600 } 601 } 602 else{ if (!name.equals(STATIC_INITIALIZER_NAME)){ if (!obj.isPublic()){ 605 throw new ClassConstraintException("Interface method '"+tostring(obj)+"' must have the ACC_PUBLIC modifier set but hasn't!"); 606 } 607 if (!obj.isAbstract()){ 608 throw new ClassConstraintException("Interface method '"+tostring(obj)+"' must have the ACC_STATIC modifier set but hasn't!"); 609 } 610 if ( obj.isPrivate() || 611 obj.isProtected() || 612 obj.isStatic() || 613 obj.isFinal() || 614 obj.isSynchronized() || 615 obj.isNative() || 616 obj.isStrictfp() ){ 617 throw new ClassConstraintException("Interface method '"+tostring(obj)+"' must not have any of the ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT, ACC_STRICT modifiers set."); 618 } 619 } 620 } 621 622 if (name.equals(CONSTRUCTOR_NAME)){ 624 if ( obj.isStatic() || 627 obj.isFinal() || 628 obj.isSynchronized() || 629 obj.isNative() || 630 obj.isAbstract() ){ 631 throw new ClassConstraintException("Instance initialization method '"+tostring(obj)+"' must not have any of the ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT modifiers set."); 632 } 633 } 634 635 if (name.equals(STATIC_INITIALIZER_NAME)){ 637 if ((obj.getAccessFlags() & (~ACC_STRICT)) > 0){ 638 addMessage("Class or interface initialization method '"+tostring(obj)+"' has superfluous access modifier(s) set: everything but ACC_STRICT is ignored."); 639 } 640 if (obj.isAbstract()){ 641 throw new ClassConstraintException("Class or interface initialization method '"+tostring(obj)+"' must not be abstract. This contradicts the Java Language Specification, Second Edition (which omits this constraint) but is common practice of existing verifiers."); 642 } 643 } 644 645 if ((obj.getAccessFlags() & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_SYNCHRONIZED|ACC_NATIVE|ACC_ABSTRACT|ACC_STRICT)) > 0){ 646 addMessage("Method '"+tostring(obj)+"' has access flag(s) other than ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT, ACC_STRICT set (ignored)."); 647 } 648 649 String nameanddesc = (name+sig); 650 if (method_names_and_desc.contains(nameanddesc)){ 651 throw new ClassConstraintException("No two methods (like '"+tostring(obj)+"') are allowed have same names and desciptors!"); 652 } 653 method_names_and_desc.add(nameanddesc); 654 655 Attribute[] atts = obj.getAttributes(); 656 int num_code_atts = 0; 657 for (int i=0; i<atts.length; i++){ 658 if ((! (atts[i] instanceof Code)) && 659 (! (atts[i] instanceof ExceptionTable)) && 660 (! (atts[i] instanceof Synthetic)) && 661 (! (atts[i] instanceof Deprecated ))){ 662 addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Method '"+tostring(obj)+"' is unknown and will therefore be ignored."); 663 } 664 if ((! (atts[i] instanceof Code)) && 665 (! (atts[i] instanceof ExceptionTable))){ 666 addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Method '"+tostring(obj)+"' is neither Code nor Exceptions and is therefore only of use for debuggers and such."); 667 } 668 if ((atts[i] instanceof Code) && (obj.isNative() || obj.isAbstract())){ 669 throw new ClassConstraintException("Native or abstract methods like '"+tostring(obj)+"' must not have a Code attribute like '"+tostring(atts[i])+"'."); } 671 if (atts[i] instanceof Code) num_code_atts++; 672 } 673 if ( !obj.isNative() && !obj.isAbstract() && num_code_atts != 1){ 674 throw new ClassConstraintException("Non-native, non-abstract methods like '"+tostring(obj)+"' must have exactly one Code attribute (found: "+num_code_atts+")."); 675 } 676 } 677 public void visitSourceFile(SourceFile obj){ 682 684 checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 685 686 String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); 687 if (! name.equals("SourceFile")){ 688 throw new ClassConstraintException("The SourceFile attribute '"+tostring(obj)+"' is not correctly named 'SourceFile' but '"+name+"'."); 689 } 690 691 checkIndex(obj, obj.getSourceFileIndex(), CONST_Utf8); 692 693 String sourcefilename = ((ConstantUtf8) cp.getConstant(obj.getSourceFileIndex())).getBytes(); String sourcefilenamelc = sourcefilename.toLowerCase(); 695 696 if ( (sourcefilename.indexOf('/') != -1) || 697 (sourcefilename.indexOf('\\') != -1) || 698 (sourcefilename.indexOf(':') != -1) || 699 (sourcefilenamelc.lastIndexOf(".java") == -1) ){ 700 addMessage("SourceFile attribute '"+tostring(obj)+"' has a funny name: remember not to confuse certain parsers working on javap's output. Also, this name ('"+sourcefilename+"') is considered an unqualified (simple) file name only."); 701 } 702 } 703 public void visitDeprecated(Deprecated obj){ checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 705 706 String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); 707 if (! name.equals("Deprecated")){ 708 throw new ClassConstraintException("The Deprecated attribute '"+tostring(obj)+"' is not correctly named 'Deprecated' but '"+name+"'."); 709 } 710 } 711 public void visitSynthetic(Synthetic obj){ checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 713 String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); 714 if (! name.equals("Synthetic")){ 715 throw new ClassConstraintException("The Synthetic attribute '"+tostring(obj)+"' is not correctly named 'Synthetic' but '"+name+"'."); 716 } 717 } 718 public void visitInnerClasses(InnerClasses obj){ 720 722 checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 723 724 String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); 725 if (! name.equals("InnerClasses")){ 726 throw new ClassConstraintException("The InnerClasses attribute '"+tostring(obj)+"' is not correctly named 'InnerClasses' but '"+name+"'."); 727 } 728 729 InnerClass[] ics = obj.getInnerClasses(); 730 731 for (int i=0; i<ics.length; i++){ 732 checkIndex(obj, ics[i].getInnerClassIndex(), CONST_Class); 733 int outer_idx = ics[i].getOuterClassIndex(); 734 if (outer_idx != 0){ 735 checkIndex(obj, outer_idx, CONST_Class); 736 } 737 int innername_idx = ics[i].getInnerNameIndex(); 738 if (innername_idx != 0){ 739 checkIndex(obj, innername_idx, CONST_Utf8); 740 } 741 int acc = ics[i].getInnerAccessFlags(); 742 acc = acc & (~ (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT)); 743 if (acc != 0){ 744 addMessage("Unknown access flag for inner class '"+tostring(ics[i])+"' set (InnerClasses attribute '"+tostring(obj)+"')."); 745 } 746 } 747 } 750 public void visitConstantValue(ConstantValue obj){ checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 757 758 String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); 759 if (! name.equals("ConstantValue")){ 760 throw new ClassConstraintException("The ConstantValue attribute '"+tostring(obj)+"' is not correctly named 'ConstantValue' but '"+name+"'."); 761 } 762 763 Object pred = carrier.predecessor(); 764 if (pred instanceof Field){ Field f = (Field) pred; 766 Type field_type = Type.getType(((ConstantUtf8) (cp.getConstant(f.getSignatureIndex()))).getBytes()); 768 769 int index = obj.getConstantValueIndex(); 770 if ((index < 0) || (index >= cplen)){ 771 throw new ClassConstraintException("Invalid index '"+index+"' used by '"+tostring(obj)+"'."); 772 } 773 Constant c = cp.getConstant(index); 774 775 if (CONST_Long.isInstance(c) && field_type.equals(Type.LONG)){ 776 return; 777 } 778 if (CONST_Float.isInstance(c) && field_type.equals(Type.FLOAT)){ 779 return; 780 } 781 if (CONST_Double.isInstance(c) && field_type.equals(Type.DOUBLE)){ 782 return; 783 } 784 if (CONST_Integer.isInstance(c) && (field_type.equals(Type.INT) || field_type.equals(Type.SHORT) || field_type.equals(Type.CHAR) || field_type.equals(Type.BYTE) || field_type.equals(Type.BOOLEAN))){ 785 return; 786 } 787 if (CONST_String.isInstance(c) && field_type.equals(Type.STRING)){ 788 return; 789 } 790 791 throw new ClassConstraintException("Illegal type of ConstantValue '"+obj+"' embedding Constant '"+c+"'. It is referenced by field '"+tostring(f)+"' expecting a different type: '"+field_type+"'."); 792 } 793 } 794 public void visitCode(Code obj){ 803 checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 804 805 String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); 806 if (! name.equals("Code")){ 807 throw new ClassConstraintException("The Code attribute '"+tostring(obj)+"' is not correctly named 'Code' but '"+name+"'."); 808 } 809 810 Method m = null; if (!(carrier.predecessor() instanceof Method)){ 812 addMessage("Code attribute '"+tostring(obj)+"' is not declared in a method_info structure but in '"+carrier.predecessor()+"'. Ignored."); 813 return; 814 } 815 else{ 816 m = (Method) carrier.predecessor(); } 819 820 if (obj.getCode().length == 0){ 821 throw new ClassConstraintException("Code array of Code attribute '"+tostring(obj)+"' (method '"+m+"') must not be empty."); 822 } 823 824 CodeException[] exc_table = obj.getExceptionTable(); 826 for (int i=0; i<exc_table.length; i++){ 827 int exc_index = exc_table[i].getCatchType(); 828 if (exc_index != 0){ checkIndex(obj, exc_index, CONST_Class); 830 ConstantClass cc = (ConstantClass) (cp.getConstant(exc_index)); 831 checkIndex(cc, cc.getNameIndex(), CONST_Utf8); String cname = ((ConstantUtf8) cp.getConstant(cc.getNameIndex())).getBytes().replace('/','.'); 833 834 Verifier v = VerifierFactory.getVerifier(cname); 835 VerificationResult vr = v.doPass1(); 836 837 if (vr != VerificationResult.VR_OK){ 838 throw new ClassConstraintException("Code attribute '"+tostring(obj)+"' (method '"+m+"') has an exception_table entry '"+tostring(exc_table[i])+"' that references '"+cname+"' as an Exception but it does not pass verification pass 1: "+vr); 839 } 840 else{ 841 JavaClass e = Repository.lookupClass(cname); 844 JavaClass t = Repository.lookupClass(Type.THROWABLE.getClassName()); 845 JavaClass o = Repository.lookupClass(Type.OBJECT.getClassName()); 846 while (e != o){ 847 if (e == t) break; 849 v = VerifierFactory.getVerifier(e.getSuperclassName()); 850 vr = v.doPass1(); 851 if (vr != VerificationResult.VR_OK){ 852 throw new ClassConstraintException("Code attribute '"+tostring(obj)+"' (method '"+m+"') has an exception_table entry '"+tostring(exc_table[i])+"' that references '"+cname+"' as an Exception but '"+e.getSuperclassName()+"' in the ancestor hierachy does not pass verification pass 1: "+vr); 853 } 854 else{ 855 e = Repository.lookupClass(e.getSuperclassName()); 856 } 857 } 858 if (e != t) throw new ClassConstraintException("Code attribute '"+tostring(obj)+"' (method '"+m+"') has an exception_table entry '"+tostring(exc_table[i])+"' that references '"+cname+"' as an Exception but it is not a subclass of '"+t.getClassName()+"'."); 859 } 860 } 861 } 862 863 int method_number = -1; 867 Method[] ms = Repository.lookupClass(myOwner.getClassName()).getMethods(); 868 for (int mn=0; mn<ms.length; mn++){ 869 if (m == ms[mn]){ 870 method_number = mn; 871 break; 872 } 873 } 874 if (method_number < 0){ throw new AssertionViolatedException("Could not find a known BCEL Method object in the corresponding BCEL JavaClass object."); 876 } 877 localVariablesInfos[method_number] = new LocalVariablesInfo(obj.getMaxLocals()); 878 879 int num_of_lvt_attribs = 0; 880 Attribute[] atts = obj.getAttributes(); 882 for (int a=0; a<atts.length; a++){ 883 if ((! (atts[a] instanceof LineNumberTable)) && 884 (! (atts[a] instanceof LocalVariableTable))){ 885 addMessage("Attribute '"+tostring(atts[a])+"' as an attribute of Code attribute '"+tostring(obj)+"' (method '"+m+"') is unknown and will therefore be ignored."); 886 } 887 else{ addMessage("Attribute '"+tostring(atts[a])+"' as an attribute of Code attribute '"+tostring(obj)+"' (method '"+m+"') will effectively be ignored and is only useful for debuggers and such."); 889 } 890 891 if (atts[a] instanceof LocalVariableTable){ 897 LocalVariableTable lvt = (LocalVariableTable) atts[a]; 898 899 checkIndex(lvt, lvt.getNameIndex(), CONST_Utf8); 900 901 String lvtname = ((ConstantUtf8) cp.getConstant(lvt.getNameIndex())).getBytes(); 902 if (! lvtname.equals("LocalVariableTable")){ 903 throw new ClassConstraintException("The LocalVariableTable attribute '"+tostring(lvt)+"' is not correctly named 'LocalVariableTable' but '"+lvtname+"'."); 904 } 905 906 Code code = obj; 907 int max_locals = code.getMaxLocals(); 908 909 LocalVariable[] localvariables = lvt.getLocalVariableTable(); 911 912 for (int i=0; i<localvariables.length; i++){ 913 checkIndex(lvt, localvariables[i].getNameIndex(), CONST_Utf8); 914 String localname = ((ConstantUtf8) cp.getConstant(localvariables[i].getNameIndex())).getBytes(); 915 if (!validJavaIdentifier(localname)){ 916 throw new ClassConstraintException("LocalVariableTable '"+tostring(lvt)+"' references a local variable by the name '"+localname+"' which is not a legal Java simple name."); 917 } 918 919 checkIndex(lvt, localvariables[i].getSignatureIndex(), CONST_Utf8); 920 String localsig = ((ConstantUtf8) (cp.getConstant(localvariables[i].getSignatureIndex()))).getBytes(); Type t; 922 try{ 923 t = Type.getType(localsig); 924 } 925 catch (ClassFormatError cfe){ throw new ClassConstraintException("Illegal descriptor (==signature) '"+localsig+"' used by LocalVariable '"+tostring(localvariables[i])+"' referenced by '"+tostring(lvt)+"'."); 927 } 928 int localindex = localvariables[i].getIndex(); 929 if ( ( (t==Type.LONG || t==Type.DOUBLE)? localindex+1:localindex) >= code.getMaxLocals()){ 930 throw new ClassConstraintException("LocalVariableTable attribute '"+tostring(lvt)+"' references a LocalVariable '"+tostring(localvariables[i])+"' with an index that exceeds the surrounding Code attribute's max_locals value of '"+code.getMaxLocals()+"'."); 931 } 932 933 try{ 934 localVariablesInfos[method_number].add(localindex, localname, localvariables[i].getStartPC(), localvariables[i].getLength(), t); 935 } 936 catch(LocalVariableInfoInconsistentException lviie){ 937 throw new ClassConstraintException("Conflicting information in LocalVariableTable '"+tostring(lvt)+"' found in Code attribute '"+tostring(obj)+"' (method '"+tostring(m)+"'). "+lviie.getMessage()); 938 } 939 } 941 num_of_lvt_attribs++; 942 if (num_of_lvt_attribs > obj.getMaxLocals()){ 943 throw new ClassConstraintException("Number of LocalVariableTable attributes of Code attribute '"+tostring(obj)+"' (method '"+tostring(m)+"') exceeds number of local variable slots '"+obj.getMaxLocals()+"' ('There may be no more than one LocalVariableTable attribute per local variable in the Code attribute.')."); 944 } 945 } } } 949 public void visitExceptionTable(ExceptionTable obj){ checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 952 953 String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); 954 if (! name.equals("Exceptions")){ 955 throw new ClassConstraintException("The Exceptions attribute '"+tostring(obj)+"' is not correctly named 'Exceptions' but '"+name+"'."); 956 } 957 958 int[] exc_indices = obj.getExceptionIndexTable(); 959 960 for (int i=0; i<exc_indices.length; i++){ 961 checkIndex(obj, exc_indices[i], CONST_Class); 962 963 ConstantClass cc = (ConstantClass) (cp.getConstant(exc_indices[i])); 964 checkIndex(cc, cc.getNameIndex(), CONST_Utf8); String cname = ((ConstantUtf8) cp.getConstant(cc.getNameIndex())).getBytes().replace('/','.'); 967 Verifier v = VerifierFactory.getVerifier(cname); 968 VerificationResult vr = v.doPass1(); 969 970 if (vr != VerificationResult.VR_OK){ 971 throw new ClassConstraintException("Exceptions attribute '"+tostring(obj)+"' references '"+cname+"' as an Exception but it does not pass verification pass 1: "+vr); 972 } 973 else{ 974 JavaClass e = Repository.lookupClass(cname); 977 JavaClass t = Repository.lookupClass(Type.THROWABLE.getClassName()); 978 JavaClass o = Repository.lookupClass(Type.OBJECT.getClassName()); 979 while (e != o){ 980 if (e == t) break; 982 v = VerifierFactory.getVerifier(e.getSuperclassName()); 983 vr = v.doPass1(); 984 if (vr != VerificationResult.VR_OK){ 985 throw new ClassConstraintException("Exceptions attribute '"+tostring(obj)+"' references '"+cname+"' as an Exception but '"+e.getSuperclassName()+"' in the ancestor hierachy does not pass verification pass 1: "+vr); 986 } 987 else{ 988 e = Repository.lookupClass(e.getSuperclassName()); 989 } 990 } 991 if (e != t) throw new ClassConstraintException("Exceptions attribute '"+tostring(obj)+"' references '"+cname+"' as an Exception but it is not a subclass of '"+t.getClassName()+"'."); 992 } 993 } 994 } 995 public void visitLineNumberTable(LineNumberTable obj){ checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 1002 1003 String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); 1004 if (! name.equals("LineNumberTable")){ 1005 throw new ClassConstraintException("The LineNumberTable attribute '"+tostring(obj)+"' is not correctly named 'LineNumberTable' but '"+name+"'."); 1006 } 1007 1008 1012 } 1013 public void visitLocalVariableTable(LocalVariableTable obj){ } 1017 public void visitUnknown(Unknown obj){ checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 1023 1024 addMessage("Unknown attribute '"+tostring(obj)+"'. This attribute is not known in any context!"); 1026 } 1027 public void visitLocalVariable(LocalVariable obj){ 1031 1034 } 1036 public void visitCodeException(CodeException obj){ 1037 1041 } 1043 public void visitConstantPool(ConstantPool obj){ 1044 } 1048 public void visitInnerClass(InnerClass obj){ 1049 } 1052 public void visitLineNumber(LineNumber obj){ 1053 1056 } 1058 } 1059 1060 1074 private void field_and_method_refs_are_valid(){ 1075 JavaClass jc = Repository.lookupClass(myOwner.getClassName()); 1076 DescendingVisitor v = new DescendingVisitor(jc, new FAMRAV_Visitor(jc)); 1077 v.visit(); 1078 } 1079 1080 1089 private class FAMRAV_Visitor extends EmptyVisitor implements Visitor{ 1090 private final JavaClass jc; 1091 private final ConstantPool cp; private FAMRAV_Visitor(JavaClass _jc){ 1093 jc = _jc; 1094 cp = _jc.getConstantPool(); 1095 } 1096 1097 public void visitConstantFieldref(ConstantFieldref obj){ 1098 if (obj.getTag() != Constants.CONSTANT_Fieldref){ 1099 throw new ClassConstraintException("ConstantFieldref '"+tostring(obj)+"' has wrong tag!"); 1100 } 1101 int name_and_type_index = obj.getNameAndTypeIndex(); 1102 ConstantNameAndType cnat = (ConstantNameAndType) (cp.getConstant(name_and_type_index)); 1103 String name = ((ConstantUtf8) (cp.getConstant(cnat.getNameIndex()))).getBytes(); if (!validFieldName(name)){ 1105 throw new ClassConstraintException("Invalid field name '"+name+"' referenced by '"+tostring(obj)+"'."); 1106 } 1107 1108 int class_index = obj.getClassIndex(); 1109 ConstantClass cc = (ConstantClass) (cp.getConstant(class_index)); 1110 String className = ((ConstantUtf8) (cp.getConstant(cc.getNameIndex()))).getBytes(); if (! validClassName(className)){ 1112 throw new ClassConstraintException("Illegal class name '"+className+"' used by '"+tostring(obj)+"'."); 1113 } 1114 1115 String sig = ((ConstantUtf8) (cp.getConstant(cnat.getSignatureIndex()))).getBytes(); 1117 try{ 1118 Type t = Type.getType(sig); 1119 } 1120 catch (ClassFormatError cfe){ 1121 throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'."); 1123 } 1124 } 1125 1126 public void visitConstantMethodref(ConstantMethodref obj){ 1127 if (obj.getTag() != Constants.CONSTANT_Methodref){ 1128 throw new ClassConstraintException("ConstantMethodref '"+tostring(obj)+"' has wrong tag!"); 1129 } 1130 int name_and_type_index = obj.getNameAndTypeIndex(); 1131 ConstantNameAndType cnat = (ConstantNameAndType) (cp.getConstant(name_and_type_index)); 1132 String name = ((ConstantUtf8) (cp.getConstant(cnat.getNameIndex()))).getBytes(); if (!validClassMethodName(name)){ 1134 throw new ClassConstraintException("Invalid (non-interface) method name '"+name+"' referenced by '"+tostring(obj)+"'."); 1135 } 1136 1137 int class_index = obj.getClassIndex(); 1138 ConstantClass cc = (ConstantClass) (cp.getConstant(class_index)); 1139 String className = ((ConstantUtf8) (cp.getConstant(cc.getNameIndex()))).getBytes(); if (! validClassName(className)){ 1141 throw new ClassConstraintException("Illegal class name '"+className+"' used by '"+tostring(obj)+"'."); 1142 } 1143 1144 String sig = ((ConstantUtf8) (cp.getConstant(cnat.getSignatureIndex()))).getBytes(); 1146 try{ 1147 Type t = Type.getReturnType(sig); 1148 Type[] ts = Type.getArgumentTypes(sig); 1149 if ( name.equals(CONSTRUCTOR_NAME) && (t != Type.VOID) ){ 1150 throw new ClassConstraintException("Instance initialization method must have VOID return type."); 1151 } 1152 } 1153 catch (ClassFormatError cfe){ 1154 throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'."); 1156 } 1157 } 1158 1159 public void visitConstantInterfaceMethodref(ConstantInterfaceMethodref obj){ 1160 if (obj.getTag() != Constants.CONSTANT_InterfaceMethodref){ 1161 throw new ClassConstraintException("ConstantInterfaceMethodref '"+tostring(obj)+"' has wrong tag!"); 1162 } 1163 int name_and_type_index = obj.getNameAndTypeIndex(); 1164 ConstantNameAndType cnat = (ConstantNameAndType) (cp.getConstant(name_and_type_index)); 1165 String name = ((ConstantUtf8) (cp.getConstant(cnat.getNameIndex()))).getBytes(); if (!validInterfaceMethodName(name)){ 1167 throw new ClassConstraintException("Invalid (interface) method name '"+name+"' referenced by '"+tostring(obj)+"'."); 1168 } 1169 1170 int class_index = obj.getClassIndex(); 1171 ConstantClass cc = (ConstantClass) (cp.getConstant(class_index)); 1172 String className = ((ConstantUtf8) (cp.getConstant(cc.getNameIndex()))).getBytes(); if (! validClassName(className)){ 1174 throw new ClassConstraintException("Illegal class name '"+className+"' used by '"+tostring(obj)+"'."); 1175 } 1176 1177 String sig = ((ConstantUtf8) (cp.getConstant(cnat.getSignatureIndex()))).getBytes(); 1179 try{ 1180 Type t = Type.getReturnType(sig); 1181 Type[] ts = Type.getArgumentTypes(sig); 1182 if ( name.equals(STATIC_INITIALIZER_NAME) && (t != Type.VOID) ){ 1183 addMessage("Class or interface initialization method '"+STATIC_INITIALIZER_NAME+"' usually has VOID return type instead of '"+t+"'. Note this is really not a requirement of The Java Virtual Machine Specification, Second Edition."); 1184 } 1185 } 1186 catch (ClassFormatError cfe){ 1187 throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'."); 1189 } 1190 1191 } 1192 1193 } 1194 1195 1199 private static final boolean validClassName(String name){ 1200 return true; 1202 } 1203 1211 private static boolean validMethodName(String name, boolean allowStaticInit){ 1212 if (validJavaLangMethodName(name)) return true; 1213 1214 if (allowStaticInit){ 1215 return (name.equals(CONSTRUCTOR_NAME) || name.equals(STATIC_INITIALIZER_NAME)); 1216 } 1217 else{ 1218 return name.equals(CONSTRUCTOR_NAME); 1219 } 1220 } 1221 1222 1227 private static boolean validClassMethodName(String name){ 1228 return validMethodName(name, false); 1229 } 1230 1231 1237 private static boolean validJavaLangMethodName(String name){ 1238 if (!Character.isJavaIdentifierStart(name.charAt(0))) return false; 1239 1240 for (int i=1; i<name.length(); i++){ 1241 if (!Character.isJavaIdentifierPart(name.charAt(i))) return false; 1242 } 1243 return true; 1244 } 1245 1246 1251 private static boolean validInterfaceMethodName(String name){ 1252 if (name.startsWith("<")) return false; 1254 return validJavaLangMethodName(name); 1255 } 1256 1257 1261 private static boolean validJavaIdentifier(String name){ 1262 if (!Character.isJavaIdentifierStart(name.charAt(0))) return false; 1264 1265 for (int i=1; i<name.length(); i++){ 1266 if (!Character.isJavaIdentifierPart(name.charAt(i))) return false; 1267 } 1268 return true; 1269 } 1270 1271 1275 private static boolean validFieldName(String name){ 1276 return validJavaIdentifier(name); 1278 } 1279 1280 1299 private class InnerClassDetector extends EmptyVisitor{ 1300 private boolean hasInnerClass = false; 1301 private JavaClass jc; 1302 private ConstantPool cp; 1303 private InnerClassDetector(){} 1305 public InnerClassDetector(JavaClass _jc){ 1306 jc = _jc; 1307 cp = jc.getConstantPool(); 1308 (new DescendingVisitor(jc, this)).visit(); 1309 } 1310 1314 public boolean innerClassReferenced(){ 1315 return hasInnerClass; 1316 } 1317 1318 public void visitConstantClass(ConstantClass obj){ 1319 Constant c = cp.getConstant(obj.getNameIndex()); 1320 if (c instanceof ConstantUtf8){ String classname = ((ConstantUtf8) c).getBytes(); 1322 if (classname.startsWith(jc.getClassName().replace('.','/')+"$")){ 1323 hasInnerClass = true; 1324 } 1325 } 1326 } 1327 } 1328 1329 1332 private static String tostring(Node n){ 1333 return new StringRepresentation(n).toString(); 1334 } 1335} 1336 | Popular Tags |