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.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.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 getRefClassName(int constantIndex) 141 { 142 throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); 143 } 144 145 public String getRefName(int constantIndex) 146 { 147 throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); 148 } 149 150 public String getRefType(int constantIndex) 151 { 152 throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); 153 } 154 155 156 public void addSubClass(Clazz clazz) 157 { 158 if (subClasses == null) 159 { 160 subClasses = new Clazz[1]; 161 } 162 else 163 { 164 // Copy the old elements into new larger array. 165 Clazz[] temp = new Clazz[subClasses.length+1]; 166 System.arraycopy(subClasses, 0, temp, 0, subClasses.length); 167 subClasses = temp; 168 } 169 170 subClasses[subClasses.length-1] = clazz; 171 } 172 173 174 public Clazz getSuperClass() 175 { 176 return superClass; 177 } 178 179 180 public Clazz getInterface(int index) 181 { 182 return interfaceClasses[index]; 183 } 184 185 186 public boolean extends_(Clazz clazz) 187 { 188 if (this.equals(clazz)) 189 { 190 return true; 191 } 192 193 return superClass != null && 194 superClass.extends_(clazz); 195 } 196 197 198 public boolean extends_(String className) 199 { 200 if (getName().equals(className)) 201 { 202 return true; 203 } 204 205 return superClass != null && 206 superClass.extends_(className); 207 } 208 209 210 public boolean extendsOrImplements(Clazz clazz) 211 { 212 if (this.equals(clazz)) 213 { 214 return true; 215 } 216 217 if (superClass != null && 218 superClass.extendsOrImplements(clazz)) 219 { 220 return true; 221 } 222 223 if (interfaceClasses != null) 224 { 225 for (int index = 0; index < interfaceClasses.length; index++) 226 { 227 Clazz interfaceClass = interfaceClasses[index]; 228 if (interfaceClass != null && 229 interfaceClass.extendsOrImplements(clazz)) 230 { 231 return true; 232 } 233 } 234 } 235 236 return false; 237 } 238 239 240 public boolean extendsOrImplements(String className) 241 { 242 if (getName().equals(className)) 243 { 244 return true; 245 } 246 247 if (superClass != null && 248 superClass.extendsOrImplements(className)) 249 { 250 return true; 251 } 252 253 if (interfaceClasses != null) 254 { 255 for (int index = 0; index < interfaceClasses.length; index++) 256 { 257 Clazz interfaceClass = interfaceClasses[index]; 258 if (interfaceClass != null && 259 interfaceClass.extendsOrImplements(className)) 260 { 261 return true; 262 } 263 } 264 } 265 266 return false; 267 } 268 269 270 public Field findField(String name, String descriptor) 271 { 272 for (int index = 0; index < fields.length; index++) 273 { 274 Field field = fields[index]; 275 if (field != null && 276 (name == null || field.getName(this).equals(name)) && 277 (descriptor == null || field.getDescriptor(this).equals(descriptor))) 278 { 279 return field; 280 } 281 } 282 283 return null; 284 } 285 286 287 public Method findMethod(String name, String descriptor) 288 { 289 for (int index = 0; index < methods.length; index++) 290 { 291 Method method = methods[index]; 292 if (method != null && 293 (name == null || method.getName(this).equals(name)) && 294 (descriptor == null || method.getDescriptor(this).equals(descriptor))) 295 { 296 return method; 297 } 298 } 299 300 return null; 301 } 302 303 304 public void accept(ClassVisitor classVisitor) 305 { 306 classVisitor.visitLibraryClass(this); 307 } 308 309 310 public void hierarchyAccept(boolean visitThisClass, 311 boolean visitSuperClass, 312 boolean visitInterfaces, 313 boolean visitSubclasses, 314 ClassVisitor classVisitor) 315 { 316 // First visit the current classfile. 317 if (visitThisClass) 318 { 319 accept(classVisitor); 320 } 321 322 // Then visit its superclass, recursively. 323 if (visitSuperClass) 324 { 325 if (superClass != null) 326 { 327 superClass.hierarchyAccept(true, 328 true, 329 visitInterfaces, 330 false, 331 classVisitor); 332 } 333 } 334 335 // Then visit its interfaces, recursively. 336 if (visitInterfaces) 337 { 338 // Visit the interfaces of the superclasses, if we haven't done so yet. 339 if (!visitSuperClass) 340 { 341 if (superClass != null) 342 { 343 superClass.hierarchyAccept(false, 344 false, 345 true, 346 false, 347 classVisitor); 348 } 349 } 350 351 // Visit the interfaces. 352 if (interfaceClasses != null) 353 { 354 for (int index = 0; index < interfaceClasses.length; index++) 355 { 356 Clazz interfaceClass = interfaceClasses[index]; 357 if (interfaceClass != null) 358 { 359 interfaceClass.hierarchyAccept(true, 360 false, 361 true, 362 false, 363 classVisitor); 364 } 365 } 366 } 367 } 368 369 // Then visit its subclasses, recursively. 370 if (visitSubclasses) 371 { 372 if (subClasses != null) 373 { 374 for (int index = 0; index < subClasses.length; index++) 375 { 376 subClasses[index].hierarchyAccept(true, 377 false, 378 false, 379 true, 380 classVisitor); 381 } 382 } 383 } 384 } 385 386 387 /** 388 * Lets the given class visitor visit the superclass, if it is known. 389 * @param classVisitor the <code>ClassVisitor</code> that will visit the 390 * superclass. 391 */ 392 public void superClassAccept(ClassVisitor classVisitor) 393 { 394 if (superClass != null) 395 { 396 superClass.accept(classVisitor); 397 } 398 } 399 400 401 /** 402 * Lets the given class visitor visit all known direct interfaces. 403 * @param classVisitor the <code>ClassVisitor</code> that will visit the 404 * interfaces. 405 */ 406 public void interfacesAccept(ClassVisitor classVisitor) 407 { 408 if (interfaceClasses != null) 409 { 410 for (int index = 0; index < interfaceClasses.length; index++) 411 { 412 Clazz interfaceClass = interfaceClasses[index]; 413 if (interfaceClass != null) 414 { 415 interfaceClass.accept(classVisitor); 416 } 417 } 418 } 419 } 420 421 422 public void subclassesAccept(ClassVisitor classVisitor) 423 { 424 if (subClasses != null) 425 { 426 for (int index = 0; index < subClasses.length; index++) 427 { 428 subClasses[index].accept(classVisitor); 429 } 430 } 431 } 432 433 434 public void constantPoolEntriesAccept(ConstantVisitor constantVisitor) 435 { 436 // This class doesn't keep references to its constant pool entries. 437 } 438 439 440 public void constantPoolEntryAccept(int index, ConstantVisitor constantVisitor) 441 { 442 // This class doesn't keep references to its constant pool entries. 443 } 444 445 446 public void thisClassConstantAccept(ConstantVisitor constantVisitor) 447 { 448 // This class doesn't keep references to its constant pool entries. 449 } 450 451 452 public void superClassConstantAccept(ConstantVisitor constantVisitor) 453 { 454 // This class doesn't keep references to its constant pool entries. 455 } 456 457 458 public void interfaceConstantsAccept(ConstantVisitor constantVisitor) 459 { 460 // This class doesn't keep references to its constant pool entries. 461 } 462 463 464 public void fieldsAccept(MemberVisitor memberVisitor) 465 { 466 for (int index = 0; index < fields.length; index++) 467 { 468 Field field = fields[index]; 469 if (field != null) 470 { 471 field.accept(this, memberVisitor); 472 } 473 } 474 } 475 476 477 public void fieldAccept(String name, String descriptor, MemberVisitor memberVisitor) 478 { 479 Field field = findField(name, descriptor); 480 if (field != null) 481 { 482 field.accept(this, memberVisitor); 483 } 484 } 485 486 487 public void methodsAccept(MemberVisitor memberVisitor) 488 { 489 for (int index = 0; index < methods.length; index++) 490 { 491 Method method = methods[index]; 492 if (method != null) 493 { 494 method.accept(this, memberVisitor); 495 } 496 } 497 } 498 499 500 public void methodAccept(String name, String descriptor, MemberVisitor memberVisitor) 501 { 502 Method method = findMethod(name, descriptor); 503 if (method != null) 504 { 505 method.accept(this, memberVisitor); 506 } 507 } 508 509 510 public boolean mayHaveImplementations(Method method) 511 { 512 return 513 (u2accessFlags & ClassConstants.ACC_FINAL) == 0 && 514 (method == null || 515 ((method.getAccessFlags() & (ClassConstants.ACC_PRIVATE | 516 ClassConstants.ACC_STATIC | 517 ClassConstants.ACC_FINAL)) == 0 && 518 !method.getName(this).equals(ClassConstants.METHOD_NAME_INIT))); 519 } 520 521 522 public void attributesAccept(AttributeVisitor attributeVisitor) 523 { 524 throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store attributes"); 525 } 526 527 528 public void attributeAccept(String name, AttributeVisitor attributeVisitor) 529 { 530 throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store attributes"); 531 } 532 533 534 // Implementations for VisitorAccepter. 535 536 public Object getVisitorInfo() 537 { 538 return visitorInfo; 539 } 540 541 public void setVisitorInfo(Object visitorInfo) 542 { 543 this.visitorInfo = visitorInfo; 544 } 545 546 547 // Implementations for Object. 548 549 public String toString() 550 { 551 return "LibraryClass("+getName()+")"; 552 } 553} 554