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.visitor.AttributeVisitor; 24import proguard.classfile.constant.visitor.ConstantVisitor; 25import proguard.classfile.util.*; 26import proguard.classfile.visitor.*; 27 28/** 29 * This Clazz is a compact representation of the essential data in a Java class. 30 * 31 * @author Eric Lafortune 32 */ 33public class LibraryClass implements Clazz 34{ 35 public int u2accessFlags; 36 public String thisClassName; 37 public String superClassName; 38 public String[] interfaceNames; 39 public LibraryField[] fields; 40 public LibraryMethod[] methods; 41 42 /** 43 * An extra field pointing to the superclass of this class. 44 * This field is filled out by the {@link ClassSuperHierarchyInitializer}. 45 */ 46 public Clazz superClass; 47 48 /** 49 * An extra field pointing to the interfaces of this class. 50 * This field is filled out by the {@link ClassSuperHierarchyInitializer}. 51 */ 52 public Clazz[] interfaceClasses; 53 54 /** 55 * An extra field pointing to the subclasses of this class. 56 * This field is filled out by the {@link ClassSubHierarchyInitializer}. 57 */ 58 public Clazz[] subClasses; 59 60 /** 61 * An extra field in which visitors can store information. 62 */ 63 public Object visitorInfo; 64 65 66 /** 67 * Creates an empty LibraryClass. 68 */ 69 public LibraryClass() {} 70 71 72 /** 73 * Returns whether this library class is visible to the outside world. 74 */ 75 boolean isVisible() 76 { 77 return (u2accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) != 0; 78 } 79 80 81 // Implementations for Clazz. 82 83 public int getAccessFlags() 84 { 85 return u2accessFlags; 86 } 87 88 public String getName() 89 { 90 return thisClassName; 91 } 92 93 public String getSuperName() 94 { 95 // This may be java/lang/Object, in which case there is no super. 96 return superClassName; 97 } 98 99 public int getInterfaceCount() 100 { 101 return interfaceClasses.length; 102 } 103 104 public String getInterfaceName(int index) 105 { 106 return interfaceNames[index]; 107 } 108 109 public int getTag(int constantIndex) 110 { 111 throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); 112 } 113 114 public String getString(int constantIndex) 115 { 116 throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); 117 } 118 119 public String getStringString(int constantIndex) 120 { 121 throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); 122 } 123 124 public String getClassName(int constantIndex) 125 { 126 throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); 127 } 128 129 public String getName(int constantIndex) 130 { 131 throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); 132 } 133 134 public String getType(int constantIndex) 135 { 136 throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); 137 } 138 139 140 public String getRefName(int constantIndex) 141 { 142 throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); 143 } 144 145 public String getRefType(int constantIndex) 146 { 147 throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); 148 } 149 150 151 public void addSubClass(Clazz clazz) 152 { 153 if (subClasses == null) 154 { 155 subClasses = new Clazz[1]; 156 } 157 else 158 { 159 // Copy the old elements into new larger array. 160 Clazz[] temp = new Clazz[subClasses.length+1]; 161 System.arraycopy(subClasses, 0, temp, 0, subClasses.length); 162 subClasses = temp; 163 } 164 165 subClasses[subClasses.length-1] = clazz; 166 } 167 168 169 public Clazz getSuperClass() 170 { 171 return superClass; 172 } 173 174 175 public Clazz getInterface(int index) 176 { 177 return interfaceClasses[index]; 178 } 179 180 181 public boolean extends_(Clazz clazz) 182 { 183 if (this.equals(clazz)) 184 { 185 return true; 186 } 187 188 return superClass != null && 189 superClass.extends_(clazz); 190 } 191 192 193 public boolean extends_(String className) 194 { 195 if (getName().equals(className)) 196 { 197 return true; 198 } 199 200 return superClass != null && 201 superClass.extends_(className); 202 } 203 204 205 public boolean extendsOrImplements(Clazz clazz) 206 { 207 if (this.equals(clazz)) 208 { 209 return true; 210 } 211 212 if (superClass != null && 213 superClass.extendsOrImplements(clazz)) 214 { 215 return true; 216 } 217 218 if (interfaceClasses != null) 219 { 220 for (int index = 0; index < interfaceClasses.length; index++) 221 { 222 Clazz interfaceClass = interfaceClasses[index]; 223 if (interfaceClass != null && 224 interfaceClass.extendsOrImplements(clazz)) 225 { 226 return true; 227 } 228 } 229 } 230 231 return false; 232 } 233 234 235 public boolean extendsOrImplements(String className) 236 { 237 if (getName().equals(className)) 238 { 239 return true; 240 } 241 242 if (superClass != null && 243 superClass.extendsOrImplements(className)) 244 { 245 return true; 246 } 247 248 if (interfaceClasses != null) 249 { 250 for (int index = 0; index < interfaceClasses.length; index++) 251 { 252 Clazz interfaceClass = interfaceClasses[index]; 253 if (interfaceClass != null && 254 interfaceClass.extendsOrImplements(className)) 255 { 256 return true; 257 } 258 } 259 } 260 261 return false; 262 } 263 264 265 public Field findField(String name, String descriptor) 266 { 267 for (int index = 0; index < fields.length; index++) 268 { 269 Field field = fields[index]; 270 if (field != null && 271 (name == null || field.getName(this).equals(name)) && 272 (descriptor == null || field.getDescriptor(this).equals(descriptor))) 273 { 274 return field; 275 } 276 } 277 278 return null; 279 } 280 281 282 public Method findMethod(String name, String descriptor) 283 { 284 for (int index = 0; index < methods.length; index++) 285 { 286 Method method = methods[index]; 287 if (method != null && 288 (name == null || method.getName(this).equals(name)) && 289 (descriptor == null || method.getDescriptor(this).equals(descriptor))) 290 { 291 return method; 292 } 293 } 294 295 return null; 296 } 297 298 299 public void accept(ClassVisitor classVisitor) 300 { 301 classVisitor.visitLibraryClass(this); 302 } 303 304 305 public void hierarchyAccept(boolean visitThisClass, 306 boolean visitSuperClass, 307 boolean visitInterfaces, 308 boolean visitSubclasses, 309 ClassVisitor classVisitor) 310 { 311 // First visit the current classfile. 312 if (visitThisClass) 313 { 314 accept(classVisitor); 315 } 316 317 // Then visit its superclass, recursively. 318 if (visitSuperClass) 319 { 320 if (superClass != null) 321 { 322 superClass.hierarchyAccept(true, 323 true, 324 visitInterfaces, 325 false, 326 classVisitor); 327 } 328 } 329 330 // Then visit its interfaces, recursively. 331 if (visitInterfaces) 332 { 333 // Visit the interfaces of the superclasses, if we haven't done so yet. 334 if (!visitSuperClass) 335 { 336 if (superClass != null) 337 { 338 superClass.hierarchyAccept(false, 339 false, 340 true, 341 false, 342 classVisitor); 343 } 344 } 345 346 // Visit the interfaces. 347 if (interfaceClasses != null) 348 { 349 for (int index = 0; index < interfaceClasses.length; index++) 350 { 351 Clazz interfaceClass = interfaceClasses[index]; 352 if (interfaceClass != null) 353 { 354 interfaceClass.hierarchyAccept(true, 355 false, 356 true, 357 false, 358 classVisitor); 359 } 360 } 361 } 362 } 363 364 // Then visit its subclasses, recursively. 365 if (visitSubclasses) 366 { 367 if (subClasses != null) 368 { 369 for (int index = 0; index < subClasses.length; index++) 370 { 371 subClasses[index].hierarchyAccept(true, 372 false, 373 false, 374 true, 375 classVisitor); 376 } 377 } 378 } 379 } 380 381 382 /** 383 * Lets the given class visitor visit the superclass, if it is known. 384 * @param classVisitor the <code>ClassVisitor</code> that will visit the 385 * superclass. 386 */ 387 public void superClassAccept(ClassVisitor classVisitor) 388 { 389 if (superClass != null) 390 { 391 superClass.accept(classVisitor); 392 } 393 } 394 395 396 /** 397 * Lets the given class visitor visit all known direct interfaces. 398 * @param classVisitor the <code>ClassVisitor</code> that will visit the 399 * interfaces. 400 */ 401 public void interfacesAccept(ClassVisitor classVisitor) 402 { 403 if (interfaceClasses != null) 404 { 405 for (int index = 0; index < interfaceClasses.length; index++) 406 { 407 Clazz interfaceClass = interfaceClasses[index]; 408 if (interfaceClass != null) 409 { 410 interfaceClass.accept(classVisitor); 411 } 412 } 413 } 414 } 415 416 417 public void subclassesAccept(ClassVisitor classVisitor) 418 { 419 if (subClasses != null) 420 { 421 for (int index = 0; index < subClasses.length; index++) 422 { 423 subClasses[index].accept(classVisitor); 424 } 425 } 426 } 427 428 429 public void constantPoolEntriesAccept(ConstantVisitor constantVisitor) 430 { 431 // This class doesn't keep references to its constant pool entries. 432 } 433 434 435 public void constantPoolEntryAccept(int index, ConstantVisitor constantVisitor) 436 { 437 // This class doesn't keep references to its constant pool entries. 438 } 439 440 441 public void thisClassConstantAccept(ConstantVisitor constantVisitor) 442 { 443 // This class doesn't keep references to its constant pool entries. 444 } 445 446 447 public void superClassConstantAccept(ConstantVisitor constantVisitor) 448 { 449 // This class doesn't keep references to its constant pool entries. 450 } 451 452 453 public void interfaceConstantsAccept(ConstantVisitor constantVisitor) 454 { 455 // This class doesn't keep references to its constant pool entries. 456 } 457 458 459 public void fieldsAccept(MemberVisitor memberVisitor) 460 { 461 for (int index = 0; index < fields.length; index++) 462 { 463 Field field = fields[index]; 464 if (field != null) 465 { 466 field.accept(this, memberVisitor); 467 } 468 } 469 } 470 471 472 public void fieldAccept(String name, String descriptor, MemberVisitor memberVisitor) 473 { 474 Field field = findField(name, descriptor); 475 if (field != null) 476 { 477 field.accept(this, memberVisitor); 478 } 479 } 480 481 482 public void methodsAccept(MemberVisitor memberVisitor) 483 { 484 for (int index = 0; index < methods.length; index++) 485 { 486 Method method = methods[index]; 487 if (method != null) 488 { 489 method.accept(this, memberVisitor); 490 } 491 } 492 } 493 494 495 public void methodAccept(String name, String descriptor, MemberVisitor memberVisitor) 496 { 497 Method method = findMethod(name, descriptor); 498 if (method != null) 499 { 500 method.accept(this, memberVisitor); 501 } 502 } 503 504 505 public boolean mayHaveImplementations(Method method) 506 { 507 return 508 (u2accessFlags & ClassConstants.INTERNAL_ACC_FINAL) == 0 && 509 (method == null || 510 ((method.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PRIVATE | 511 ClassConstants.INTERNAL_ACC_STATIC | 512 ClassConstants.INTERNAL_ACC_FINAL)) == 0 && 513 !method.getName(this).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))); 514 } 515 516 517 public void attributesAccept(AttributeVisitor attributeVisitor) 518 { 519 throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store attributes"); 520 } 521 522 523 public void attributeAccept(String name, AttributeVisitor attributeVisitor) 524 { 525 throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store attributes"); 526 } 527 528 529 // Implementations for VisitorAccepter. 530 531 public Object getVisitorInfo() 532 { 533 return visitorInfo; 534 } 535 536 public void setVisitorInfo(Object visitorInfo) 537 { 538 this.visitorInfo = visitorInfo; 539 } 540 541 542 // Implementations for Object. 543 544 public String toString() 545 { 546 return "LibraryClass("+getName()+")"; 547 } 548} 549