1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 package proguard.classfile; 22 23 import proguard.classfile.attribute.Attribute; 24 import proguard.classfile.attribute.visitor.AttributeVisitor; 25 import proguard.classfile.constant.*; 26 import proguard.classfile.constant.visitor.ConstantVisitor; 27 import proguard.classfile.util.ClassSubHierarchyInitializer; 28 import proguard.classfile.visitor.*; 29 30 /** 31 * This Clazz is a complete representation of the data in a Java class. 32 * 33 * @author Eric Lafortune 34 */ 35 public class ProgramClass implements Clazz 36 { 37 public int u4magic; 38 public int u4version; 39 public int u2constantPoolCount; 40 public Constant[] constantPool; 41 public int u2accessFlags; 42 public int u2thisClass; 43 public int u2superClass; 44 public int u2interfacesCount; 45 public int[] u2interfaces; 46 public int u2fieldsCount; 47 public ProgramField[] fields; 48 public int u2methodsCount; 49 public ProgramMethod[] methods; 50 public int u2attributesCount; 51 public Attribute[] attributes; 52 53 /** 54 * An extra field pointing to the subclasses of this class. 55 * This field is filled out by the {@link ClassSubHierarchyInitializer}. 56 */ 57 public Clazz[] subClasses; 58 59 /** 60 * An extra field in which visitors can store information. 61 */ 62 public Object visitorInfo; 63 64 65 /** 66 * Creates an uninitialized ProgramClass. 67 */ ProgramClass()68 public ProgramClass() {} 69 70 71 /** 72 * Returns the Constant at the given index in the constant pool. 73 */ getConstant(int constantIndex)74 public Constant getConstant(int constantIndex) 75 { 76 return constantPool[constantIndex]; 77 } 78 79 80 // Implementations for Clazz. 81 getAccessFlags()82 public int getAccessFlags() 83 { 84 return u2accessFlags; 85 } 86 getName()87 public String getName() 88 { 89 return getClassName(u2thisClass); 90 } 91 getSuperName()92 public String getSuperName() 93 { 94 return u2superClass == 0 ? null : getClassName(u2superClass); 95 } 96 getInterfaceCount()97 public int getInterfaceCount() 98 { 99 return u2interfacesCount; 100 } 101 getInterfaceName(int index)102 public String getInterfaceName(int index) 103 { 104 return getClassName(u2interfaces[index]); 105 } 106 getTag(int constantIndex)107 public int getTag(int constantIndex) 108 { 109 return constantPool[constantIndex].getTag(); 110 } 111 getString(int constantIndex)112 public String getString(int constantIndex) 113 { 114 try 115 { 116 return ((Utf8Constant)constantPool[constantIndex]).getString(); 117 } 118 catch (ClassCastException ex) 119 { 120 new ClassPrinter().visitProgramClass(this); 121 throw new ClassCastException("Expected Utf8Constant at index ["+constantIndex+"] in class ["+getName()+"], found ["+ex.getMessage()+"]"); 122 } 123 } 124 getStringString(int constantIndex)125 public String getStringString(int constantIndex) 126 { 127 try 128 { 129 return ((StringConstant)constantPool[constantIndex]).getString(this); 130 } 131 catch (ClassCastException ex) 132 { 133 throw new ClassCastException("Expected StringConstant at index ["+constantIndex+"] in class ["+getName()+"], found ["+ex.getMessage()+"]"); 134 } 135 } 136 getClassName(int constantIndex)137 public String getClassName(int constantIndex) 138 { 139 try 140 { 141 return ((ClassConstant)constantPool[constantIndex]).getName(this); 142 } 143 catch (ClassCastException ex) 144 { 145 throw new ClassCastException("Expected ClassConstant at index ["+constantIndex+"] in class ["+getName()+"], found ["+ex.getMessage()+"]"); 146 } 147 } 148 getName(int constantIndex)149 public String getName(int constantIndex) 150 { 151 try 152 { 153 return ((NameAndTypeConstant)constantPool[constantIndex]).getName(this); 154 } 155 catch (ClassCastException ex) 156 { 157 throw new ClassCastException("Expected NameAndTypeConstant at index ["+constantIndex+"] in class ["+getName()+"], found ["+ex.getMessage()+"]"); 158 } 159 } 160 getType(int constantIndex)161 public String getType(int constantIndex) 162 { 163 try 164 { 165 return ((NameAndTypeConstant)constantPool[constantIndex]).getType(this); 166 } 167 catch (ClassCastException ex) 168 { 169 throw new ClassCastException("Expected NameAndTypeConstant at index ["+constantIndex+"] in class ["+getName()+"], found ["+ex.getMessage()+"]"); 170 } 171 } 172 173 addSubClass(Clazz clazz)174 public void addSubClass(Clazz clazz) 175 { 176 if (subClasses == null) 177 { 178 subClasses = new Clazz[1]; 179 } 180 else 181 { 182 // Copy the old elements into new larger array. 183 Clazz[] temp = new Clazz[subClasses.length+1]; 184 System.arraycopy(subClasses, 0, temp, 0, subClasses.length); 185 subClasses = temp; 186 } 187 188 subClasses[subClasses.length-1] = clazz; 189 } 190 191 getSuperClass()192 public Clazz getSuperClass() 193 { 194 return u2superClass != 0 ? 195 ((ClassConstant)constantPool[u2superClass]).referencedClass : 196 null; 197 } 198 199 getInterface(int index)200 public Clazz getInterface(int index) 201 { 202 return ((ClassConstant)constantPool[u2interfaces[index]]).referencedClass; 203 } 204 205 extends_(Clazz clazz)206 public boolean extends_(Clazz clazz) 207 { 208 if (this.equals(clazz)) 209 { 210 return true; 211 } 212 213 Clazz superClass = getSuperClass(); 214 return superClass != null && 215 superClass.extends_(clazz); 216 } 217 218 extendsOrImplements(Clazz clazz)219 public boolean extendsOrImplements(Clazz clazz) 220 { 221 if (this.equals(clazz)) 222 { 223 return true; 224 } 225 226 Clazz superClass = getSuperClass(); 227 if (superClass != null && 228 superClass.extendsOrImplements(clazz)) 229 { 230 return true; 231 } 232 233 for (int index = 0; index < u2interfacesCount; index++) 234 { 235 Clazz interfaceClass = getInterface(index); 236 if (interfaceClass != null && 237 interfaceClass.extendsOrImplements(clazz)) 238 { 239 return true; 240 } 241 } 242 243 return false; 244 } 245 246 findField(String name, String descriptor)247 public Field findField(String name, String descriptor) 248 { 249 for (int index = 0; index < u2fieldsCount; index++) 250 { 251 Field field = fields[index]; 252 if ((name == null || field.getName(this).equals(name)) && 253 (descriptor == null || field.getDescriptor(this).equals(descriptor))) 254 { 255 return field; 256 } 257 } 258 259 return null; 260 } 261 262 findMethod(String name, String descriptor)263 public Method findMethod(String name, String descriptor) 264 { 265 for (int index = 0; index < u2methodsCount; index++) 266 { 267 Method method = methods[index]; 268 if ((name == null || method.getName(this).equals(name)) && 269 (descriptor == null || method.getDescriptor(this).equals(descriptor))) 270 { 271 return method; 272 } 273 } 274 275 return null; 276 } 277 278 accept(ClassVisitor classVisitor)279 public void accept(ClassVisitor classVisitor) 280 { 281 classVisitor.visitProgramClass(this); 282 } 283 284 hierarchyAccept(boolean visitThisClass, boolean visitSuperClass, boolean visitInterfaces, boolean visitSubclasses, ClassVisitor classVisitor)285 public void hierarchyAccept(boolean visitThisClass, 286 boolean visitSuperClass, 287 boolean visitInterfaces, 288 boolean visitSubclasses, 289 ClassVisitor classVisitor) 290 { 291 // First visit the current classfile. 292 if (visitThisClass) 293 { 294 accept(classVisitor); 295 } 296 297 // Then visit its superclass, recursively. 298 if (visitSuperClass) 299 { 300 Clazz superClass = getSuperClass(); 301 if (superClass != null) 302 { 303 superClass.hierarchyAccept(true, 304 true, 305 visitInterfaces, 306 false, 307 classVisitor); 308 } 309 } 310 311 // Then visit its interfaces, recursively. 312 if (visitInterfaces) 313 { 314 // Visit the interfaces of the superclasses, if we haven't done so yet. 315 if (!visitSuperClass) 316 { 317 Clazz superClass = getSuperClass(); 318 if (superClass != null) 319 { 320 superClass.hierarchyAccept(false, 321 false, 322 true, 323 false, 324 classVisitor); 325 } 326 } 327 328 // Visit the interfaces. 329 for (int index = 0; index < u2interfacesCount; index++) 330 { 331 Clazz interfaceClass = getInterface(index); 332 if (interfaceClass != null) 333 { 334 interfaceClass.hierarchyAccept(true, 335 false, 336 true, 337 false, 338 classVisitor); 339 } 340 } 341 } 342 343 // Then visit its subclasses, recursively. 344 if (visitSubclasses) 345 { 346 if (subClasses != null) 347 { 348 for (int index = 0; index < subClasses.length; index++) 349 { 350 Clazz subClass = subClasses[index]; 351 subClass.hierarchyAccept(true, 352 false, 353 false, 354 true, 355 classVisitor); 356 } 357 } 358 } 359 } 360 361 subclassesAccept(ClassVisitor classVisitor)362 public void subclassesAccept(ClassVisitor classVisitor) 363 { 364 if (subClasses != null) 365 { 366 for (int index = 0; index < subClasses.length; index++) 367 { 368 subClasses[index].accept(classVisitor); 369 } 370 } 371 } 372 373 constantPoolEntriesAccept(ConstantVisitor constantVisitor)374 public void constantPoolEntriesAccept(ConstantVisitor constantVisitor) 375 { 376 for (int index = 1; index < u2constantPoolCount; index++) 377 { 378 if (constantPool[index] != null) 379 { 380 constantPool[index].accept(this, constantVisitor); 381 } 382 } 383 } 384 385 constantPoolEntryAccept(int index, ConstantVisitor constantVisitor)386 public void constantPoolEntryAccept(int index, ConstantVisitor constantVisitor) 387 { 388 constantPool[index].accept(this, constantVisitor); 389 } 390 391 thisClassConstantAccept(ConstantVisitor constantVisitor)392 public void thisClassConstantAccept(ConstantVisitor constantVisitor) 393 { 394 constantPool[u2thisClass].accept(this, constantVisitor); 395 } 396 397 superClassConstantAccept(ConstantVisitor constantVisitor)398 public void superClassConstantAccept(ConstantVisitor constantVisitor) 399 { 400 if (u2superClass != 0) 401 { 402 constantPool[u2superClass].accept(this, constantVisitor); 403 } 404 } 405 406 interfaceConstantsAccept(ConstantVisitor constantVisitor)407 public void interfaceConstantsAccept(ConstantVisitor constantVisitor) 408 { 409 for (int index = 0; index < u2interfacesCount; index++) 410 { 411 constantPool[u2interfaces[index]].accept(this, constantVisitor); 412 } 413 } 414 415 fieldsAccept(MemberVisitor memberVisitor)416 public void fieldsAccept(MemberVisitor memberVisitor) 417 { 418 for (int index = 0; index < u2fieldsCount; index++) 419 { 420 fields[index].accept(this, memberVisitor); 421 } 422 } 423 424 fieldAccept(String name, String descriptor, MemberVisitor memberVisitor)425 public void fieldAccept(String name, String descriptor, MemberVisitor memberVisitor) 426 { 427 Field field = findField(name, descriptor); 428 if (field != null) 429 { 430 field.accept(this, memberVisitor); 431 } 432 } 433 434 methodsAccept(MemberVisitor memberVisitor)435 public void methodsAccept(MemberVisitor memberVisitor) 436 { 437 for (int index = 0; index < u2methodsCount; index++) 438 { 439 methods[index].accept(this, memberVisitor); 440 } 441 } 442 443 methodAccept(String name, String descriptor, MemberVisitor memberVisitor)444 public void methodAccept(String name, String descriptor, MemberVisitor memberVisitor) 445 { 446 Method method = findMethod(name, descriptor); 447 if (method != null) 448 { 449 method.accept(this, memberVisitor); 450 } 451 } 452 453 mayHaveImplementations(Method method)454 public boolean mayHaveImplementations(Method method) 455 { 456 return 457 (u2accessFlags & ClassConstants.INTERNAL_ACC_FINAL) == 0 && 458 (method == null || 459 ((method.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PRIVATE | 460 ClassConstants.INTERNAL_ACC_STATIC | 461 ClassConstants.INTERNAL_ACC_FINAL)) == 0 && 462 !method.getName(this).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))); 463 } 464 465 attributesAccept(AttributeVisitor attributeVisitor)466 public void attributesAccept(AttributeVisitor attributeVisitor) 467 { 468 for (int index = 0; index < u2attributesCount; index++) 469 { 470 attributes[index].accept(this, attributeVisitor); 471 } 472 } 473 474 475 // Implementations for VisitorAccepter. 476 getVisitorInfo()477 public Object getVisitorInfo() 478 { 479 return visitorInfo; 480 } 481 setVisitorInfo(Object visitorInfo)482 public void setVisitorInfo(Object visitorInfo) 483 { 484 this.visitorInfo = visitorInfo; 485 } 486 487 488 // Implementations for Object. 489 toString()490 public String toString() 491 { 492 return "ProgramClass("+getName()+")"; 493 } 494 } 495