1 19 20 25 26 27 28 29 30 package soot; 31 32 import soot.tagkit.*; 33 import soot.util.*; 34 import java.util.*; 35 import java.io.*; 36 import soot.baf.toolkits.base.*; 37 import soot.jimple.toolkits.base.*; 38 import soot.dava.*; 39 import soot.dava.toolkits.base.misc.*; 40 import soot.jimple.*; 41 import soot.options.*; 42 43 58 59 63 public class SootClass extends AbstractHost implements Numberable 64 { 65 protected String name, shortName, fixedShortName, packageName, fixedPackageName; 66 protected int modifiers; 67 protected Chain fields = new HashChain(); 68 protected SmallNumberedMap subSigToMethods = new SmallNumberedMap( Scene.v().getSubSigNumberer() ); 69 protected List methodList = new ArrayList(); 72 protected Chain interfaces = new HashChain(); 73 74 protected boolean isInScene; 75 protected SootClass superClass; 76 protected SootClass outerClass; 77 78 protected boolean isPhantom; 79 80 81 84 85 public SootClass(String name, int modifiers) 86 { 87 if( name.charAt(0) == '[' ) throw new RuntimeException ( "Attempt to make a class whose name starts with [" ); 88 setName( name); 89 this.modifiers = modifiers; 90 refType = RefType.v(name); 91 refType.setSootClass(this); 92 if(Options.v().debug_resolver()) G.v().out.println("created "+name+" with modifiers "+modifiers); 93 setResolvingLevel(BODIES); 94 } 95 96 99 100 public SootClass(String name) 101 { 102 this( name, 0); 103 } 104 105 public final static int DANGLING = 0; 106 public final static int HIERARCHY = 1; 107 public final static int SIGNATURES = 2; 108 public final static int BODIES = 3; 109 private int resolvingLevel = DANGLING; 110 111 private String levelToString( int level ) { 112 switch(level) { 113 case DANGLING: return "DANGLING"; 114 case HIERARCHY: return "HIERARCHY"; 115 case SIGNATURES: return "SIGNATURES"; 116 case BODIES: return "BODIES"; 117 default: throw new RuntimeException ("unknown resolving level"); 118 } 119 } 120 public void checkLevel( int level ) { 121 if( !Scene.v().doneResolving() ) return; 122 if( resolvingLevel < level ) { 123 126 throw new RuntimeException ( 127 "This operation requires resolving level "+ 128 levelToString(level)+" but "+name+ 129 " is at resolving level "+levelToString(resolvingLevel) ); 130 136 } 137 } 138 139 public int resolvingLevel() { return resolvingLevel; } 140 public void setResolvingLevel( int newLevel ) { 141 resolvingLevel = newLevel; 142 } 143 144 public boolean isInScene() 145 { 146 return isInScene; 147 } 148 149 150 public void setInScene(boolean isInScene) 151 { 152 this.isInScene = isInScene; 153 } 154 155 158 159 public int getFieldCount() 160 { 161 checkLevel(SIGNATURES); 162 return fields.size(); 163 } 164 165 168 169 public Chain getFields() 170 { 171 checkLevel(SIGNATURES); 172 return fields; 173 } 174 175 181 182 185 186 public void addField(SootField f) 187 { 188 checkLevel(SIGNATURES); 189 if(f.isDeclared()) 190 throw new RuntimeException ("already declared: "+f.getName()); 191 192 if(declaresField(f.getName())) 193 throw new RuntimeException ("Field already exists : "+f.getName()); 194 195 fields.add(f); 196 f.isDeclared = true; 197 f.declaringClass = this; 198 199 } 200 201 204 205 public void removeField(SootField f) 206 { 207 checkLevel(SIGNATURES); 208 if(!f.isDeclared() || f.getDeclaringClass() != this) 209 throw new RuntimeException ("did not declare: "+f.getName()); 210 211 fields.remove(f); 212 f.isDeclared = false; 213 } 214 215 218 219 public SootField getField( String name, Type type ) { 220 checkLevel(SIGNATURES); 221 for( Iterator fieldIt = this.getFields().iterator(); fieldIt.hasNext(); ) { 222 final SootField field = (SootField) fieldIt.next(); 223 if(field.name.equals(name) && field.type.equals(type)) 224 return field; 225 } 226 throw new RuntimeException ("No field " + name + " in class " + getName()); 227 } 228 229 233 234 public SootField getFieldByName(String name) 235 { 236 checkLevel(SIGNATURES); 237 boolean found = false; 238 SootField foundField = null; 239 240 Iterator fieldIt = getFields().iterator(); 241 242 while(fieldIt.hasNext()) 243 { 244 SootField field = (SootField) fieldIt.next(); 245 246 if(field.name.equals(name)) 247 { 248 if(found) 249 throw new RuntimeException ("ambiguous field: "+name); 250 else { 251 found = true; 252 foundField = field; 253 } 254 } 255 } 256 257 if(found) 258 return foundField; 259 else 260 throw new RuntimeException ("No field " + name + " in class " + getName()); 261 } 262 263 264 267 268 public SootField getField(String subsignature) 269 { 270 checkLevel(SIGNATURES); 271 for( Iterator fieldIt = this.getFields().iterator(); fieldIt.hasNext(); ) { 272 final SootField field = (SootField) fieldIt.next(); 273 if( field.getSubSignature().equals( subsignature ) ) return field; 274 } 275 276 throw new RuntimeException ("No field " + subsignature + " in class " + getName()); 277 } 278 279 280 283 284 public boolean declaresField(String subsignature) 285 { 286 checkLevel(SIGNATURES); 287 for( Iterator fieldIt = this.getFields().iterator(); fieldIt.hasNext(); ) { 288 final SootField field = (SootField) fieldIt.next(); 289 if( field.getSubSignature().equals( subsignature ) ) return true; 290 } 291 return false; 292 } 293 294 295 298 299 public SootMethod getMethod(NumberedString subsignature) 300 { 301 checkLevel(SIGNATURES); 302 SootMethod ret = (SootMethod) subSigToMethods.get( subsignature ); 303 if(ret == null) 304 throw new RuntimeException ("No method " + subsignature + " in class " + getName()); 305 else 306 return ret; 307 } 308 309 312 313 public boolean declaresMethod(NumberedString subsignature) 314 { 315 checkLevel(SIGNATURES); 316 SootMethod ret = (SootMethod) subSigToMethods.get( subsignature ); 317 return ret != null; 318 } 319 320 321 324 325 public SootMethod getMethod(String subsignature) 326 { 327 checkLevel(SIGNATURES); 328 return getMethod( Scene.v().getSubSigNumberer().findOrAdd( subsignature ) ); 329 } 330 331 334 335 public boolean declaresMethod(String subsignature) 336 { 337 checkLevel(SIGNATURES); 338 return declaresMethod( Scene.v().getSubSigNumberer().findOrAdd( subsignature ) ); 339 } 340 341 342 345 346 public boolean declaresFieldByName(String name) 347 { 348 checkLevel(SIGNATURES); 349 Iterator fieldIt = getFields().iterator(); 350 351 while(fieldIt.hasNext()) 352 { 353 SootField field = (SootField) fieldIt.next(); 354 355 if(field.name.equals(name)) 356 return true; 357 } 358 359 return false; 360 } 361 362 363 366 367 public boolean declaresField(String name, Type type) 368 { 369 checkLevel(SIGNATURES); 370 Iterator fieldIt = getFields().iterator(); 371 372 while(fieldIt.hasNext()) 373 { 374 SootField field = (SootField) fieldIt.next(); 375 376 if(field.name.equals(name) && 377 field.type.equals(type)) 378 return true; 379 } 380 381 return false; 382 } 383 384 387 388 public int getMethodCount() 389 { 390 checkLevel(SIGNATURES); 391 return subSigToMethods.nonNullSize(); 392 } 393 394 397 398 public Iterator methodIterator() 399 { 400 checkLevel(SIGNATURES); 401 return methodList.iterator(); 402 } 403 404 public List getMethods() { 405 checkLevel(SIGNATURES); 406 ArrayList ret = new ArrayList(); 407 for( Iterator it = methodIterator(); it.hasNext(); ) 408 ret.add( it.next() ); 409 return ret; 410 } 411 412 public SootMethod getMethod( String name, List parameterTypes, 413 Type returnType ) 414 { 415 checkLevel(SIGNATURES); 416 for( Iterator methodIt = methodIterator(); methodIt.hasNext(); ) { 417 final SootMethod method = (SootMethod) methodIt.next(); 418 if(method.getName().equals(name) && 419 parameterTypes.equals(method.getParameterTypes()) && 420 returnType.equals(method.getReturnType())) 421 { 422 return method; 423 } 424 } 425 throw new RuntimeException ( 426 "Class "+getName()+" doesn't have method "+ 427 name + "(" + parameterTypes + ")" + " : " + returnType ); 428 } 429 432 433 438 439 public SootMethod getMethod(String name, List parameterTypes) 440 { 441 checkLevel(SIGNATURES); 442 boolean found = false; 443 SootMethod foundMethod = null; 444 445 Iterator methodIt = methodIterator(); 446 447 while(methodIt.hasNext()) 448 { 449 SootMethod method = (SootMethod) methodIt.next(); 450 451 if(method.getName().equals(name) && 452 parameterTypes.equals(method.getParameterTypes())) 453 { 454 if(found) 455 throw new RuntimeException ("ambiguous method"); 456 else { 457 found = true; 458 foundMethod = method; 459 } 460 } 461 } 462 463 if(found) 464 return foundMethod; 465 else 466 throw new RuntimeException ("couldn't find method "+name+"("+parameterTypes+") in "+this); 467 } 468 469 470 475 476 public SootMethod getMethodByName(String name) 477 { 478 checkLevel(SIGNATURES); 479 boolean found = false; 480 SootMethod foundMethod = null; 481 482 Iterator methodIt = methodIterator(); 483 484 while(methodIt.hasNext()) 485 { 486 SootMethod method = (SootMethod) methodIt.next(); 487 488 if(method.getName().equals(name)) 489 { 490 if(found) 491 throw new RuntimeException ("ambiguous method"); 492 else { 493 found = true; 494 foundMethod = method; 495 } 496 } 497 } 498 if(found) 499 return foundMethod; 500 else 501 throw new RuntimeException ("couldn't find method "+name+"(*) in "+this); 502 } 503 504 507 508 public boolean declaresMethod(String name, List parameterTypes) 509 { 510 checkLevel(SIGNATURES); 511 Iterator methodIt = methodIterator(); 512 513 while(methodIt.hasNext()) 514 { 515 SootMethod method = (SootMethod) methodIt.next(); 516 517 if(method.getName().equals(name) && 518 method.getParameterTypes().equals(parameterTypes)) 519 return true; 520 } 521 522 return false; 523 } 524 525 528 529 public boolean declaresMethod(String name, List parameterTypes, Type returnType) 530 { 531 checkLevel(SIGNATURES); 532 Iterator methodIt = methodIterator(); 533 534 while(methodIt.hasNext()) 535 { 536 SootMethod method = (SootMethod) methodIt.next(); 537 538 if(method.getName().equals(name) && 539 method.getParameterTypes().equals(parameterTypes) && 540 method.getReturnType().equals(returnType)) 541 542 return true; 543 } 544 545 return false; 546 } 547 548 551 552 public boolean declaresMethodByName(String name) 553 { 554 checkLevel(SIGNATURES); 555 Iterator methodIt = methodIterator(); 556 557 while(methodIt.hasNext()) 558 { 559 SootMethod method = (SootMethod) methodIt.next(); 560 561 if(method.getName().equals(name)) 562 return true; 563 } 564 565 return false; 566 } 567 568 574 575 578 579 public void addMethod(SootMethod m) 580 { 581 checkLevel(SIGNATURES); 582 if(m.isDeclared()) 583 throw new RuntimeException ("already declared: "+m.getName()); 584 585 589 590 if(subSigToMethods.get(m.getNumberedSubSignature()) != null ) { 591 throw new RuntimeException ( 592 "Attempting to add method "+m.getSubSignature()+" to class "+this+", but the class already has a method with that signature."); 593 } 594 subSigToMethods.put(m.getNumberedSubSignature(),m); 595 methodList.add(m); 596 m.isDeclared = true; 597 m.declaringClass = this; 598 599 } 600 601 604 605 public void removeMethod(SootMethod m) 606 { 607 checkLevel(SIGNATURES); 608 if(!m.isDeclared() || m.getDeclaringClass() != this) 609 throw new RuntimeException ("incorrect declarer for remove: "+m.getName()); 610 611 if(subSigToMethods.get(m.getNumberedSubSignature()) == null) { 612 throw new RuntimeException ( 613 "Attempt to remove method "+m.getSubSignature()+" which is not in class "+this); 614 } 615 subSigToMethods.put(m.getNumberedSubSignature(),null); 616 methodList.remove(m); 617 m.isDeclared = false; 618 } 619 620 623 624 public int getModifiers() 625 { 626 return modifiers; 627 } 628 629 632 633 public void setModifiers(int modifiers) 634 { 635 this.modifiers = modifiers; 636 } 637 638 644 645 public int getInterfaceCount() 646 { 647 checkLevel(HIERARCHY); 648 return interfaces.size(); 649 } 650 651 654 655 public Chain getInterfaces() 656 { 657 checkLevel(HIERARCHY); 658 return interfaces; 659 } 660 661 664 665 public boolean implementsInterface(String name) 666 { 667 checkLevel(HIERARCHY); 668 Iterator interfaceIt = getInterfaces().iterator(); 669 670 while(interfaceIt.hasNext()) 671 { 672 SootClass SootClass = (SootClass) interfaceIt.next(); 673 674 if(SootClass.getName().equals(name)) 675 return true; 676 } 677 678 return false; 679 } 680 681 684 685 public void addInterface(SootClass interfaceClass) 686 { 687 checkLevel(HIERARCHY); 688 if(implementsInterface(interfaceClass.getName())) 689 throw new RuntimeException ("duplicate interface: "+interfaceClass.getName()); 690 interfaces.add(interfaceClass); 691 } 692 693 696 697 public void removeInterface(SootClass interfaceClass) 698 { 699 checkLevel(HIERARCHY); 700 if(!implementsInterface(interfaceClass.getName())) 701 throw new RuntimeException ("no such interface: "+interfaceClass.getName()); 702 703 interfaces.remove(interfaceClass); 704 } 705 706 711 712 713 public boolean hasSuperclass() 714 { 715 checkLevel(HIERARCHY); 716 return superClass != null; 717 } 718 719 723 724 public SootClass getSuperclass() 725 { 726 checkLevel(HIERARCHY); 727 if(superClass == null) 728 throw new RuntimeException ("no superclass for "+getName()); 729 else 730 return superClass; 731 } 732 733 736 737 public void setSuperclass(SootClass c) 738 { 739 checkLevel(HIERARCHY); 740 superClass = c; 741 } 742 743 public boolean hasOuterClass(){ 744 checkLevel(HIERARCHY); 745 return outerClass != null; 746 } 747 748 public SootClass getOuterClass(){ 749 checkLevel(HIERARCHY); 750 if (outerClass == null) 751 throw new RuntimeException ("no outer class"); 752 else 753 return outerClass; 754 } 755 756 public void setOuterClass(SootClass c){ 757 checkLevel(HIERARCHY); 758 outerClass = c; 759 } 760 761 764 765 public String getName() 766 { 767 return name; 768 } 769 770 public String getJavaStyleName() 771 { 772 if (PackageNamer.v().has_FixedNames()) { 773 if (fixedShortName == null) 774 fixedShortName = PackageNamer.v().get_FixedClassName( name); 775 776 if (PackageNamer.v().use_ShortName( getJavaPackageName(), fixedShortName) == false) 777 return getJavaPackageName() + "." + fixedShortName; 778 779 return fixedShortName; 780 } 781 782 return shortName; 783 } 784 785 public String getShortJavaStyleName() 786 { 787 if (PackageNamer.v().has_FixedNames()) { 788 if (fixedShortName == null) 789 fixedShortName = PackageNamer.v().get_FixedClassName( name); 790 791 return fixedShortName; 792 } 793 794 return shortName; 795 } 796 797 public String getShortName() { 798 return shortName; 799 } 800 801 804 805 public String getPackageName() 806 { 807 return packageName; 808 } 809 810 public String getJavaPackageName() 811 { 812 if (PackageNamer.v().has_FixedNames()) { 813 if (fixedPackageName == null) 814 fixedPackageName = PackageNamer.v().get_FixedPackageName( packageName); 815 816 return fixedPackageName; 817 } 818 819 return packageName; 820 } 821 822 825 826 private void setName(String name) 827 { 828 this.name = name; 829 830 shortName = name; 831 packageName = ""; 832 833 int index = name.lastIndexOf( '.'); 834 if (index > 0) { 835 shortName = name.substring( index + 1); 836 packageName = name.substring( 0, index); 837 } 838 839 fixedShortName = null; 840 fixedPackageName = null; 841 } 842 843 844 public boolean isInterface() 845 { 846 checkLevel(HIERARCHY); 847 return Modifier.isInterface(this.getModifiers()); 848 } 849 850 851 public boolean isConcrete() { 852 return !isInterface() && !isAbstract(); 853 } 854 855 856 public boolean isPublic() 857 { 858 return Modifier.isPublic(this.getModifiers()); 859 } 860 861 862 public boolean containsBafBody() 863 { 864 Iterator methodIt = methodIterator(); 865 866 while(methodIt.hasNext()) 867 { 868 SootMethod m = (SootMethod) methodIt.next(); 869 870 if(m.hasActiveBody() && 871 m.getActiveBody() instanceof soot.baf.BafBody) 872 { 873 return true; 874 } 875 } 876 877 return false; 878 } 879 880 private RefType refType; 881 void setRefType( RefType refType ) { this.refType = refType; } 882 public boolean hasRefType() { return refType != null; } 883 884 885 public RefType getType() 886 { 887 return refType; 888 } 889 890 891 public String toString() 892 { 893 return getName(); 894 } 895 896 897 public void renameFieldsAndMethods(boolean privateOnly) 898 { 899 checkLevel(SIGNATURES); 900 { 902 Iterator fieldIt = this.getFields().iterator(); 903 int fieldCount = 0; 904 905 if(fieldIt.hasNext()) 906 { 907 while(fieldIt.hasNext()) 908 { 909 SootField f = (SootField)fieldIt.next(); 910 if (!privateOnly || Modifier.isPrivate(f.getModifiers())) 911 { 912 String newFieldName = "__field"+(fieldCount++); 913 f.setName(newFieldName); 914 } 915 } 916 } 917 } 918 919 { 921 Iterator methodIt = this.methodIterator(); 922 int methodCount = 0; 923 924 if(methodIt.hasNext()) 925 { 926 while(methodIt.hasNext()) 927 { 928 SootMethod m = (SootMethod)methodIt.next(); 929 if (!privateOnly || Modifier.isPrivate(m.getModifiers())) 930 { 931 String newMethodName = "__method"+(methodCount++); 932 m.setName(newMethodName); 933 } 934 } 935 } 936 } 937 } 938 939 942 public boolean isApplicationClass() 943 { 944 return Scene.v().getApplicationClasses().contains(this); 945 } 946 947 948 public void setApplicationClass() 949 { 950 Chain c = Scene.v().getContainingChain(this); 951 if (c != null) 952 c.remove(this); 953 Scene.v().getApplicationClasses().add(this); 954 955 isPhantom = false; 956 } 957 958 961 public boolean isLibraryClass() 962 { 963 return Scene.v().getLibraryClasses().contains(this); 964 } 965 966 967 public void setLibraryClass() 968 { 969 Chain c = Scene.v().getContainingChain(this); 970 if (c != null) 971 c.remove(this); 972 Scene.v().getLibraryClasses().add(this); 973 974 isPhantom = false; 975 } 976 977 980 public boolean isPhantomClass() 981 { 982 return Scene.v().getPhantomClasses().contains(this); 983 } 984 985 986 public void setPhantomClass() 987 { 988 Chain c = Scene.v().getContainingChain(this); 989 if (c != null) 990 c.remove(this); 991 Scene.v().getPhantomClasses().add(this); 992 isPhantom = true; 993 } 994 995 996 public boolean isPhantom() 997 { 998 return isPhantom; 999 } 1000 1001 1002 public void setPhantom(boolean value) 1003 { 1004 if (value == false) 1005 if (isPhantom) 1006 throw new RuntimeException ("don't know how to de-phantomize this class"); 1007 else 1008 return; 1009 1010 setPhantomClass(); 1011 } 1012 1015 public boolean isPrivate() 1016 { 1017 return Modifier.isPrivate(this.getModifiers()); 1018 } 1019 1020 1023 public boolean isProtected() 1024 { 1025 return Modifier.isProtected(this.getModifiers()); 1026 } 1027 1028 1031 public boolean isAbstract() 1032 { 1033 return Modifier.isAbstract(this.getModifiers()); 1034 } 1035 1036 public final int getNumber() { return number; } 1037 public final void setNumber( int number ) { this.number = number; } 1038 1039 private int number = 0; 1040} 1041 1042 | Popular Tags |