1 16 package com.google.gwt.core.ext.typeinfo; 17 18 import com.google.gwt.core.ext.UnableToCompleteException; 19 20 import java.io.UnsupportedEncodingException ; 21 import java.security.MessageDigest ; 22 import java.security.NoSuchAlgorithmException ; 23 import java.util.ArrayList ; 24 import java.util.Collection ; 25 import java.util.HashMap ; 26 import java.util.HashSet ; 27 import java.util.Iterator ; 28 import java.util.List ; 29 import java.util.Map ; 30 import java.util.Set ; 31 import java.util.TreeMap ; 32 33 36 public class JClassType extends JType implements HasMetaData { 37 private static final char[] HEX_CHARS = new char[] { 38 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 39 'E', 'F'}; 40 41 47 private static String computeStrongName(byte[] content) { 48 MessageDigest md5; 49 try { 50 md5 = MessageDigest.getInstance("MD5"); 51 } catch (NoSuchAlgorithmException e) { 52 throw new RuntimeException ("Error initializing MD5", e); 53 } 54 for (int i = 0; i < content.length; i++) { 55 md5.update(content[i]); 56 } 57 byte[] hash = md5.digest(); 58 char[] name = new char[2 * hash.length]; 61 int j = 0; 62 for (int i = 0; i < hash.length; i++) { 63 name[j++] = HEX_CHARS[(hash[i] & 0xF0) >> 4]; 64 name[j++] = HEX_CHARS[hash[i] & 0x0F]; 65 } 66 return new String (name); 67 } 68 69 private final Set allSubtypes = new HashSet (); 70 71 private final int bodyEnd; 72 73 private final int bodyStart; 74 75 private JMethod[] cachedOverridableMethods; 76 77 private final List constructors = new ArrayList (); 78 79 private final CompilationUnitProvider cup; 80 81 private final JPackage declaringPackage; 82 83 private final int declEnd; 84 85 private final int declStart; 86 87 private final JClassType enclosingType; 88 89 private final Map fields = new HashMap (); 90 91 private final List interfaces = new ArrayList (); 92 93 private final boolean isInterface; 94 95 private final boolean isLocalType; 96 97 private String lazyHash; 98 99 private String lazyQualifiedName; 100 101 private final HasMetaData metaData = new MetaData(); 102 103 private final Map methods = new HashMap (); 104 105 private int modifierBits; 106 107 private final String name; 108 109 private final String nestedName; 110 111 private final Map nestedTypes = new HashMap (); 112 113 private final TypeOracle oracle; 114 115 private JClassType superclass; 116 117 public JClassType(TypeOracle oracle, CompilationUnitProvider cup, 118 JPackage declaringPackage, JClassType enclosingType, boolean isLocalType, 119 String name, int declStart, int declEnd, int bodyStart, int bodyEnd, 120 boolean isInterface) { 121 oracle.recordTypeInCompilationUnit(cup, this); 122 this.oracle = oracle; 123 this.cup = cup; 124 this.declaringPackage = declaringPackage; 125 this.enclosingType = enclosingType; 126 this.isLocalType = isLocalType; 127 this.name = name; 128 this.declStart = declStart; 129 this.declEnd = declEnd; 130 this.bodyStart = bodyStart; 131 this.bodyEnd = bodyEnd; 132 this.isInterface = isInterface; 133 if (enclosingType == null) { 134 declaringPackage.addType(this); 137 nestedName = name; 140 } else { 141 enclosingType.addNestedType(this); 144 JClassType enclosing = enclosingType; 147 String nn = name; 148 do { 149 nn = enclosing.getSimpleSourceName() + "." + nn; 150 enclosing = enclosing.getEnclosingType(); 151 } while (enclosing != null); 152 nestedName = nn; 153 } 154 } 155 156 public void addImplementedInterface(JClassType intf) { 157 assert (intf != null); 158 interfaces.add(intf); 159 } 160 161 public void addMetaData(String tagName, String [] values) { 162 metaData.addMetaData(tagName, values); 163 } 164 165 public void addModifierBits(int bits) { 166 modifierBits |= bits; 167 } 168 169 public JConstructor findConstructor(JType[] paramTypes) { 170 JConstructor[] ctors = getConstructors(); 171 for (int i = 0; i < ctors.length; i++) { 172 JConstructor candidate = ctors[i]; 173 if (candidate.hasParamTypes(paramTypes)) { 174 return candidate; 175 } 176 } 177 return null; 178 } 179 180 public JField findField(String name) { 181 return (JField) fields.get(name); 182 } 183 184 public JMethod findMethod(String name, JType[] paramTypes) { 185 JMethod[] overloads = getOverloads(name); 186 for (int i = 0; i < overloads.length; i++) { 187 JMethod candidate = overloads[i]; 188 if (candidate.hasParamTypes(paramTypes)) { 189 return candidate; 190 } 191 } 192 return null; 193 } 194 195 public JClassType findNestedType(String typeName) { 196 String [] parts = typeName.split("\\."); 197 return findNestedTypeImpl(parts, 0); 198 } 199 200 public int getBodyEnd() { 201 return bodyEnd; 202 } 203 204 public int getBodyStart() { 205 return bodyStart; 206 } 207 208 public CompilationUnitProvider getCompilationUnit() { 209 return cup; 210 } 211 212 public JConstructor getConstructor(JType[] paramTypes) 213 throws NotFoundException { 214 JConstructor result = findConstructor(paramTypes); 215 if (result == null) { 216 throw new NotFoundException(); 217 } 218 return result; 219 } 220 221 public JConstructor[] getConstructors() { 222 return (JConstructor[]) constructors.toArray(TypeOracle.NO_JCTORS); 223 } 224 225 public JClassType getEnclosingType() { 226 return enclosingType; 227 } 228 229 public JField getField(String name) { 230 JField field = findField(name); 231 assert (field != null); 232 return field; 233 } 234 235 public JField[] getFields() { 236 return (JField[]) fields.values().toArray(TypeOracle.NO_JFIELDS); 237 } 238 239 public JClassType[] getImplementedInterfaces() { 240 return (JClassType[]) interfaces.toArray(TypeOracle.NO_JCLASSES); 241 } 242 243 public String getJNISignature() { 244 String typeName = nestedName.replace('.', '$'); 245 String packageName = getPackage().getName().replace('.', '/'); 246 if (packageName.length() > 0) { 247 packageName += "/"; 248 } 249 return "L" + packageName + typeName + ";"; 250 } 251 252 public String [][] getMetaData(String tagName) { 253 return metaData.getMetaData(tagName); 254 } 255 256 public String [] getMetaDataTags() { 257 return metaData.getMetaDataTags(); 258 } 259 260 public JMethod getMethod(String name, JType[] paramTypes) 261 throws NotFoundException { 262 JMethod result = findMethod(name, paramTypes); 263 if (result == null) { 264 throw new NotFoundException(); 265 } 266 return result; 267 } 268 269 273 public JMethod[] getMethods() { 274 List resultMethods = new ArrayList (); 275 for (Iterator iter = methods.values().iterator(); iter.hasNext();) { 276 List overloads = (List ) iter.next(); 277 resultMethods.addAll(overloads); 278 } 279 return (JMethod[]) resultMethods.toArray(TypeOracle.NO_JMETHODS); 280 } 281 282 public String getName() { 283 return nestedName; 284 } 285 286 public JClassType getNestedType(String typeName) throws NotFoundException { 287 JClassType result = findNestedType(typeName); 288 if (result == null) { 289 throw new NotFoundException(); 290 } 291 return result; 292 } 293 294 public JClassType[] getNestedTypes() { 295 return (JClassType[]) nestedTypes.values().toArray(TypeOracle.NO_JCLASSES); 296 } 297 298 public TypeOracle getOracle() { 299 return oracle; 300 } 301 302 public JMethod[] getOverloads(String name) { 303 List resultMethods = (List ) methods.get(name); 304 if (resultMethods != null) { 305 return (JMethod[]) resultMethods.toArray(TypeOracle.NO_JMETHODS); 306 } else { 307 return TypeOracle.NO_JMETHODS; 308 } 309 } 310 311 328 public JMethod[] getOverridableMethods() { 329 if (cachedOverridableMethods == null) { 330 Map methodsBySignature = new TreeMap (); 331 getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface(methodsBySignature); 332 if (isClass() != null) { 333 getOverridableMethodsOnSuperclassesAndThisClass(methodsBySignature); 334 } 335 int size = methodsBySignature.size(); 336 Collection leafMethods = methodsBySignature.values(); 337 cachedOverridableMethods = (JMethod[]) leafMethods.toArray(new JMethod[size]); 338 } 339 return cachedOverridableMethods; 340 } 341 342 public JPackage getPackage() { 343 return declaringPackage; 344 } 345 346 public String getQualifiedSourceName() { 347 if (lazyQualifiedName == null) { 348 JPackage pkg = getPackage(); 349 if (!pkg.isDefault()) { 350 lazyQualifiedName = pkg.getName() + "." + makeCompoundName(this); 351 } else { 352 lazyQualifiedName = makeCompoundName(this); 353 } 354 } 355 return lazyQualifiedName; 356 } 357 358 public String getSimpleSourceName() { 359 return name; 360 } 361 362 public JClassType[] getSubtypes() { 363 return (JClassType[]) allSubtypes.toArray(TypeOracle.NO_JCLASSES); 364 } 365 366 public JClassType getSuperclass() { 367 return superclass; 368 } 369 370 public String getTypeHash() throws UnableToCompleteException { 371 if (lazyHash == null) { 372 char[] source = cup.getSource(); 373 int length = declEnd - declStart + 1; 374 String s = new String (source, declStart, length); 375 try { 376 lazyHash = computeStrongName(s.getBytes("UTF-8")); 377 } catch (UnsupportedEncodingException e) { 378 throw new UnableToCompleteException(); 380 } 381 } 382 return lazyHash; 383 } 384 385 public boolean isAbstract() { 386 return 0 != (modifierBits & TypeOracle.MOD_ABSTRACT); 387 } 388 389 public JArrayType isArray() { 390 return null; 392 } 393 394 public boolean isAssignableFrom(JClassType possibleSubtype) { 395 if (possibleSubtype == this) { 396 return true; 397 } 398 if (allSubtypes.contains(possibleSubtype)) { 399 return true; 400 } else if (this == getOracle().getJavaLangObject()) { 401 return true; 405 } else { 406 return false; 407 } 408 } 409 410 public boolean isAssignableTo(JClassType possibleSupertype) { 411 return possibleSupertype.isAssignableFrom(this); 412 } 413 414 public JClassType isClass() { 415 return isInterface ? null : this; 416 } 417 418 430 public boolean isDefaultInstantiable() { 431 if (isInterface() != null) { 432 return false; 433 } 434 if (constructors.isEmpty()) { 435 return true; 436 } 437 JConstructor ctor = findConstructor(TypeOracle.NO_JTYPES); 438 if (ctor != null) { 439 return true; 440 } 441 return false; 442 } 443 444 public JClassType isInterface() { 445 return isInterface ? this : null; 446 } 447 448 454 public boolean isLocalType() { 455 return isLocalType; 456 } 457 458 464 public boolean isMemberType() { 465 return enclosingType != null; 466 } 467 468 public JParameterizedType isParameterized() { 469 return null; 471 } 472 473 public JPrimitiveType isPrimitive() { 474 return null; 476 } 477 478 public boolean isPrivate() { 479 return 0 != (modifierBits & TypeOracle.MOD_PRIVATE); 480 } 481 482 public boolean isProtected() { 483 return 0 != (modifierBits & TypeOracle.MOD_PROTECTED); 484 } 485 486 public boolean isPublic() { 487 return 0 != (modifierBits & TypeOracle.MOD_PUBLIC); 488 } 489 490 public boolean isStatic() { 491 return 0 != (modifierBits & TypeOracle.MOD_STATIC); 492 } 493 494 public void setSuperclass(JClassType type) { 495 assert (type != null); 496 assert (isInterface() == null); 497 this.superclass = type; 498 } 499 500 public String toString() { 501 if (isInterface) { 502 return "interface " + getQualifiedSourceName(); 503 } else { 504 return "class " + getQualifiedSourceName(); 505 } 506 } 507 508 protected int getModifierBits() { 509 return modifierBits; 510 } 511 512 void addConstructor(JConstructor ctor) { 513 assert (!constructors.contains(ctor)); 514 constructors.add(ctor); 515 } 516 517 void addField(JField field) { 518 Object existing = fields.put(field.getName(), field); 519 assert (existing == null); 520 } 521 522 void addMethod(JMethod method) { 523 String methodName = method.getName(); 524 List overloads = (List ) methods.get(methodName); 525 if (overloads == null) { 526 overloads = new ArrayList (); 527 methods.put(methodName, overloads); 528 } 529 overloads.add(method); 530 } 531 532 void addNestedType(JClassType type) { 533 Object existing = nestedTypes.put(type.getSimpleSourceName(), type); 534 } 535 536 JClassType findNestedTypeImpl(String [] typeName, int index) { 537 JClassType found = (JClassType) nestedTypes.get(typeName[index]); 538 if (found == null) { 539 return null; 540 } else if (index < typeName.length - 1) { 541 return found.findNestedTypeImpl(typeName, index + 1); 542 } else { 543 return found; 544 } 545 } 546 547 void notifySuperTypes() { 548 notifySuperTypesOf(this); 549 } 550 551 554 void removeFromSupertypes() { 555 removeSubtype(this); 556 } 557 558 private void acceptSubtype(JClassType me) { 559 allSubtypes.add(me); 560 notifySuperTypesOf(me); 561 } 562 563 private String computeInternalSignature(JMethod method) { 564 StringBuffer sb = new StringBuffer (); 565 sb.setLength(0); 566 sb.append(method.getName()); 567 JParameter[] params = method.getParameters(); 568 for (int j = 0; j < params.length; j++) { 569 JParameter param = params[j]; 570 sb.append("/"); 571 sb.append(param.getType().getQualifiedSourceName()); 572 } 573 return sb.toString(); 574 } 575 576 private void getOverridableMethodsOnSuperclassesAndThisClass( 577 Map methodsBySignature) { 578 assert (isClass() != null); 579 580 JClassType superClass = getSuperclass(); 583 if (superClass != null) { 584 superClass.getOverridableMethodsOnSuperclassesAndThisClass(methodsBySignature); 585 } 586 587 JMethod[] declaredMethods = getMethods(); 588 for (int i = 0; i < declaredMethods.length; i++) { 589 JMethod method = declaredMethods[i]; 590 591 if (method.isFinal() || method.isPrivate()) { 593 continue; 595 } 596 597 String sig = computeInternalSignature(method); 599 methodsBySignature.put(sig, method); 600 } 601 } 602 603 611 private void getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface( 612 Map methodsBySignature) { 613 JClassType[] superIntfs = getImplementedInterfaces(); 616 for (int i = 0; i < superIntfs.length; i++) { 617 JClassType superIntf = superIntfs[i]; 618 superIntf.getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface(methodsBySignature); 619 } 620 621 if (isInterface() == null) { 622 return; 625 } 626 627 JMethod[] declaredMethods = getMethods(); 628 for (int i = 0; i < declaredMethods.length; i++) { 629 JMethod method = declaredMethods[i]; 630 631 String sig = computeInternalSignature(method); 632 JMethod existing = (JMethod) methodsBySignature.get(sig); 633 if (existing != null) { 634 JClassType existingType = existing.getEnclosingType(); 635 JClassType thisType = method.getEnclosingType(); 636 if (thisType.isAssignableFrom(existingType)) { 637 continue; 639 } 640 } 641 methodsBySignature.put(sig, method); 642 } 643 } 644 645 private String makeCompoundName(JClassType type) { 646 if (type.enclosingType == null) { 647 return type.name; 648 } else { 649 return makeCompoundName(type.enclosingType) + "." + type.name; 650 } 651 } 652 653 656 private void notifySuperTypesOf(JClassType me) { 657 if (superclass != null) { 658 superclass.acceptSubtype(me); 659 } 660 for (int i = 0, n = interfaces.size(); i < n; ++i) { 661 JClassType intf = (JClassType) interfaces.get(i); 662 intf.acceptSubtype(me); 663 } 664 } 665 666 private void removeSubtype(JClassType me) { 667 allSubtypes.remove(me); 668 669 if (superclass != null) { 670 superclass.removeSubtype(me); 671 } 672 673 for (int i = 0, n = interfaces.size(); i < n; ++i) { 674 JClassType intf = (JClassType) interfaces.get(i); 675 676 intf.removeSubtype(me); 677 } 678 } 679 } 680 | Popular Tags |