| 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 | } |