1/* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2013 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 */ 21package proguard.classfile; 22 23import proguard.classfile.attribute.Attribute; 24import proguard.classfile.attribute.visitor.AttributeVisitor; 25import proguard.classfile.constant.*; 26import proguard.classfile.constant.visitor.ConstantVisitor; 27import proguard.classfile.util.ClassSubHierarchyInitializer; 28import 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 */ 35public 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 */ 68 public ProgramClass() {} 69 70 71 /** 72 * Returns the Constant at the given index in the constant pool. 73 */ 74 public Constant getConstant(int constantIndex) 75 { 76 return constantPool[constantIndex]; 77 } 78 79 80 // Implementations for Clazz. 81 82 public int getAccessFlags() 83 { 84 return u2accessFlags; 85 } 86 87 public String getName() 88 { 89 return getClassName(u2thisClass); 90 } 91 92 public String getSuperName() 93 { 94 return u2superClass == 0 ? null : getClassName(u2superClass); 95 } 96 97 public int getInterfaceCount() 98 { 99 return u2interfacesCount; 100 } 101 102 public String getInterfaceName(int index) 103 { 104 return getClassName(u2interfaces[index]); 105 } 106 107 public int getTag(int constantIndex) 108 { 109 return constantPool[constantIndex].getTag(); 110 } 111 112 public String getString(int constantIndex) 113 { 114 try 115 { 116 return ((Utf8Constant)constantPool[constantIndex]).getString(); 117 } 118 catch (ClassCastException ex) 119 { 120 throw ((IllegalStateException)new IllegalStateException("Expected Utf8Constant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex)); 121 } 122 } 123 124 public String getStringString(int constantIndex) 125 { 126 try 127 { 128 return ((StringConstant)constantPool[constantIndex]).getString(this); 129 } 130 catch (ClassCastException ex) 131 { 132 throw ((IllegalStateException)new IllegalStateException("Expected StringConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex)); 133 } 134 } 135 136 public String getClassName(int constantIndex) 137 { 138 try 139 { 140 return ((ClassConstant)constantPool[constantIndex]).getName(this); 141 } 142 catch (ClassCastException ex) 143 { 144 throw ((IllegalStateException)new IllegalStateException("Expected ClassConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex)); 145 } 146 } 147 148 public String getName(int constantIndex) 149 { 150 try 151 { 152 return ((NameAndTypeConstant)constantPool[constantIndex]).getName(this); 153 } 154 catch (ClassCastException ex) 155 { 156 throw ((IllegalStateException)new IllegalStateException("Expected NameAndTypeConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex)); 157 } 158 } 159 160 public String getType(int constantIndex) 161 { 162 try 163 { 164 return ((NameAndTypeConstant)constantPool[constantIndex]).getType(this); 165 } 166 catch (ClassCastException ex) 167 { 168 throw ((IllegalStateException)new IllegalStateException("Expected NameAndTypeConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex)); 169 } 170 } 171 172 173 public String getRefName(int constantIndex) 174 { 175 try 176 { 177 return ((RefConstant)constantPool[constantIndex]).getName(this); 178 } 179 catch (ClassCastException ex) 180 { 181 throw ((IllegalStateException)new IllegalStateException("Expected RefConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex)); 182 } 183 } 184 185 public String getRefType(int constantIndex) 186 { 187 try 188 { 189 return ((RefConstant)constantPool[constantIndex]).getType(this); 190 } 191 catch (ClassCastException ex) 192 { 193 throw ((IllegalStateException)new IllegalStateException("Expected RefConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex)); 194 } 195 } 196 197 198 public void addSubClass(Clazz clazz) 199 { 200 if (subClasses == null) 201 { 202 subClasses = new Clazz[1]; 203 } 204 else 205 { 206 // Copy the old elements into new larger array. 207 Clazz[] temp = new Clazz[subClasses.length+1]; 208 System.arraycopy(subClasses, 0, temp, 0, subClasses.length); 209 subClasses = temp; 210 } 211 212 subClasses[subClasses.length-1] = clazz; 213 } 214 215 216 public Clazz getSuperClass() 217 { 218 return u2superClass != 0 ? 219 ((ClassConstant)constantPool[u2superClass]).referencedClass : 220 null; 221 } 222 223 224 public Clazz getInterface(int index) 225 { 226 return ((ClassConstant)constantPool[u2interfaces[index]]).referencedClass; 227 } 228 229 230 public boolean extends_(Clazz clazz) 231 { 232 if (this.equals(clazz)) 233 { 234 return true; 235 } 236 237 Clazz superClass = getSuperClass(); 238 return superClass != null && 239 superClass.extends_(clazz); 240 } 241 242 243 public boolean extends_(String className) 244 { 245 if (getName().equals(className)) 246 { 247 return true; 248 } 249 250 Clazz superClass = getSuperClass(); 251 return superClass != null && 252 superClass.extends_(className); 253 } 254 255 256 public boolean extendsOrImplements(Clazz clazz) 257 { 258 if (this.equals(clazz)) 259 { 260 return true; 261 } 262 263 Clazz superClass = getSuperClass(); 264 if (superClass != null && 265 superClass.extendsOrImplements(clazz)) 266 { 267 return true; 268 } 269 270 for (int index = 0; index < u2interfacesCount; index++) 271 { 272 Clazz interfaceClass = getInterface(index); 273 if (interfaceClass != null && 274 interfaceClass.extendsOrImplements(clazz)) 275 { 276 return true; 277 } 278 } 279 280 return false; 281 } 282 283 284 public boolean extendsOrImplements(String className) 285 { 286 if (getName().equals(className)) 287 { 288 return true; 289 } 290 291 Clazz superClass = getSuperClass(); 292 if (superClass != null && 293 superClass.extendsOrImplements(className)) 294 { 295 return true; 296 } 297 298 for (int index = 0; index < u2interfacesCount; index++) 299 { 300 Clazz interfaceClass = getInterface(index); 301 if (interfaceClass != null && 302 interfaceClass.extendsOrImplements(className)) 303 { 304 return true; 305 } 306 } 307 308 return false; 309 } 310 311 312 public Field findField(String name, String descriptor) 313 { 314 for (int index = 0; index < u2fieldsCount; index++) 315 { 316 Field field = fields[index]; 317 if ((name == null || field.getName(this).equals(name)) && 318 (descriptor == null || field.getDescriptor(this).equals(descriptor))) 319 { 320 return field; 321 } 322 } 323 324 return null; 325 } 326 327 328 public Method findMethod(String name, String descriptor) 329 { 330 for (int index = 0; index < u2methodsCount; index++) 331 { 332 Method method = methods[index]; 333 if ((name == null || method.getName(this).equals(name)) && 334 (descriptor == null || method.getDescriptor(this).equals(descriptor))) 335 { 336 return method; 337 } 338 } 339 340 return null; 341 } 342 343 344 public void accept(ClassVisitor classVisitor) 345 { 346 classVisitor.visitProgramClass(this); 347 } 348 349 350 public void hierarchyAccept(boolean visitThisClass, 351 boolean visitSuperClass, 352 boolean visitInterfaces, 353 boolean visitSubclasses, 354 ClassVisitor classVisitor) 355 { 356 // First visit the current classfile. 357 if (visitThisClass) 358 { 359 accept(classVisitor); 360 } 361 362 // Then visit its superclass, recursively. 363 if (visitSuperClass) 364 { 365 Clazz superClass = getSuperClass(); 366 if (superClass != null) 367 { 368 superClass.hierarchyAccept(true, 369 true, 370 visitInterfaces, 371 false, 372 classVisitor); 373 } 374 } 375 376 // Then visit its interfaces, recursively. 377 if (visitInterfaces) 378 { 379 // Visit the interfaces of the superclasses, if we haven't done so yet. 380 if (!visitSuperClass) 381 { 382 Clazz superClass = getSuperClass(); 383 if (superClass != null) 384 { 385 superClass.hierarchyAccept(false, 386 false, 387 true, 388 false, 389 classVisitor); 390 } 391 } 392 393 // Visit the interfaces. 394 for (int index = 0; index < u2interfacesCount; index++) 395 { 396 Clazz interfaceClass = getInterface(index); 397 if (interfaceClass != null) 398 { 399 interfaceClass.hierarchyAccept(true, 400 false, 401 true, 402 false, 403 classVisitor); 404 } 405 } 406 } 407 408 // Then visit its subclasses, recursively. 409 if (visitSubclasses) 410 { 411 if (subClasses != null) 412 { 413 for (int index = 0; index < subClasses.length; index++) 414 { 415 Clazz subClass = subClasses[index]; 416 subClass.hierarchyAccept(true, 417 false, 418 false, 419 true, 420 classVisitor); 421 } 422 } 423 } 424 } 425 426 427 public void subclassesAccept(ClassVisitor classVisitor) 428 { 429 if (subClasses != null) 430 { 431 for (int index = 0; index < subClasses.length; index++) 432 { 433 subClasses[index].accept(classVisitor); 434 } 435 } 436 } 437 438 439 public void constantPoolEntriesAccept(ConstantVisitor constantVisitor) 440 { 441 for (int index = 1; index < u2constantPoolCount; index++) 442 { 443 if (constantPool[index] != null) 444 { 445 constantPool[index].accept(this, constantVisitor); 446 } 447 } 448 } 449 450 451 public void constantPoolEntryAccept(int index, ConstantVisitor constantVisitor) 452 { 453 constantPool[index].accept(this, constantVisitor); 454 } 455 456 457 public void thisClassConstantAccept(ConstantVisitor constantVisitor) 458 { 459 constantPool[u2thisClass].accept(this, constantVisitor); 460 } 461 462 463 public void superClassConstantAccept(ConstantVisitor constantVisitor) 464 { 465 if (u2superClass != 0) 466 { 467 constantPool[u2superClass].accept(this, constantVisitor); 468 } 469 } 470 471 472 public void interfaceConstantsAccept(ConstantVisitor constantVisitor) 473 { 474 for (int index = 0; index < u2interfacesCount; index++) 475 { 476 constantPool[u2interfaces[index]].accept(this, constantVisitor); 477 } 478 } 479 480 481 public void fieldsAccept(MemberVisitor memberVisitor) 482 { 483 for (int index = 0; index < u2fieldsCount; index++) 484 { 485 fields[index].accept(this, memberVisitor); 486 } 487 } 488 489 490 public void fieldAccept(String name, String descriptor, MemberVisitor memberVisitor) 491 { 492 Field field = findField(name, descriptor); 493 if (field != null) 494 { 495 field.accept(this, memberVisitor); 496 } 497 } 498 499 500 public void methodsAccept(MemberVisitor memberVisitor) 501 { 502 for (int index = 0; index < u2methodsCount; index++) 503 { 504 methods[index].accept(this, memberVisitor); 505 } 506 } 507 508 509 public void methodAccept(String name, String descriptor, MemberVisitor memberVisitor) 510 { 511 Method method = findMethod(name, descriptor); 512 if (method != null) 513 { 514 method.accept(this, memberVisitor); 515 } 516 } 517 518 519 public boolean mayHaveImplementations(Method method) 520 { 521 return 522 (u2accessFlags & ClassConstants.INTERNAL_ACC_FINAL) == 0 && 523 (method == null || 524 ((method.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PRIVATE | 525 ClassConstants.INTERNAL_ACC_STATIC | 526 ClassConstants.INTERNAL_ACC_FINAL)) == 0 && 527 !method.getName(this).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))); 528 } 529 530 531 public void attributesAccept(AttributeVisitor attributeVisitor) 532 { 533 for (int index = 0; index < u2attributesCount; index++) 534 { 535 attributes[index].accept(this, attributeVisitor); 536 } 537 } 538 539 540 public void attributeAccept(String name, AttributeVisitor attributeVisitor) 541 { 542 for (int index = 0; index < u2attributesCount; index++) 543 { 544 Attribute attribute = attributes[index]; 545 if (attribute.getAttributeName(this).equals(name)) 546 { 547 attribute.accept(this, attributeVisitor); 548 } 549 } 550 } 551 552 553 // Implementations for VisitorAccepter. 554 555 public Object getVisitorInfo() 556 { 557 return visitorInfo; 558 } 559 560 public void setVisitorInfo(Object visitorInfo) 561 { 562 this.visitorInfo = visitorInfo; 563 } 564 565 566 // Implementations for Object. 567 568 public String toString() 569 { 570 return "ProgramClass("+getName()+")"; 571 } 572} 573