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