| 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2008, 2009 IBM Corporation and others. |
| 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the Eclipse Public License v1.0 |
| 5 | * which accompanies this distribution, and is available at |
| 6 | * http://www.eclipse.org/legal/epl-v10.html |
| 7 | * |
| 8 | * Contributors: |
| 9 | * IBM Corporation - initial API and implementation |
| 10 | *******************************************************************************/ |
| 11 | package org.eclipse.pde.api.tools.internal.model; |
| 12 | |
| 13 | import java.util.HashMap; |
| 14 | import java.util.HashSet; |
| 15 | import java.util.Iterator; |
| 16 | import java.util.LinkedHashMap; |
| 17 | import java.util.LinkedList; |
| 18 | import java.util.List; |
| 19 | import java.util.Map; |
| 20 | |
| 21 | import org.eclipse.core.runtime.CoreException; |
| 22 | import org.eclipse.core.runtime.IProgressMonitor; |
| 23 | import org.eclipse.core.runtime.IStatus; |
| 24 | import org.eclipse.core.runtime.Status; |
| 25 | import org.eclipse.pde.api.tools.internal.builder.ReferenceExtractor; |
| 26 | import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin; |
| 27 | import org.eclipse.pde.api.tools.internal.provisional.descriptors.IMemberDescriptor; |
| 28 | import org.eclipse.pde.api.tools.internal.provisional.descriptors.IReferenceTypeDescriptor; |
| 29 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent; |
| 30 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiElement; |
| 31 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiField; |
| 32 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiMethod; |
| 33 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiType; |
| 34 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiTypeRoot; |
| 35 | import org.eclipse.pde.api.tools.internal.util.Signatures; |
| 36 | import org.eclipse.pde.api.tools.internal.util.Util; |
| 37 | import org.objectweb.asm.ClassReader; |
| 38 | import org.objectweb.asm.Opcodes; |
| 39 | |
| 40 | import com.ibm.icu.text.MessageFormat; |
| 41 | |
| 42 | /** |
| 43 | * Base implementation of {@link IApiType} |
| 44 | * |
| 45 | * @since 1.0.0 |
| 46 | * @noextend This class is not intended to be sub-classed by clients. |
| 47 | * @noinstantiate This class is not intended to be instantiated by clients. |
| 48 | */ |
| 49 | public class ApiType extends ApiMember implements IApiType { |
| 50 | |
| 51 | private String fSuperclassName; |
| 52 | private String[] fSuperInterfaceNames; |
| 53 | private String fEnclosingTypeName; |
| 54 | private String fSimpleName; |
| 55 | |
| 56 | private static final IApiMethod[] EMPTY_METHODS = new IApiMethod[0]; |
| 57 | private static final IApiField[] EMPTY_FIELDS = new IApiField[0]; |
| 58 | private static final IApiType[] EMPTY_TYPES = new IApiType[0]; |
| 59 | |
| 60 | /* |
| 61 | * Use to tag fEnclosingMethodName and fEnclosingMethodSignature when there is no enclosing method |
| 62 | * but the EnclosingMethodAttribute is set (anonymous type in a field initializer). |
| 63 | */ |
| 64 | private static final String NO_ENCLOSING_METHOD = Util.EMPTY_STRING; |
| 65 | |
| 66 | /** |
| 67 | * Maps field name to field element. |
| 68 | */ |
| 69 | private Map fFields; |
| 70 | /** |
| 71 | * Maps method name/signature pair to method element. |
| 72 | */ |
| 73 | private LinkedHashMap fMethods; |
| 74 | |
| 75 | /** |
| 76 | * Map of member type names to class file (or null until resolved) |
| 77 | */ |
| 78 | private Map fMemberTypes; |
| 79 | |
| 80 | /** |
| 81 | * Cached descriptor |
| 82 | */ |
| 83 | private IReferenceTypeDescriptor fHandle; |
| 84 | |
| 85 | /** |
| 86 | * Cached superclass or <code>null</code> |
| 87 | */ |
| 88 | private IApiType fSuperclass; |
| 89 | |
| 90 | /** |
| 91 | * Cached super interfaces or <code>null</code> |
| 92 | */ |
| 93 | private IApiType[] fSuperInterfaces; |
| 94 | |
| 95 | /** |
| 96 | * The storage this type structure originated from |
| 97 | */ |
| 98 | private IApiTypeRoot fStorage; |
| 99 | |
| 100 | /** |
| 101 | * The signature of the enclosing method if this is a local type |
| 102 | */ |
| 103 | private String fEnclosingMethodSignature = null; |
| 104 | |
| 105 | /** |
| 106 | * The name of the method that encloses this type if it is local |
| 107 | */ |
| 108 | private String fEnclosingMethodName = null; |
| 109 | |
| 110 | /** |
| 111 | * If this is an anonymous class or not |
| 112 | */ |
| 113 | private boolean fAnonymous = false; |
| 114 | |
| 115 | /** |
| 116 | * If this is a local type or not (class defined in a method) |
| 117 | */ |
| 118 | private boolean fLocal = false; |
| 119 | |
| 120 | /** |
| 121 | * If this is a member type or not (class defined in a method) |
| 122 | */ |
| 123 | private boolean fMemberType = false; |
| 124 | |
| 125 | /** |
| 126 | * cached enclosing type once it has been successfully calculated |
| 127 | */ |
| 128 | private IApiType fEnclosingType = null; |
| 129 | |
| 130 | /** |
| 131 | * The method that encloses this type |
| 132 | */ |
| 133 | private IApiMethod fEnclosingMethod = null; |
| 134 | |
| 135 | /** |
| 136 | * Creates an API type. Note that if an API component is not specified, |
| 137 | * then some operations will not be available (navigating super types, |
| 138 | * member types, etc). |
| 139 | * |
| 140 | * @param parent the parent {@link IApiElement} or <code>null</code> if none |
| 141 | * @param name the name of the type |
| 142 | * @param signature the signature of the type |
| 143 | * @param genericSig the generic signature of the type |
| 144 | * @param flags the flags for the type |
| 145 | * @param enclosingName |
| 146 | * @param storage the storage this content was generated from |
| 147 | */ |
| 148 | public ApiType(IApiElement parent, String name, String signature, String genericSig, int flags, String enclosingName, IApiTypeRoot storage) { |
| 149 | super(parent, name, signature, genericSig, IApiElement.TYPE, flags); |
| 150 | fEnclosingTypeName = enclosingName; |
| 151 | fStorage = storage; |
| 152 | } |
| 153 | |
| 154 | /* (non-Javadoc) |
| 155 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#extractReferences(int, org.eclipse.core.runtime.IProgressMonitor) |
| 156 | */ |
| 157 | public List extractReferences(int referenceMask, IProgressMonitor monitor) throws CoreException { |
| 158 | HashSet references = new HashSet(); |
| 159 | ReferenceExtractor extractor = new ReferenceExtractor(this, references, referenceMask); |
| 160 | ClassReader reader = new ClassReader(((AbstractApiTypeRoot)fStorage).getContents()); |
| 161 | reader.accept(extractor, ClassReader.SKIP_FRAMES); |
| 162 | return new LinkedList(references); |
| 163 | } |
| 164 | |
| 165 | /* (non-Javadoc) |
| 166 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#getField(java.lang.String) |
| 167 | */ |
| 168 | public IApiField getField(String name) { |
| 169 | if (fFields != null) { |
| 170 | return (IApiField) fFields.get(name); |
| 171 | } |
| 172 | return null; |
| 173 | } |
| 174 | |
| 175 | /* (non-Javadoc) |
| 176 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#getFields() |
| 177 | */ |
| 178 | public IApiField[] getFields() { |
| 179 | if (fFields != null) { |
| 180 | return (IApiField[]) fFields.values().toArray(new IApiField[fFields.size()]); |
| 181 | } |
| 182 | return EMPTY_FIELDS; |
| 183 | } |
| 184 | |
| 185 | /* (non-Javadoc) |
| 186 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiMember#getPackageName() |
| 187 | */ |
| 188 | public String getPackageName() { |
| 189 | return getName().substring(0, getName().lastIndexOf('.')); |
| 190 | } |
| 191 | |
| 192 | /** |
| 193 | * Used when building a type structure. |
| 194 | * |
| 195 | * @param name method name |
| 196 | * @param signature method signature |
| 197 | * @param genericSig |
| 198 | * @param modifiers method modifiers |
| 199 | * @param exceptions names of thrown exceptions |
| 200 | */ |
| 201 | public ApiMethod addMethod(String name, String signature, String genericSig, int modifiers, String[] exceptions) { |
| 202 | if (fMethods == null) { |
| 203 | fMethods = new LinkedHashMap(); |
| 204 | } |
| 205 | ApiMethod method = new ApiMethod(this, name, signature, genericSig, modifiers, exceptions); |
| 206 | fMethods.put(new MethodKey(name, signature), method); |
| 207 | return method; |
| 208 | } |
| 209 | |
| 210 | /** |
| 211 | * Used when building a type structure. |
| 212 | * |
| 213 | * @param name field name |
| 214 | * @param signature field signature |
| 215 | * @param genericSig |
| 216 | * @param modifiers field modifiers |
| 217 | * @param value constant value or <code>null</code> if none |
| 218 | */ |
| 219 | public ApiField addField(String name, String signature, String genericSig, int modifiers, Object value) { |
| 220 | if (fFields == null) { |
| 221 | fFields = new HashMap(); |
| 222 | } |
| 223 | ApiField field = new ApiField(this, name, signature, genericSig, modifiers, value); |
| 224 | fFields.put(name, field); |
| 225 | return field; |
| 226 | } |
| 227 | |
| 228 | /* (non-Javadoc) |
| 229 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#getMethod(java.lang.String, java.lang.String) |
| 230 | */ |
| 231 | public IApiMethod getMethod(String name, String signature) { |
| 232 | if (fMethods != null) { |
| 233 | return (IApiMethod) fMethods.get(new MethodKey(name, signature)); |
| 234 | } |
| 235 | return null; |
| 236 | } |
| 237 | |
| 238 | |
| 239 | /* (non-Javadoc) |
| 240 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#getMethods() |
| 241 | */ |
| 242 | public IApiMethod[] getMethods() { |
| 243 | if (fMethods != null) { |
| 244 | return (IApiMethod[]) fMethods.values().toArray(new IApiMethod[fMethods.size()]); |
| 245 | } |
| 246 | return EMPTY_METHODS; |
| 247 | } |
| 248 | |
| 249 | /* (non-Javadoc) |
| 250 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#getSuperInterfaceNames() |
| 251 | */ |
| 252 | public String[] getSuperInterfaceNames() { |
| 253 | return fSuperInterfaceNames; |
| 254 | } |
| 255 | |
| 256 | public void setSuperInterfaceNames(String[] names) { |
| 257 | fSuperInterfaceNames = names; |
| 258 | } |
| 259 | |
| 260 | /* (non-Javadoc) |
| 261 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#getSuperInterfaces() |
| 262 | */ |
| 263 | public IApiType[] getSuperInterfaces() throws CoreException { |
| 264 | String[] names = getSuperInterfaceNames(); |
| 265 | if (names == null) { |
| 266 | return EMPTY_TYPES; |
| 267 | } |
| 268 | if (fSuperInterfaces == null) { |
| 269 | IApiType[] interfaces = new IApiType[names.length]; |
| 270 | for (int i = 0; i < interfaces.length; i++) { |
| 271 | interfaces[i] = resolveType(names[i]); |
| 272 | if (interfaces[i] == null) { |
| 273 | throw new CoreException( |
| 274 | new Status( |
| 275 | IStatus.ERROR, |
| 276 | ApiPlugin.PLUGIN_ID, |
| 277 | ApiPlugin.REPORT_RESOLUTION_ERRORS, |
| 278 | MessageFormat.format(Messages.ApiType_0, new String[]{names[i], getName()}), |
| 279 | null)); |
| 280 | } |
| 281 | } |
| 282 | fSuperInterfaces = interfaces; |
| 283 | } |
| 284 | return fSuperInterfaces; |
| 285 | } |
| 286 | |
| 287 | /* (non-Javadoc) |
| 288 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#getSuperclass() |
| 289 | */ |
| 290 | public IApiType getSuperclass() throws CoreException { |
| 291 | String name = getSuperclassName(); |
| 292 | if (name == null) { |
| 293 | return null; |
| 294 | } |
| 295 | if (fSuperclass == null) { |
| 296 | fSuperclass = resolveType(name); |
| 297 | if (fSuperclass == null) { |
| 298 | throw new CoreException(new Status( |
| 299 | IStatus.ERROR, |
| 300 | ApiPlugin.PLUGIN_ID, |
| 301 | ApiPlugin.REPORT_RESOLUTION_ERRORS, |
| 302 | MessageFormat.format(Messages.ApiType_1, new String[]{name, getName()}), |
| 303 | null)); |
| 304 | } |
| 305 | } |
| 306 | return fSuperclass; |
| 307 | } |
| 308 | |
| 309 | /** |
| 310 | * Resolves and returns the specified fully qualified type name or <code>null</code> |
| 311 | * if none. |
| 312 | * |
| 313 | * @param qName qualified name |
| 314 | * @return type or <code>null</code> |
| 315 | * @throws CoreException if unable to resolve |
| 316 | */ |
| 317 | private IApiType resolveType(String qName) throws CoreException { |
| 318 | if (getApiComponent() == null) { |
| 319 | requiresApiComponent(); |
| 320 | } |
| 321 | String packageName = Signatures.getPackageName(qName); |
| 322 | IApiComponent[] components = getApiComponent().getBaseline(). |
| 323 | resolvePackage(getApiComponent(), packageName); |
| 324 | IApiTypeRoot result = Util.getClassFile(components, qName); |
| 325 | if (result != null) { |
| 326 | return result.getStructure(); |
| 327 | } |
| 328 | return null; |
| 329 | } |
| 330 | |
| 331 | /** |
| 332 | * Throws an exception due to the fact an API component was not provided when this type |
| 333 | * was created and is now required to perform navigation or resolution. |
| 334 | * |
| 335 | * @throws CoreException |
| 336 | */ |
| 337 | private void requiresApiComponent() throws CoreException { |
| 338 | throw new CoreException(new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, Messages.ApiType_2)); |
| 339 | } |
| 340 | |
| 341 | /* (non-Javadoc) |
| 342 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#getSuperclassName() |
| 343 | */ |
| 344 | public String getSuperclassName() { |
| 345 | return fSuperclassName; |
| 346 | } |
| 347 | |
| 348 | public void setSuperclassName(String superName) { |
| 349 | fSuperclassName = superName; |
| 350 | } |
| 351 | |
| 352 | public void setSimpleName(String simpleName) { |
| 353 | fSimpleName = simpleName; |
| 354 | } |
| 355 | |
| 356 | /* (non-Javadoc) |
| 357 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#isAnnotation() |
| 358 | */ |
| 359 | public boolean isAnnotation() { |
| 360 | return (getModifiers() & Opcodes.ACC_ANNOTATION) != 0; |
| 361 | } |
| 362 | |
| 363 | /* (non-Javadoc) |
| 364 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#isAnonymous() |
| 365 | */ |
| 366 | public boolean isAnonymous() { |
| 367 | return fAnonymous; |
| 368 | } |
| 369 | |
| 370 | /* (non-Javadoc) |
| 371 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#isLocal() |
| 372 | */ |
| 373 | public boolean isLocal() { |
| 374 | return fLocal; |
| 375 | } |
| 376 | |
| 377 | /* (non-Javadoc) |
| 378 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#getTypeRoot() |
| 379 | */ |
| 380 | public IApiTypeRoot getTypeRoot() { |
| 381 | return fStorage; |
| 382 | } |
| 383 | |
| 384 | /** |
| 385 | * Used when building a type structure. |
| 386 | */ |
| 387 | public void setAnonymous() { |
| 388 | fAnonymous = true; |
| 389 | } |
| 390 | |
| 391 | /** |
| 392 | * Used when building a type structure. |
| 393 | */ |
| 394 | public void setMemberType() { |
| 395 | fMemberType = true; |
| 396 | } |
| 397 | |
| 398 | /** |
| 399 | * Used when building a type structure for pre-1.5 sources |
| 400 | */ |
| 401 | public void setLocal() { |
| 402 | fLocal = true; |
| 403 | } |
| 404 | |
| 405 | /** |
| 406 | * Sets the signature of the method that encloses this local type |
| 407 | * @param signature the signature of the method. |
| 408 | * @see org.eclipse.jdt.core.Signature for more information |
| 409 | */ |
| 410 | public void setEnclosingMethodInfo(String name, String signature) { |
| 411 | if (name != null) { |
| 412 | fEnclosingMethodName = name; |
| 413 | } else { |
| 414 | fEnclosingMethodName = NO_ENCLOSING_METHOD; |
| 415 | } |
| 416 | if (signature != null) { |
| 417 | fEnclosingMethodSignature = signature; |
| 418 | } else { |
| 419 | fEnclosingMethodSignature = NO_ENCLOSING_METHOD; |
| 420 | } |
| 421 | } |
| 422 | |
| 423 | /* (non-Javadoc) |
| 424 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#getEnclosingMethod() |
| 425 | */ |
| 426 | public IApiMethod getEnclosingMethod() { |
| 427 | if(fEnclosingMethod == null) { |
| 428 | try { |
| 429 | IApiType enclosingType = getEnclosingType(); |
| 430 | if(fEnclosingMethodName != null) { |
| 431 | if (fEnclosingMethodName != NO_ENCLOSING_METHOD) { |
| 432 | fEnclosingMethod = enclosingType.getMethod(fEnclosingMethodName, fEnclosingMethodSignature); |
| 433 | } |
| 434 | } else { |
| 435 | TypeStructureBuilder.setEnclosingMethod(enclosingType, this); |
| 436 | if(fEnclosingMethodName != null) { |
| 437 | fEnclosingMethod = enclosingType.getMethod(fEnclosingMethodName, fEnclosingMethodSignature); |
| 438 | } else { |
| 439 | // this prevents from trying to retrieve again the enclosing method when there is none |
| 440 | fEnclosingMethodName = NO_ENCLOSING_METHOD; |
| 441 | } |
| 442 | } |
| 443 | } |
| 444 | catch (CoreException ce) {} |
| 445 | } |
| 446 | return fEnclosingMethod; |
| 447 | } |
| 448 | |
| 449 | /* (non-Javadoc) |
| 450 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#isClass() |
| 451 | */ |
| 452 | public boolean isClass() { |
| 453 | return (getModifiers() & ( |
| 454 | Opcodes.ACC_ANNOTATION | |
| 455 | Opcodes.ACC_ENUM | |
| 456 | Opcodes.ACC_INTERFACE)) == 0; |
| 457 | } |
| 458 | |
| 459 | /* (non-Javadoc) |
| 460 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#isEnum() |
| 461 | */ |
| 462 | public boolean isEnum() { |
| 463 | return (getModifiers() & Opcodes.ACC_ENUM) != 0; |
| 464 | } |
| 465 | |
| 466 | /* (non-Javadoc) |
| 467 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#isInterface() |
| 468 | */ |
| 469 | public boolean isInterface() { |
| 470 | return (getModifiers() & Opcodes.ACC_INTERFACE) != 0; |
| 471 | } |
| 472 | |
| 473 | /* (non-Javadoc) |
| 474 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#isMemberType() |
| 475 | */ |
| 476 | public boolean isMemberType() { |
| 477 | return fMemberType; |
| 478 | } |
| 479 | |
| 480 | /* (non-Javadoc) |
| 481 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiMember#getHandle() |
| 482 | */ |
| 483 | public IMemberDescriptor getHandle() { |
| 484 | if (fHandle == null) { |
| 485 | fHandle = Util.getType(getName()); |
| 486 | } |
| 487 | return fHandle; |
| 488 | } |
| 489 | |
| 490 | /* (non-Javadoc) |
| 491 | * @see java.lang.Object#equals(java.lang.Object) |
| 492 | */ |
| 493 | public boolean equals(Object obj) { |
| 494 | if (obj instanceof IApiType) { |
| 495 | IApiType type = (IApiType) obj; |
| 496 | if (getApiComponent() == null) { |
| 497 | return type.getApiComponent() == null && |
| 498 | getName().equals(type.getName()); |
| 499 | } |
| 500 | return getApiComponent().equals(type.getApiComponent()) && |
| 501 | getName().equals(type.getName()); |
| 502 | } |
| 503 | return false; |
| 504 | } |
| 505 | |
| 506 | /* (non-Javadoc) |
| 507 | * @see java.lang.Object#hashCode() |
| 508 | */ |
| 509 | public int hashCode() { |
| 510 | IApiComponent component = getApiComponent(); |
| 511 | if (component == null) { |
| 512 | return getName().hashCode(); |
| 513 | } |
| 514 | return component.hashCode() + getName().hashCode(); |
| 515 | } |
| 516 | |
| 517 | /** |
| 518 | * Used when building a type structure. |
| 519 | * |
| 520 | * @param name member type name |
| 521 | */ |
| 522 | public void addMemberType(String name, int modifiers) { |
| 523 | if (fMemberTypes == null) { |
| 524 | fMemberTypes = new HashMap(); |
| 525 | } |
| 526 | int index = name.lastIndexOf('$'); |
| 527 | String simpleName = name.substring(index + 1); |
| 528 | fMemberTypes.put(simpleName, null); |
| 529 | } |
| 530 | |
| 531 | /* (non-Javadoc) |
| 532 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#getMemberType(java.lang.String) |
| 533 | */ |
| 534 | public IApiType getMemberType(String simpleName) throws CoreException { |
| 535 | if (fMemberTypes == null) { |
| 536 | return null; |
| 537 | } |
| 538 | if (getApiComponent() == null) { |
| 539 | requiresApiComponent(); |
| 540 | } |
| 541 | if (fMemberTypes.containsKey(simpleName)) { |
| 542 | IApiTypeRoot file = (IApiTypeRoot) fMemberTypes.get(simpleName); |
| 543 | if (file == null) { |
| 544 | // resolve |
| 545 | StringBuffer qName = new StringBuffer(); |
| 546 | qName.append(getName()); |
| 547 | qName.append('$'); |
| 548 | qName.append(simpleName); |
| 549 | file = getApiComponent().findTypeRoot(qName.toString()); |
| 550 | if (file == null) { |
| 551 | throw new CoreException(new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, |
| 552 | MessageFormat.format(Messages.ApiType_3, |
| 553 | new String[]{simpleName, getName()}))); |
| 554 | } |
| 555 | fMemberTypes.put(simpleName, file); |
| 556 | } |
| 557 | return file.getStructure(); |
| 558 | } |
| 559 | return null; |
| 560 | } |
| 561 | |
| 562 | /* (non-Javadoc) |
| 563 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#getMemberTypes() |
| 564 | */ |
| 565 | public IApiType[] getMemberTypes() throws CoreException { |
| 566 | if (fMemberTypes == null) { |
| 567 | return EMPTY_TYPES; |
| 568 | } |
| 569 | IApiType[] members = new IApiType[fMemberTypes.size()]; |
| 570 | Iterator iterator = fMemberTypes.keySet().iterator(); |
| 571 | int index = 0; |
| 572 | while (iterator.hasNext()) { |
| 573 | String name = (String) iterator.next(); |
| 574 | members[index] = getMemberType(name); |
| 575 | index++; |
| 576 | } |
| 577 | return members; |
| 578 | } |
| 579 | |
| 580 | /** |
| 581 | * @see java.lang.Object#toString() |
| 582 | */ |
| 583 | public String toString() { |
| 584 | StringBuffer buffer = new StringBuffer(); |
| 585 | buffer |
| 586 | .append("Type : access(") //$NON-NLS-1$ |
| 587 | .append(getModifiers()) |
| 588 | .append(") ") //$NON-NLS-1$ |
| 589 | .append(getName()); |
| 590 | if (getSuperclassName() != null) { |
| 591 | buffer |
| 592 | .append(" superclass: ") //$NON-NLS-1$ |
| 593 | .append(getSuperclassName()); |
| 594 | } |
| 595 | if (getSuperInterfaceNames() != null) { |
| 596 | buffer.append(" interfaces : "); //$NON-NLS-1$ |
| 597 | if (getSuperInterfaceNames().length > 0) { |
| 598 | for (int i = 0; i < getSuperInterfaceNames().length; i++) { |
| 599 | if (i > 0) buffer.append(','); |
| 600 | buffer.append(getSuperInterfaceNames()[i]); |
| 601 | } |
| 602 | } else { |
| 603 | buffer.append("none"); //$NON-NLS-1$ |
| 604 | } |
| 605 | } |
| 606 | buffer.append(';').append(Util.LINE_DELIMITER); |
| 607 | if (getGenericSignature() != null) { |
| 608 | buffer |
| 609 | .append(" Signature : ") //$NON-NLS-1$ |
| 610 | .append(getGenericSignature()).append(Util.LINE_DELIMITER); |
| 611 | } |
| 612 | buffer.append(Util.LINE_DELIMITER).append("Methods : ").append(Util.LINE_DELIMITER); //$NON-NLS-1$ |
| 613 | IApiMethod[] methods = getMethods(); |
| 614 | for (int i = 0; i < methods.length; i++) { |
| 615 | buffer.append(methods[i]); |
| 616 | } |
| 617 | buffer.append(Util.LINE_DELIMITER).append("Fields : ").append(Util.LINE_DELIMITER); //$NON-NLS-1$ |
| 618 | IApiField[] fields = getFields(); |
| 619 | for (int i = 0; i < fields.length; i++) { |
| 620 | buffer.append(fields[i]); |
| 621 | } |
| 622 | return String.valueOf(buffer); |
| 623 | } |
| 624 | |
| 625 | /* (non-Javadoc) |
| 626 | * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiType#getSimpleName() |
| 627 | */ |
| 628 | public String getSimpleName() { |
| 629 | if (this.isAnonymous()) { |
| 630 | return null; |
| 631 | } |
| 632 | if (this.isLocal() || this.isMemberType()) { |
| 633 | return this.fSimpleName; |
| 634 | } |
| 635 | String name = getName(); |
| 636 | int index = name.lastIndexOf('.'); |
| 637 | if (index != -1) { |
| 638 | return name.substring(index + 1); |
| 639 | } |
| 640 | return name; |
| 641 | } |
| 642 | /* (non-Javadoc) |
| 643 | * @see org.eclipse.pde.api.tools.internal.model.ApiMember#getEnclosingType() |
| 644 | */ |
| 645 | public IApiType getEnclosingType() throws CoreException { |
| 646 | if(fEnclosingType != null) { |
| 647 | return fEnclosingType; |
| 648 | } |
| 649 | if(fEnclosingTypeName != null) { |
| 650 | IApiTypeRoot root = getApiComponent().findTypeRoot(processEnclosingTypeName()); |
| 651 | if(root != null) { |
| 652 | fEnclosingType = root.getStructure(); |
| 653 | } |
| 654 | } |
| 655 | return fEnclosingType; |
| 656 | } |
| 657 | |
| 658 | private String processEnclosingTypeName() { |
| 659 | if(isLocal() || isAnonymous()) { |
| 660 | int idx = fEnclosingTypeName.lastIndexOf('$'); |
| 661 | if(Character.isDigit(fEnclosingTypeName.charAt(idx + 1))) { |
| 662 | return fEnclosingTypeName.substring(0, idx); |
| 663 | } |
| 664 | } |
| 665 | return fEnclosingTypeName; |
| 666 | } |
| 667 | } |