1/* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2014 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 getRefClassName(int constantIndex) 174 { 175 try 176 { 177 return ((RefConstant)constantPool[constantIndex]).getClassName(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 getRefName(int constantIndex) 186 { 187 try 188 { 189 return ((RefConstant)constantPool[constantIndex]).getName(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 public String getRefType(int constantIndex) 198 { 199 try 200 { 201 return ((RefConstant)constantPool[constantIndex]).getType(this); 202 } 203 catch (ClassCastException ex) 204 { 205 throw ((IllegalStateException)new IllegalStateException("Expected RefConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex)); 206 } 207 } 208 209 210 public void addSubClass(Clazz clazz) 211 { 212 if (subClasses == null) 213 { 214 subClasses = new Clazz[1]; 215 } 216 else 217 { 218 // Copy the old elements into new larger array. 219 Clazz[] temp = new Clazz[subClasses.length+1]; 220 System.arraycopy(subClasses, 0, temp, 0, subClasses.length); 221 subClasses = temp; 222 } 223 224 subClasses[subClasses.length-1] = clazz; 225 } 226 227 228 public Clazz getSuperClass() 229 { 230 return u2superClass != 0 ? 231 ((ClassConstant)constantPool[u2superClass]).referencedClass : 232 null; 233 } 234 235 236 public Clazz getInterface(int index) 237 { 238 return ((ClassConstant)constantPool[u2interfaces[index]]).referencedClass; 239 } 240 241 242 public boolean extends_(Clazz clazz) 243 { 244 if (this.equals(clazz)) 245 { 246 return true; 247 } 248 249 Clazz superClass = getSuperClass(); 250 return superClass != null && 251 superClass.extends_(clazz); 252 } 253 254 255 public boolean extends_(String className) 256 { 257 if (getName().equals(className)) 258 { 259 return true; 260 } 261 262 Clazz superClass = getSuperClass(); 263 return superClass != null && 264 superClass.extends_(className); 265 } 266 267 268 public boolean extendsOrImplements(Clazz clazz) 269 { 270 if (this.equals(clazz)) 271 { 272 return true; 273 } 274 275 Clazz superClass = getSuperClass(); 276 if (superClass != null && 277 superClass.extendsOrImplements(clazz)) 278 { 279 return true; 280 } 281 282 for (int index = 0; index < u2interfacesCount; index++) 283 { 284 Clazz interfaceClass = getInterface(index); 285 if (interfaceClass != null && 286 interfaceClass.extendsOrImplements(clazz)) 287 { 288 return true; 289 } 290 } 291 292 return false; 293 } 294 295 296 public boolean extendsOrImplements(String className) 297 { 298 if (getName().equals(className)) 299 { 300 return true; 301 } 302 303 Clazz superClass = getSuperClass(); 304 if (superClass != null && 305 superClass.extendsOrImplements(className)) 306 { 307 return true; 308 } 309 310 for (int index = 0; index < u2interfacesCount; index++) 311 { 312 Clazz interfaceClass = getInterface(index); 313 if (interfaceClass != null && 314 interfaceClass.extendsOrImplements(className)) 315 { 316 return true; 317 } 318 } 319 320 return false; 321 } 322 323 324 public Field findField(String name, String descriptor) 325 { 326 for (int index = 0; index < u2fieldsCount; index++) 327 { 328 Field field = fields[index]; 329 if ((name == null || field.getName(this).equals(name)) && 330 (descriptor == null || field.getDescriptor(this).equals(descriptor))) 331 { 332 return field; 333 } 334 } 335 336 return null; 337 } 338 339 340 public Method findMethod(String name, String descriptor) 341 { 342 for (int index = 0; index < u2methodsCount; index++) 343 { 344 Method method = methods[index]; 345 if ((name == null || method.getName(this).equals(name)) && 346 (descriptor == null || method.getDescriptor(this).equals(descriptor))) 347 { 348 return method; 349 } 350 } 351 352 return null; 353 } 354 355 356 public void accept(ClassVisitor classVisitor) 357 { 358 classVisitor.visitProgramClass(this); 359 } 360 361 362 public void hierarchyAccept(boolean visitThisClass, 363 boolean visitSuperClass, 364 boolean visitInterfaces, 365 boolean visitSubclasses, 366 ClassVisitor classVisitor) 367 { 368 // First visit the current classfile. 369 if (visitThisClass) 370 { 371 accept(classVisitor); 372 } 373 374 // Then visit its superclass, recursively. 375 if (visitSuperClass) 376 { 377 Clazz superClass = getSuperClass(); 378 if (superClass != null) 379 { 380 superClass.hierarchyAccept(true, 381 true, 382 visitInterfaces, 383 false, 384 classVisitor); 385 } 386 } 387 388 // Then visit its interfaces, recursively. 389 if (visitInterfaces) 390 { 391 // Visit the interfaces of the superclasses, if we haven't done so yet. 392 if (!visitSuperClass) 393 { 394 Clazz superClass = getSuperClass(); 395 if (superClass != null) 396 { 397 superClass.hierarchyAccept(false, 398 false, 399 true, 400 false, 401 classVisitor); 402 } 403 } 404 405 // Visit the interfaces. 406 for (int index = 0; index < u2interfacesCount; index++) 407 { 408 Clazz interfaceClass = getInterface(index); 409 if (interfaceClass != null) 410 { 411 interfaceClass.hierarchyAccept(true, 412 false, 413 true, 414 false, 415 classVisitor); 416 } 417 } 418 } 419 420 // Then visit its subclasses, recursively. 421 if (visitSubclasses) 422 { 423 if (subClasses != null) 424 { 425 for (int index = 0; index < subClasses.length; index++) 426 { 427 Clazz subClass = subClasses[index]; 428 subClass.hierarchyAccept(true, 429 false, 430 false, 431 true, 432 classVisitor); 433 } 434 } 435 } 436 } 437 438 439 public void subclassesAccept(ClassVisitor classVisitor) 440 { 441 if (subClasses != null) 442 { 443 for (int index = 0; index < subClasses.length; index++) 444 { 445 subClasses[index].accept(classVisitor); 446 } 447 } 448 } 449 450 451 public void constantPoolEntriesAccept(ConstantVisitor constantVisitor) 452 { 453 for (int index = 1; index < u2constantPoolCount; index++) 454 { 455 if (constantPool[index] != null) 456 { 457 constantPool[index].accept(this, constantVisitor); 458 } 459 } 460 } 461 462 463 public void constantPoolEntryAccept(int index, ConstantVisitor constantVisitor) 464 { 465 constantPool[index].accept(this, constantVisitor); 466 } 467 468 469 public void thisClassConstantAccept(ConstantVisitor constantVisitor) 470 { 471 constantPool[u2thisClass].accept(this, constantVisitor); 472 } 473 474 475 public void superClassConstantAccept(ConstantVisitor constantVisitor) 476 { 477 if (u2superClass != 0) 478 { 479 constantPool[u2superClass].accept(this, constantVisitor); 480 } 481 } 482 483 484 public void interfaceConstantsAccept(ConstantVisitor constantVisitor) 485 { 486 for (int index = 0; index < u2interfacesCount; index++) 487 { 488 constantPool[u2interfaces[index]].accept(this, constantVisitor); 489 } 490 } 491 492 493 public void fieldsAccept(MemberVisitor memberVisitor) 494 { 495 for (int index = 0; index < u2fieldsCount; index++) 496 { 497 fields[index].accept(this, memberVisitor); 498 } 499 } 500 501 502 public void fieldAccept(String name, String descriptor, MemberVisitor memberVisitor) 503 { 504 Field field = findField(name, descriptor); 505 if (field != null) 506 { 507 field.accept(this, memberVisitor); 508 } 509 } 510 511 512 public void methodsAccept(MemberVisitor memberVisitor) 513 { 514 for (int index = 0; index < u2methodsCount; index++) 515 { 516 methods[index].accept(this, memberVisitor); 517 } 518 } 519 520 521 public void methodAccept(String name, String descriptor, MemberVisitor memberVisitor) 522 { 523 Method method = findMethod(name, descriptor); 524 if (method != null) 525 { 526 method.accept(this, memberVisitor); 527 } 528 } 529 530 531 public boolean mayHaveImplementations(Method method) 532 { 533 return 534 (u2accessFlags & ClassConstants.ACC_FINAL) == 0 && 535 (method == null || 536 ((method.getAccessFlags() & (ClassConstants.ACC_PRIVATE | 537 ClassConstants.ACC_STATIC | 538 ClassConstants.ACC_FINAL)) == 0 && 539 !method.getName(this).equals(ClassConstants.METHOD_NAME_INIT))); 540 } 541 542 543 public void attributesAccept(AttributeVisitor attributeVisitor) 544 { 545 for (int index = 0; index < u2attributesCount; index++) 546 { 547 attributes[index].accept(this, attributeVisitor); 548 } 549 } 550 551 552 public void attributeAccept(String name, AttributeVisitor attributeVisitor) 553 { 554 for (int index = 0; index < u2attributesCount; index++) 555 { 556 Attribute attribute = attributes[index]; 557 if (attribute.getAttributeName(this).equals(name)) 558 { 559 attribute.accept(this, attributeVisitor); 560 } 561 } 562 } 563 564 565 // Implementations for VisitorAccepter. 566 567 public Object getVisitorInfo() 568 { 569 return visitorInfo; 570 } 571 572 public void setVisitorInfo(Object visitorInfo) 573 { 574 this.visitorInfo = visitorInfo; 575 } 576 577 578 // Implementations for Object. 579 580 public String toString() 581 { 582 return "ProgramClass("+getName()+")"; 583 } 584} 585